Skip to content

Commit

Permalink
vodtester: Add E2E tests for playback (#252)
Browse files Browse the repository at this point in the history
* go.mod: add go-api-client with playback info

* vodtester: Create helper function to check playback

reusing existing stuff

* vodtester: Grab duration from API

So good to avoid having to ffprobe or joy4 locally lol

* vodtester: checkPlayback from all the right places
  • Loading branch information
victorges authored Jan 31, 2023
1 parent 1b90eb1 commit 5dc957e
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 11 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/golang/glog v1.0.0
github.com/gosuri/uilive v0.0.3 // indirect
github.com/gosuri/uiprogress v0.0.1
github.com/livepeer/go-api-client v0.4.2
github.com/livepeer/go-api-client v0.4.2-0.20230124192858-4ae2f6d037f3
github.com/livepeer/go-livepeer v0.5.31
github.com/livepeer/joy4 v0.1.2-0.20220210094601-95e4d28f5f07
github.com/livepeer/leaderboard-serverless v1.0.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -738,8 +738,8 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/livepeer/go-api-client v0.4.2 h1:jfYY6lIpB6XOXSqJOKOc6eQ1VGlYJNh5W+7HFV0v6VE=
github.com/livepeer/go-api-client v0.4.2/go.mod h1:Jdb+RI7JyzEZOHd1GUuKofwFDKMO/btTa80SdpUpYQw=
github.com/livepeer/go-api-client v0.4.2-0.20230124192858-4ae2f6d037f3 h1:qmX+PwBhzvDiybrePyvDmgUK4+n1Ny53UtR0xohNMfs=
github.com/livepeer/go-api-client v0.4.2-0.20230124192858-4ae2f6d037f3/go.mod h1:Jdb+RI7JyzEZOHd1GUuKofwFDKMO/btTa80SdpUpYQw=
github.com/livepeer/go-livepeer v0.5.31 h1:LcN+qDnqWRws7fdVYc4ucZPVcLQRs2tehUYCQVnlnRw=
github.com/livepeer/go-livepeer v0.5.31/go.mod h1:cpBikcGWApkx0cyR0Ht+uAym7j3uAwXGpPbvaOA8XUU=
github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded/go.mod h1:xkDdm+akniYxVT9KW1Y2Y7Hso6aW+rZObz3nrA9yTHw=
Expand Down
66 changes: 63 additions & 3 deletions internal/app/vodtester/vodtester_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ import (

"github.com/golang/glog"
"github.com/livepeer/go-api-client"

"github.com/livepeer/stream-tester/internal/app/common"
"github.com/livepeer/stream-tester/m3u8"
"golang.org/x/sync/errgroup"
)

const maxTimeToWaitForManifest = 20 * time.Second

type (
// IVodTester ...
IVodTester interface {
Expand Down Expand Up @@ -136,8 +140,15 @@ func (vt *vodTester) uploadViaUrlTester(vodImportUrl string, taskPollDuration ti

if err != nil {
glog.Errorf("Error processing asset assetId=%s taskId=%s", importAsset.ID, importTask.ID)
return nil, fmt.Errorf("error waiting for asset processing: %w", err)
}

if err := vt.checkPlayback(importAsset.ID); err != nil {
glog.Errorf("Error checking playback assetId=%s err=%v", importAsset.ID, err)
return nil, fmt.Errorf("error checking playback: %w", err)
}
return importAsset, err

return importAsset, nil
}

func (vt *vodTester) directUploadTester(fileName string, taskPollDuration time.Duration) error {
Expand Down Expand Up @@ -175,8 +186,15 @@ func (vt *vodTester) directUploadTester(fileName string, taskPollDuration time.D
err = vt.CheckTaskProcessing(taskPollDuration, uploadTask)
if err != nil {
glog.Errorf("Error processing asset assetId=%s taskId=%s", uploadAsset.ID, uploadTask.ID)
return fmt.Errorf("error waiting for asset processing: %w", err)
}

if err := vt.checkPlayback(uploadAsset.ID); err != nil {
glog.Errorf("Error checking playback assetId=%s err=%v", uploadAsset.ID, err)
return fmt.Errorf("error checking playback: %w", err)
}
return err

return nil
}

func (vt *vodTester) resumableUploadTester(fileName string, taskPollDuration time.Duration) error {
Expand Down Expand Up @@ -216,9 +234,51 @@ func (vt *vodTester) resumableUploadTester(fileName string, taskPollDuration tim

if err != nil {
glog.Errorf("Error processing asset assetId=%s taskId=%s", uploadAsset.ID, uploadTask.ID)
return fmt.Errorf("error waiting for asset processing: %w", err)
}

if err := vt.checkPlayback(uploadAsset.ID); err != nil {
glog.Errorf("Error checking playback assetId=%s err=%v", uploadAsset.ID, err)
return fmt.Errorf("error checking playback: %w", err)
}

return nil
}

func (vt *vodTester) checkPlayback(assetID string) error {
asset, err := vt.Lapi.GetAsset(assetID, false)
if err != nil {
return fmt.Errorf("error getting asset: %w", err)
} else if asset.VideoSpec.DurationSec <= 0 {
return fmt.Errorf("missing asset duration (%f)", asset.VideoSpec.DurationSec)
}
duration := time.Duration(asset.VideoSpec.DurationSec * float64(time.Second))

pinfo, err := vt.Lapi.GetPlaybackInfo(asset.PlaybackID)
if err != nil {
return fmt.Errorf("error getting playback info: %w", err)
}

return err
var url string
for _, src := range pinfo.Meta.Source {
if src.Type == api.PlaybackInfoSourceTypeHLS {
url = src.Url
break
}
}
if url == "" {
return fmt.Errorf("no HLS source found in playback info")
}

stats, err := m3u8.CheckStats(vt.Ctx, url, duration, maxTimeToWaitForManifest)
if err != nil {
return err
}
if numRenditions := len(stats.SegmentsNum); numRenditions <= 1 {
return fmt.Errorf("no transcoded renditions found in playlist")
}

return nil
}

// Patches the target URL with the source URL host, only if the latter is not
Expand Down
19 changes: 14 additions & 5 deletions m3u8/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/livepeer/go-api-client"
"github.com/livepeer/stream-tester/internal/metrics"
"github.com/livepeer/stream-tester/internal/testers"
"github.com/livepeer/stream-tester/model"
)

func InitCensus(service, version string) {
Expand All @@ -17,14 +18,22 @@ func InitCensus(service, version string) {
}

func Check(ctx context.Context, url string, profiles []api.Profile, expectedDuration time.Duration, timeout time.Duration) error {
downloader := testers.NewM3utester2(ctx, url, false, false, false, false, timeout, nil, false)
<-downloader.Done()
stats := downloader.VODStats()
if ok, ers := stats.IsOk(expectedDuration, false); !ok {
return fmt.Errorf("playlist not ok: %s", ers)
stats, err := CheckStats(ctx, url, expectedDuration, timeout)
if err != nil {
return err
}
if len(stats.SegmentsNum) != len(profiles)+1 {
return fmt.Errorf("number of renditions doesn't match (has %d should %d)", len(stats.SegmentsNum), len(profiles)+1)
}
return nil
}

func CheckStats(ctx context.Context, url string, expectedDuration time.Duration, timeout time.Duration) (model.VODStats, error) {
downloader := testers.NewM3utester2(ctx, url, false, false, false, false, timeout, nil, false)
<-downloader.Done()
stats := downloader.VODStats()
if ok, ers := stats.IsOk(expectedDuration, false); !ok {
return model.VODStats{}, fmt.Errorf("playlist not ok: %s", ers)
}
return stats, nil
}

0 comments on commit 5dc957e

Please sign in to comment.