Add mock show generator and timeline benchmark
This commit is contained in:
@@ -34,6 +34,11 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := show.Validate(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error validating show: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
timeline, err := BuildTimeline(show)
|
timeline, err := BuildTimeline(show)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error building timeline: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Error building timeline: %v\n", err)
|
||||||
|
|||||||
70
cmd/qrunproxy/mockshow.go
Normal file
70
cmd/qrunproxy/mockshow.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func GenerateMockShow(numTracks, numCues, numBlocks int) *Show {
|
||||||
|
show := &Show{}
|
||||||
|
|
||||||
|
for i := range numTracks {
|
||||||
|
show.Tracks = append(show.Tracks, &Track{
|
||||||
|
ID: fmt.Sprintf("track_%d", i),
|
||||||
|
Name: fmt.Sprintf("Track %d", i),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range numCues {
|
||||||
|
show.Blocks = append(show.Blocks, &Block{
|
||||||
|
ID: fmt.Sprintf("cue_%d", i),
|
||||||
|
Type: "cue",
|
||||||
|
Name: fmt.Sprintf("Cue %d", i),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
blocksByTrack := make([][]*Block, numTracks)
|
||||||
|
for i := range numBlocks {
|
||||||
|
trackIdx := i % numTracks
|
||||||
|
trackID := fmt.Sprintf("track_%d", trackIdx)
|
||||||
|
block := &Block{
|
||||||
|
ID: fmt.Sprintf("block_%d_%d", trackIdx, len(blocksByTrack[trackIdx])),
|
||||||
|
Type: "media",
|
||||||
|
Track: trackID,
|
||||||
|
Name: fmt.Sprintf("Block %d-%d", trackIdx, len(blocksByTrack[trackIdx])),
|
||||||
|
}
|
||||||
|
show.Blocks = append(show.Blocks, block)
|
||||||
|
blocksByTrack[trackIdx] = append(blocksByTrack[trackIdx], block)
|
||||||
|
}
|
||||||
|
|
||||||
|
for trackIdx := range numTracks {
|
||||||
|
blocks := blocksByTrack[trackIdx]
|
||||||
|
for i := 1; i < len(blocks); i++ {
|
||||||
|
show.Triggers = append(show.Triggers, &Trigger{
|
||||||
|
Source: TriggerSource{Block: blocks[i-1].ID, Signal: "END"},
|
||||||
|
Targets: []TriggerTarget{{Block: blocks[i].ID, Hook: "START"}},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headPerTrack := make([]int, numTracks)
|
||||||
|
for i := range numCues {
|
||||||
|
cue := show.Blocks[i]
|
||||||
|
targets := []TriggerTarget{}
|
||||||
|
for trackIdx := range numTracks {
|
||||||
|
if headPerTrack[trackIdx] >= len(blocksByTrack[trackIdx]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
block := blocksByTrack[trackIdx][headPerTrack[trackIdx]]
|
||||||
|
targets = append(targets, TriggerTarget{Block: block.ID, Hook: "START"})
|
||||||
|
depth := len(blocksByTrack[trackIdx]) - headPerTrack[trackIdx]
|
||||||
|
advance := max(depth/(numCues-i), 1)
|
||||||
|
headPerTrack[trackIdx] += advance
|
||||||
|
}
|
||||||
|
if len(targets) > 0 {
|
||||||
|
show.Triggers = append(show.Triggers, &Trigger{
|
||||||
|
Source: TriggerSource{Block: cue.ID, Signal: "GO"},
|
||||||
|
Targets: targets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return show
|
||||||
|
}
|
||||||
@@ -63,7 +63,7 @@ func isValidEventForBlock(block *Block, event string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (show *Show) validate() error {
|
func (show *Show) Validate() error {
|
||||||
if show == nil {
|
if show == nil {
|
||||||
return fmt.Errorf("show is nil")
|
return fmt.Errorf("show is nil")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,10 +47,6 @@ type cellKey struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BuildTimeline(show *Show) (Timeline, error) {
|
func BuildTimeline(show *Show) (Timeline, error) {
|
||||||
if err := show.validate(); err != nil {
|
|
||||||
return Timeline{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tl := Timeline{
|
tl := Timeline{
|
||||||
show: show,
|
show: show,
|
||||||
Blocks: map[string]*Block{},
|
Blocks: map[string]*Block{},
|
||||||
|
|||||||
52
cmd/qrunproxy/timeline_test.go
Normal file
52
cmd/qrunproxy/timeline_test.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildTimelineFromShowJSON(t *testing.T) {
|
||||||
|
buf, err := os.ReadFile("static/show.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var show Show
|
||||||
|
if err := json.Unmarshal(buf, &show); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := show.Validate(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := BuildTimeline(&show); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineFromMockShow(t *testing.T) {
|
||||||
|
show := GenerateMockShow(7, 100, 1000)
|
||||||
|
if err := show.Validate(); err != nil {
|
||||||
|
t.Fatalf("generated show failed validation: %v", err)
|
||||||
|
}
|
||||||
|
tl, err := BuildTimeline(show)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildTimeline failed: %v", err)
|
||||||
|
}
|
||||||
|
if len(tl.Tracks) != 8 {
|
||||||
|
t.Errorf("expected 8 tracks (7 + cue), got %d", len(tl.Tracks))
|
||||||
|
}
|
||||||
|
if len(tl.Blocks) != 1100 {
|
||||||
|
t.Errorf("expected 1100 blocks (100 cues + 1000), got %d", len(tl.Blocks))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkBuildTimeline(b *testing.B) {
|
||||||
|
show := GenerateMockShow(7, 100, 1000)
|
||||||
|
if err := show.Validate(); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
for range b.N {
|
||||||
|
BuildTimeline(show)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user