FEAT: Update Status Of Video Row On Media Convert Update

This commit is contained in:
FahdShalhoub
2026-08-27 20:04:38 +03:00
parent 5d35d4029e
commit 3f5301afb6
25 changed files with 1444 additions and 14 deletions
+180
View File
@@ -2,8 +2,11 @@ package tests
import (
"bytes"
"context"
"net/url"
"slices"
"strings"
"time"
"github.com/go-bdd/gobdd"
)
@@ -352,3 +355,180 @@ func theVideoKeepsTheMetadataISent(t gobdd.StepTest, ctx gobdd.Context) {
t.Errorf("expected the file name %q, got %q", w.sent.FileName, w.video.FileName)
}
}
func askForThatVideo(t gobdd.StepTest, ctx gobdd.Context) {
w := worldOf(t, ctx)
if w.video.ID == "" {
t.Fatalf("no video has been registered, so there is no id to ask for")
return
}
result, err := w.client.get("/api/videos/" + w.video.ID)
if err != nil {
t.Fatalf("could not ask for the video: %s", err)
return
}
w.last = result
w.video = videoBody{}
if result.status == 200 {
if err := result.json(&w.video); err != nil {
t.Fatalf("could not decode the video: %s", err)
}
}
}
func askForVideoWithID(t gobdd.StepTest, ctx gobdd.Context, id string) {
w := worldOf(t, ctx)
result, err := w.client.get("/api/videos/" + url.PathEscape(id))
if err != nil {
t.Fatalf("could not ask for the video: %s", err)
return
}
w.last = result
w.video = videoBody{}
}
// --- transcoding status -----------------------------------------------------
// statusSettleTimeout bounds how long a scenario waits for the consumer to
// pick an event off the queue and write the record. The consumer long-polls,
// so in practice this resolves in well under a second; the budget is for a
// loaded machine, not for a slow path.
const (
statusSettleTimeout = 20 * time.Second
statusPollInterval = 200 * time.Millisecond
statusHoldWindow = 3 * time.Second
)
func registerVideoBeingTranscoded(t gobdd.StepTest, ctx gobdd.Context) {
w := worldOf(t, ctx)
requestUploadSlot(t, ctx, "transcoding.mp4", "video/mp4")
uploadTheFile(t, ctx)
registerUploadedVideo(t, ctx, "A Video Being Transcoded", "other")
if w.last.status != 201 {
t.Fatalf("could not register a video to transcode: %s", w.last.summary())
return
}
if strings.TrimSpace(w.video.MediaConvertJobID) == "" {
t.Fatalf("the registered video carries no transcoding job id, so no event could name it")
return
}
}
func mediaConvertReportsState(t gobdd.StepTest, ctx gobdd.Context, state string) {
w := worldOf(t, ctx)
if strings.TrimSpace(w.video.MediaConvertJobID) == "" {
t.Fatalf("no transcoding job has been started, so there is no job to report on")
return
}
publishJobState(t, w.video.MediaConvertJobID, state)
}
func mediaConvertReportsStateForJob(t gobdd.StepTest, ctx gobdd.Context, jobID, state string) {
worldOf(t, ctx) // keeps the step honest about needing a scenario world
publishJobState(t, jobID, state)
}
func publishJobState(t gobdd.StepTest, jobID, state string) {
background := context.Background()
publisher, err := newEventPublisher(background)
if err != nil {
t.Fatalf("could not reach the job events topic: %s", err)
return
}
if err := publisher.publishJobState(background, jobID, state); err != nil {
t.Fatalf("could not publish the job state change: %s", err)
}
}
func theVideoEventuallyHasStatus(t gobdd.StepTest, ctx gobdd.Context, want string) {
w := worldOf(t, ctx)
deadline := time.Now().Add(statusSettleTimeout)
last := ""
for time.Now().Before(deadline) {
last = currentStatus(t, w)
if last == want {
return
}
time.Sleep(statusPollInterval)
}
t.Errorf("the video never reached status %q within %s; it is still %q", want, statusSettleTimeout, last)
}
func theVideoKeepsStatus(t gobdd.StepTest, ctx gobdd.Context, want string) {
w := worldOf(t, ctx)
// Held rather than sampled once: the consumer is asynchronous, so a status
// that is still "processing" the instant after publishing proves nothing.
deadline := time.Now().Add(statusHoldWindow)
for time.Now().Before(deadline) {
if got := currentStatus(t, w); got != want {
t.Errorf("the video moved to status %q, but this event should have left it %q", got, want)
return
}
time.Sleep(statusPollInterval)
}
}
// currentStatus re-reads the video over the API. It deliberately does not
// touch w.last: these steps assert on the record, not on an exchange.
func currentStatus(t gobdd.StepTest, w *world) string {
result, err := w.client.get("/api/videos/" + w.video.ID)
if err != nil {
t.Fatalf("could not re-read the video: %s", err)
return ""
}
if result.status != 200 {
t.Fatalf("could not re-read the video: %s", result.summary())
return ""
}
var body videoBody
if err := result.json(&body); err != nil {
t.Fatalf("could not decode the video: %s", err)
return ""
}
return body.Status
}
// askForThatVideoWrittenAs re-reads the video by a different, still-valid
// spelling of the same uuid.
func askForThatVideoWrittenAs(t gobdd.StepTest, ctx gobdd.Context, form string) {
w := worldOf(t, ctx)
if w.video.ID == "" {
t.Fatalf("no video has been registered, so there is no id to rewrite")
return
}
var id string
switch form {
case "braced":
id = "{" + w.video.ID + "}"
case "unhyphenated":
id = strings.ReplaceAll(w.video.ID, "-", "")
case "as a urn":
id = "urn:uuid:" + w.video.ID
default:
t.Fatalf("no such spelling of a uuid: %q", form)
return
}
askForVideoWithID(t, ctx, id)
if w.last.status == 200 {
if err := w.last.json(&w.video); err != nil {
t.Fatalf("could not decode the video: %s", err)
}
}
}