✅ Improve video tests

This commit is contained in:
OpenWaygate committed 2026-04-21 19:44:43 +08:00
1 parent c0d4300871
commit c14c60d977
2 files changed
+330 -24

No files matched your search

+1
View File
@@ -21,6 +21,7 @@ go_test(
srcs = ["video_test.go"],
embed = [":video"],
deps = [
"//pkg",
"//pkg/common",
"@org_golang_google_api//youtube/v3:youtube",
],
+329 -24
View File
@@ -16,6 +16,7 @@ import (
"strings"
"testing"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/common"
"google.golang.org/api/youtube/v3"
)
@@ -373,6 +374,31 @@ func TestVideo_Get(t *testing.T) {
wantLen: 1,
wantErr: false,
},
{
name: "get videos with hl, locale, categoryId",
opts: []Option{
WithHl("en"),
WithLocale("en_US"),
WithCategory("10"),
WithMaxResults(1),
},
verify: func(r *http.Request) {
if r.URL.Query().Get("hl") != "en" {
t.Errorf("expected hl=en, got %s", r.URL.Query().Get("hl"))
}
if r.URL.Query().Get("locale") != "en_US" {
t.Errorf("expected locale=en_US, got %s", r.URL.Query().Get("locale"))
}
if r.URL.Query().Get("videoCategoryId") != "10" {
t.Errorf(
"expected videoCategoryId=10, got %s",
r.URL.Query().Get("videoCategoryId"),
)
}
},
wantLen: 1,
wantErr: false,
},
}
for _, tt := range tests {
@@ -437,7 +463,7 @@ func TestVideo_List(t *testing.T) {
"title": "Video 1"
},
"statistics": {
"viewCount": 100
"viewCount": "100"
}
}
]
@@ -450,16 +476,54 @@ func TestVideo_List(t *testing.T) {
WithService(svc),
WithOutput(output),
WithIds([]string{"video-1"}),
WithMaxResults(5),
)
return v.List
},
)
}
func TestVideo_List_NilFields(t *testing.T) {
mockResponse := `{
"items": [
{"id": "video-1"},
{"id": "video-2", "snippet": {"title": "Video 2", "channelId": "ch-2"}},
{"id": "video-3", "statistics": {"viewCount": "500"}}
]
}`
svc := common.NewTestService(
t, http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(mockResponse))
},
),
)
v := NewVideo(
WithService(svc),
WithOutput("table"),
WithIds([]string{"video-1"}),
WithMaxResults(5),
)
var buf bytes.Buffer
if err := v.List(&buf); err != nil {
t.Errorf("List() error = %v", err)
}
if buf.Len() == 0 {
t.Error("List() output is empty")
}
}
func TestVideo_Insert(t *testing.T) {
autoLevelsTrue := true
notifySubscribersTrue := true
stabilizeTrue := true
forKidsTrue := true
embeddableTrue := true
containsSyntheticMediaTrue := true
publicStatsViewableTrue := true
decodeMultipartVideo := func(t *testing.T, r *http.Request) *youtube.Video {
t.Helper()
@@ -571,15 +635,102 @@ func TestVideo_Insert(t *testing.T) {
},
wantErr: false,
},
{
name: "insert video with recording date and boolean options",
opts: []Option{
WithFile("test_video.mp4"),
WithTitle("Dated Video"),
WithPrivacy("private"),
WithRecordingDate("2024-06-15T10:00:00Z"),
WithForKids(&forKidsTrue),
WithEmbeddable(&embeddableTrue),
WithContainsSyntheticMedia(&containsSyntheticMediaTrue),
WithPublicStatsViewable(&publicStatsViewableTrue),
},
verify: func(r *http.Request) {
if r.Method != "POST" {
t.Errorf("expected POST, got %s", r.Method)
}
if !strings.Contains(r.URL.Query().Get("part"), "recordingDetails") {
t.Errorf("expected part to contain recordingDetails, got %s", r.URL.Query().Get("part"))
}
body := decodeMultipartVideo(t, r)
if body.RecordingDetails == nil || body.RecordingDetails.RecordingDate != "2024-06-15T10:00:00Z" {
t.Errorf("expected recordingDetails.recordingDate=2024-06-15T10:00:00Z, got %+v", body.RecordingDetails)
}
if body.Status == nil || !body.Status.SelfDeclaredMadeForKids {
t.Errorf("expected status.selfDeclaredMadeForKids=true")
}
if body.Status == nil || !body.Status.Embeddable {
t.Errorf("expected status.embeddable=true")
}
if body.Status == nil || !body.Status.ContainsSyntheticMedia {
t.Errorf("expected status.containsSyntheticMedia=true")
}
if body.Status == nil || !body.Status.PublicStatsViewable {
t.Errorf("expected status.publicStatsViewable=true")
}
},
wantErr: false,
},
{
name: "insert video with empty title uses filename",
opts: []Option{
WithFile("test_video.mp4"),
WithPrivacy("public"),
},
verify: func(r *http.Request) {
if r.Method != "POST" {
return
}
body := decodeMultipartVideo(t, r)
if body.Snippet == nil || body.Snippet.Title != "test_video" {
t.Errorf("expected snippet.title=test_video (from filename), got %+v", body.Snippet)
}
},
wantErr: false,
},
{
name: "insert video with existing yutu tag",
opts: []Option{
WithFile("test_video.mp4"),
WithTitle("Tagged Video"),
WithTags([]string{"yutu🐰", "existing"}),
WithPrivacy("public"),
},
verify: func(r *http.Request) {
if r.Method != "POST" {
return
}
body := decodeMultipartVideo(t, r)
count := 0
for _, tag := range body.Snippet.Tags {
if tag == "yutu🐰" {
count++
}
}
if count != 1 {
t.Errorf("expected exactly 1 yutu🐰 tag, got %d in %v", count, body.Snippet.Tags)
}
},
wantErr: false,
},
}
err := os.WriteFile("test_video.mp4", []byte("dummy video content"), 0644)
tmpDir := t.TempDir()
root, err := os.OpenRoot(tmpDir)
if err != nil {
t.Fatalf("failed to open root: %v", err)
}
oldRoot := pkg.Root
pkg.Root = root
defer func() { pkg.Root = oldRoot }()
defer func() { _ = root.Close() }()
err = os.WriteFile(tmpDir+"/test_video.mp4", []byte("dummy video content"), 0644)
if err != nil {
t.Fatalf("failed to create dummy file: %v", err)
}
defer func() {
_ = os.Remove("test_video.mp4")
}()
for _, tt := range tests {
t.Run(
@@ -607,12 +758,45 @@ func TestVideo_Insert(t *testing.T) {
}
}
func TestVideo_Insert_FileError(t *testing.T) {
tmpDir := t.TempDir()
root, err := os.OpenRoot(tmpDir)
if err != nil {
t.Fatalf("failed to open root: %v", err)
}
oldRoot := pkg.Root
pkg.Root = root
defer func() { pkg.Root = oldRoot }()
defer func() { _ = root.Close() }()
svc := common.NewTestService(
t, http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
},
),
)
v := NewVideo(
WithService(svc),
WithFile("non_existent.mp4"),
)
var buf bytes.Buffer
if err := v.Insert(&buf); err == nil {
t.Error("expected error for non-existent file, got nil")
}
}
func TestVideo_Update(t *testing.T) {
embeddableTrue := true
containsSyntheticMediaTrue := true
tests := []struct {
name string
opts []Option
verify func(*http.Request)
wantErr bool
name string
opts []Option
getResponse string
verify func(*http.Request)
wantErr bool
}{
{
name: "update video",
@@ -622,6 +806,7 @@ func TestVideo_Update(t *testing.T) {
WithDescription("Updated Description"),
WithMaxResults(1),
},
getResponse: `{"items": [{"id": "video-id", "snippet": {"title": "Old Title"}}]}`,
verify: func(r *http.Request) {
if r.Method == "PUT" {
if r.URL.Query().Get("part") != "snippet,status" {
@@ -660,6 +845,7 @@ func TestVideo_Update(t *testing.T) {
WithMaxResults(1),
WithOnBehalfOfContentOwner("owner-id"),
},
getResponse: `{"items": [{"id": "video-id", "snippet": {"title": "Old Title"}}]}`,
verify: func(r *http.Request) {
if r.Method == "PUT" {
if r.URL.Query().Get("onBehalfOfContentOwner") != "owner-id" {
@@ -672,6 +858,91 @@ func TestVideo_Update(t *testing.T) {
},
wantErr: false,
},
{
name: "update video with tags, language, license, categoryId, privacy",
opts: []Option{
WithIds([]string{"video-id"}),
WithTags([]string{"new-tag"}),
WithLanguage("ja"),
WithLicense("creativeCommon"),
WithCategory("22"),
WithPrivacy("unlisted"),
WithMaxResults(1),
},
getResponse: `{"items": [{"id": "video-id", "snippet": {"title": "Old Title"}, "status": {"privacyStatus": "public", "license": "youtube", "embeddable": true, "publicStatsViewable": true}}]}`,
verify: func(r *http.Request) {
if r.Method == "PUT" {
var body youtube.Video
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatalf("failed to decode update body: %v", err)
}
if body.Snippet.DefaultLanguage != "ja" {
t.Errorf("expected defaultLanguage=ja, got %s", body.Snippet.DefaultLanguage)
}
if body.Status.License != "creativeCommon" {
t.Errorf("expected license=creativeCommon, got %s", body.Status.License)
}
if body.Snippet.CategoryId != "22" {
t.Errorf("expected categoryId=22, got %s", body.Snippet.CategoryId)
}
if body.Status.PrivacyStatus != "unlisted" {
t.Errorf("expected privacyStatus=unlisted, got %s", body.Status.PrivacyStatus)
}
found := false
for _, tag := range body.Snippet.Tags {
if tag == "yutu🐰" {
found = true
}
}
if !found {
t.Errorf("expected yutu🐰 tag in %v", body.Snippet.Tags)
}
}
},
wantErr: false,
},
{
name: "update video with embeddable, containsSyntheticMedia, recordingDate",
opts: []Option{
WithIds([]string{"video-id"}),
WithEmbeddable(&embeddableTrue),
WithContainsSyntheticMedia(&containsSyntheticMediaTrue),
WithRecordingDate("2024-01-01T00:00:00Z"),
WithMaxResults(1),
},
getResponse: `{"items": [{"id": "video-id", "snippet": {"title": "Old Title"}, "status": {"privacyStatus": "public"}}]}`,
verify: func(r *http.Request) {
if r.Method == "PUT" {
if !strings.Contains(r.URL.Query().Get("part"), "recordingDetails") {
t.Errorf("expected part to contain recordingDetails, got %s", r.URL.Query().Get("part"))
}
var body youtube.Video
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatalf("failed to decode update body: %v", err)
}
if !body.Status.Embeddable {
t.Errorf("expected embeddable=true")
}
if !body.Status.ContainsSyntheticMedia {
t.Errorf("expected containsSyntheticMedia=true")
}
if body.RecordingDetails == nil || body.RecordingDetails.RecordingDate != "2024-01-01T00:00:00Z" {
t.Errorf("expected recordingDate=2024-01-01T00:00:00Z, got %+v", body.RecordingDetails)
}
}
},
wantErr: false,
},
{
name: "update video not found",
opts: []Option{
WithIds([]string{"missing"}),
WithTitle("X"),
WithMaxResults(1),
},
getResponse: `{"items": []}`,
wantErr: true,
},
}
for _, tt := range tests {
@@ -685,15 +956,9 @@ func TestVideo_Update(t *testing.T) {
}
w.Header().Set("Content-Type", "application/json")
if r.Method == "GET" {
_, _ = w.Write(
[]byte(`{
"items": [
{"id": "video-id", "snippet": {"title": "Old Title"}}
]
}`),
)
_, _ = w.Write([]byte(tt.getResponse))
} else {
_, _ = w.Write([]byte(`{"id": "video-id", "snippet": {"title": "Updated Title"}}`))
_, _ = w.Write([]byte(`{"id": "video-id", "snippet": {"title": "Updated Title"}, "status": {"privacyStatus": "public"}}`))
}
},
),
@@ -727,15 +992,20 @@ func TestVideo_Rate(t *testing.T) {
if r.Method != "POST" {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Query().Get("id") != "video-id" {
t.Errorf("expected id=video-id, got %s", r.URL.Query().Get("id"))
}
if r.URL.Query().Get("rating") != "like" {
t.Errorf("expected rating=like, got %s", r.URL.Query().Get("rating"))
}
},
wantErr: false,
},
{
name: "rate multiple videos",
opts: []Option{
WithIds([]string{"video-1", "video-2"}),
WithRating("dislike"),
},
wantErr: false,
},
}
for _, tt := range tests {
@@ -771,9 +1041,10 @@ func TestVideo_GetRating(t *testing.T) {
wantErr bool
}{
{
name: "get rating",
name: "get rating table",
opts: []Option{
WithIds([]string{"video-id"}),
WithOutput("table"),
},
verify: func(r *http.Request) {
if r.URL.Query().Get("id") != "video-id" {
@@ -782,6 +1053,22 @@ func TestVideo_GetRating(t *testing.T) {
},
wantErr: false,
},
{
name: "get rating json",
opts: []Option{
WithIds([]string{"video-id"}),
WithOutput("json"),
},
wantErr: false,
},
{
name: "get rating yaml",
opts: []Option{
WithIds([]string{"video-id"}),
WithOutput("yaml"),
},
wantErr: false,
},
{
name: "get rating with onBehalfOfContentOwner",
opts: []Option{
@@ -827,6 +1114,9 @@ func TestVideo_GetRating(t *testing.T) {
if err := v.GetRating(&buf); (err != nil) != tt.wantErr {
t.Errorf("Video.GetRating() error = %v, wantErr %v", err, tt.wantErr)
}
if buf.Len() == 0 {
t.Errorf("GetRating(%s) output is empty", tt.name)
}
},
)
}
@@ -848,9 +1138,6 @@ func TestVideo_Delete(t *testing.T) {
if r.Method != "DELETE" {
t.Errorf("expected DELETE, got %s", r.Method)
}
if r.URL.Query().Get("id") != "video-id" {
t.Errorf("expected id=video-id, got %s", r.URL.Query().Get("id"))
}
},
wantErr: false,
},
@@ -873,6 +1160,13 @@ func TestVideo_Delete(t *testing.T) {
},
wantErr: false,
},
{
name: "delete multiple videos",
opts: []Option{
WithIds([]string{"video-1", "video-2"}),
},
wantErr: false,
},
}
for _, tt := range tests {
@@ -912,6 +1206,9 @@ func TestVideo_ReportAbuse(t *testing.T) {
opts: []Option{
WithIds([]string{"video-id"}),
WithReasonId("reason-id"),
WithComments("spam"),
WithLanguage("en"),
WithSecondaryReasonId("secondary-reason"),
},
verify: func(r *http.Request) {
if r.Method != "POST" {
@@ -940,6 +1237,14 @@ func TestVideo_ReportAbuse(t *testing.T) {
},
wantErr: false,
},
{
name: "report abuse multiple videos",
opts: []Option{
WithIds([]string{"video-1", "video-2"}),
WithReasonId("reason-id"),
},
wantErr: false,
},
}
for _, tt := range tests {