490 lines
11 KiB
Go
490 lines
11 KiB
Go
// Copyright 2026 eat-pray-ai & OpenWaygate
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package liveStream
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json/v2"
|
|
"io"
|
|
"math"
|
|
"net/http"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/eat-pray-ai/yutu/pkg/common"
|
|
"google.golang.org/api/youtube/v3"
|
|
)
|
|
|
|
func TestNewLiveStream(t *testing.T) {
|
|
type args struct {
|
|
opts []Option
|
|
}
|
|
|
|
svc := &youtube.Service{}
|
|
mine := true
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want ILiveStream[youtube.LiveStream]
|
|
}{
|
|
{
|
|
name: "with all options",
|
|
args: args{
|
|
opts: []Option{
|
|
WithIds([]string{"stream1", "stream2"}),
|
|
WithTitle("Test Stream"),
|
|
WithDescription(new("A test stream")),
|
|
WithMine(&mine),
|
|
WithFrameRate("60fps"),
|
|
WithIngestionType("rtmp"),
|
|
WithResolution("1080p"),
|
|
WithMaxResults(50),
|
|
WithParts([]string{"snippet", "cdn", "status"}),
|
|
WithOutput("json"),
|
|
WithService(svc),
|
|
WithOnBehalfOfContentOwner("owner123"),
|
|
WithOnBehalfOfContentOwnerChannel("channel123"),
|
|
},
|
|
},
|
|
want: &LiveStream{
|
|
Service: svc,
|
|
Parts: []string{"snippet", "cdn", "status"},
|
|
Output: "json",
|
|
MaxResults: 50,
|
|
Ids: []string{"stream1", "stream2"},
|
|
OnBehalfOfContentOwner: "owner123",
|
|
Title: "Test Stream",
|
|
Description: new("A test stream"),
|
|
Mine: &mine,
|
|
FrameRate: "60fps",
|
|
IngestionType: "rtmp",
|
|
Resolution: "1080p",
|
|
OnBehalfOfContentOwnerChannel: "channel123",
|
|
},
|
|
},
|
|
{
|
|
name: "with no options",
|
|
args: args{
|
|
opts: []Option{},
|
|
},
|
|
want: &LiveStream{Fields: common.Fields{}},
|
|
},
|
|
{
|
|
name: "with zero max results",
|
|
args: args{
|
|
opts: []Option{
|
|
WithMaxResults(0),
|
|
},
|
|
},
|
|
want: &LiveStream{
|
|
MaxResults: math.MaxInt64,
|
|
},
|
|
},
|
|
{
|
|
name: "with negative max results",
|
|
args: args{
|
|
opts: []Option{
|
|
WithMaxResults(-10),
|
|
},
|
|
},
|
|
want: &LiveStream{
|
|
MaxResults: 1,
|
|
},
|
|
},
|
|
{
|
|
name: "with empty string values",
|
|
args: args{
|
|
opts: []Option{
|
|
WithTitle(""),
|
|
WithDescription(new("")),
|
|
WithFrameRate(""),
|
|
WithIngestionType(""),
|
|
WithResolution(""),
|
|
},
|
|
},
|
|
want: &LiveStream{
|
|
Fields: common.Fields{},
|
|
Title: "",
|
|
Description: new(""),
|
|
FrameRate: "",
|
|
IngestionType: "",
|
|
Resolution: "",
|
|
},
|
|
},
|
|
{
|
|
name: "with partial options",
|
|
args: args{
|
|
opts: []Option{
|
|
WithTitle("My Stream"),
|
|
WithIngestionType("rtmp"),
|
|
WithMaxResults(25),
|
|
WithParts([]string{"snippet"}),
|
|
},
|
|
},
|
|
want: &LiveStream{
|
|
Parts: []string{"snippet"},
|
|
MaxResults: 25,
|
|
Title: "My Stream",
|
|
IngestionType: "rtmp",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name, func(t *testing.T) {
|
|
if got := NewLiveStream(tt.args.opts...); !reflect.DeepEqual(
|
|
got, tt.want,
|
|
) {
|
|
t.Errorf("%s\nNewLiveStream() = %v\nwant %v", tt.name, got, tt.want)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestLiveStream_Get(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
opts []Option
|
|
verify func(*http.Request)
|
|
wantLen int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "get live streams by id",
|
|
opts: []Option{
|
|
WithIds([]string{"stream-1"}),
|
|
WithMaxResults(1),
|
|
},
|
|
verify: func(r *http.Request) {
|
|
q := r.URL.Query()
|
|
if q.Get("id") != "stream-1" {
|
|
t.Errorf(
|
|
"expected id=stream-1, got %s",
|
|
q.Get("id"),
|
|
)
|
|
}
|
|
},
|
|
wantLen: 1,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "get live streams with mine",
|
|
opts: func() []Option {
|
|
mine := true
|
|
return []Option{
|
|
WithMine(&mine),
|
|
WithMaxResults(1),
|
|
}
|
|
}(),
|
|
verify: func(r *http.Request) {
|
|
q := r.URL.Query()
|
|
if q.Get("mine") != "true" {
|
|
t.Errorf(
|
|
"expected mine=true, got %s",
|
|
q.Get("mine"),
|
|
)
|
|
}
|
|
},
|
|
wantLen: 1,
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name, func(t *testing.T) {
|
|
svc := common.NewTestService(
|
|
t, http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
if tt.verify != nil {
|
|
tt.verify(r)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write(
|
|
[]byte(`{
|
|
"items": [
|
|
{
|
|
"id": "stream-1",
|
|
"snippet": {
|
|
"title": "Test Stream",
|
|
"description": "A test stream"
|
|
},
|
|
"status": {
|
|
"streamStatus": "active"
|
|
}
|
|
}
|
|
]
|
|
}`),
|
|
)
|
|
},
|
|
),
|
|
)
|
|
|
|
opts := append([]Option{WithService(svc)}, tt.opts...)
|
|
s := NewLiveStream(opts...)
|
|
got, err := s.Get()
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("LiveStream.Get() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if len(got) != tt.wantLen {
|
|
t.Errorf(
|
|
"LiveStream.Get() got length = %v, want %v", len(got), tt.wantLen,
|
|
)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestLiveStream_Get_Pagination(t *testing.T) {
|
|
svc := common.NewTestService(t, common.PaginationHandler("stream"))
|
|
|
|
mine := true
|
|
s := NewLiveStream(
|
|
WithService(svc),
|
|
WithMine(&mine),
|
|
WithMaxResults(22),
|
|
)
|
|
got, err := s.Get()
|
|
if err != nil {
|
|
t.Errorf("LiveStream.Get() error = %v", err)
|
|
}
|
|
if len(got) != 22 {
|
|
t.Errorf("LiveStream.Get() got length = %v, want 22", len(got))
|
|
}
|
|
}
|
|
|
|
func TestLiveStream_List(t *testing.T) {
|
|
mockResponse := `{
|
|
"items": [
|
|
{
|
|
"id": "stream-1",
|
|
"snippet": {
|
|
"title": "Test Stream",
|
|
"description": "A test stream"
|
|
},
|
|
"status": {
|
|
"streamStatus": "active"
|
|
}
|
|
}
|
|
]
|
|
}`
|
|
|
|
mine := true
|
|
common.RunListTest(
|
|
t, mockResponse,
|
|
func(svc *youtube.Service, output string) func(io.Writer) error {
|
|
s := NewLiveStream(
|
|
WithService(svc),
|
|
WithMine(&mine),
|
|
WithOutput(output),
|
|
WithMaxResults(1),
|
|
)
|
|
return s.List
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestLiveStream_Insert(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
opts []Option
|
|
verify func(*http.Request)
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "insert live stream",
|
|
opts: []Option{
|
|
WithTitle("New Stream"),
|
|
WithDescription(new("A new live stream")),
|
|
WithFrameRate("60fps"),
|
|
WithIngestionType("rtmp"),
|
|
WithResolution("1080p"),
|
|
WithParts([]string{"snippet", "cdn"}),
|
|
},
|
|
verify: func(r *http.Request) {
|
|
if r.Method != "POST" {
|
|
t.Errorf("expected POST, got %s", r.Method)
|
|
}
|
|
|
|
defer func() { _ = r.Body.Close() }()
|
|
var body struct {
|
|
Snippet struct {
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
} `json:"snippet"`
|
|
Cdn struct {
|
|
FrameRate string `json:"frameRate"`
|
|
IngestionType string `json:"ingestionType"`
|
|
Resolution string `json:"resolution"`
|
|
} `json:"cdn"`
|
|
}
|
|
if err := json.UnmarshalRead(r.Body, &body); err != nil {
|
|
t.Fatalf("failed to decode request body: %v", err)
|
|
}
|
|
|
|
if body.Snippet.Title != "New Stream" {
|
|
t.Errorf(
|
|
"expected snippet.title=New Stream, got %s", body.Snippet.Title,
|
|
)
|
|
}
|
|
if body.Snippet.Description != "A new live stream" {
|
|
t.Errorf(
|
|
"expected snippet.description=A new live stream, got %s",
|
|
body.Snippet.Description,
|
|
)
|
|
}
|
|
if body.Cdn.FrameRate != "60fps" {
|
|
t.Errorf("expected cdn.frameRate=60fps, got %s", body.Cdn.FrameRate)
|
|
}
|
|
if body.Cdn.IngestionType != "rtmp" {
|
|
t.Errorf(
|
|
"expected cdn.ingestionType=rtmp, got %s", body.Cdn.IngestionType,
|
|
)
|
|
}
|
|
if body.Cdn.Resolution != "1080p" {
|
|
t.Errorf("expected cdn.resolution=1080p, got %s", body.Cdn.Resolution)
|
|
}
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name, func(t *testing.T) {
|
|
svc := common.NewTestService(
|
|
t, http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
if tt.verify != nil {
|
|
tt.verify(r)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"id": "new-stream-id"}`))
|
|
},
|
|
),
|
|
)
|
|
|
|
opts := append([]Option{WithService(svc)}, tt.opts...)
|
|
s := NewLiveStream(opts...)
|
|
var buf bytes.Buffer
|
|
if err := s.Insert(&buf); (err != nil) != tt.wantErr {
|
|
t.Errorf(
|
|
"LiveStream.Insert() error = %v, wantErr %v", err, tt.wantErr,
|
|
)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestLiveStream_Update(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
opts []Option
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "update live stream",
|
|
opts: []Option{
|
|
WithIds([]string{"stream-1"}),
|
|
WithTitle("Updated Stream"),
|
|
WithDescription(new("Updated description")),
|
|
WithMaxResults(1),
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name, func(t *testing.T) {
|
|
callCount := 0
|
|
svc := common.NewTestService(
|
|
t, http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
callCount++
|
|
if callCount == 1 {
|
|
_, _ = w.Write(
|
|
[]byte(`{
|
|
"items": [{
|
|
"id": "stream-1",
|
|
"snippet": {"title": "Old Stream", "description": "Old description"},
|
|
"cdn": {"frameRate": "30fps", "ingestionType": "rtmp", "resolution": "720p"}
|
|
}]
|
|
}`),
|
|
)
|
|
} else {
|
|
_, _ = w.Write([]byte(`{"id": "stream-1"}`))
|
|
}
|
|
},
|
|
),
|
|
)
|
|
|
|
opts := append([]Option{WithService(svc)}, tt.opts...)
|
|
s := NewLiveStream(opts...)
|
|
var buf bytes.Buffer
|
|
if err := s.Update(&buf); (err != nil) != tt.wantErr {
|
|
t.Errorf(
|
|
"LiveStream.Update() error = %v, wantErr %v", err, tt.wantErr,
|
|
)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestLiveStream_Delete(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
opts []Option
|
|
verify func(*http.Request)
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "delete live stream",
|
|
opts: []Option{
|
|
WithIds([]string{"stream-id"}),
|
|
},
|
|
verify: func(r *http.Request) {
|
|
if r.Method != "DELETE" {
|
|
t.Errorf("expected DELETE, got %s", r.Method)
|
|
}
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name, func(t *testing.T) {
|
|
svc := common.NewTestService(
|
|
t, http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
if tt.verify != nil {
|
|
tt.verify(r)
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
},
|
|
),
|
|
)
|
|
|
|
opts := append([]Option{WithService(svc)}, tt.opts...)
|
|
s := NewLiveStream(opts...)
|
|
var buf bytes.Buffer
|
|
if err := s.Delete(&buf); (err != nil) != tt.wantErr {
|
|
t.Errorf(
|
|
"LiveStream.Delete() error = %v, wantErr %v", err, tt.wantErr,
|
|
)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|