Skip to content

Commit

Permalink
website/api/v1: try and test the SSE handler
Browse files Browse the repository at this point in the history
These tests are pretty low quality right now but it atleast tests the
very basic functionality of the code.
  • Loading branch information
Wessie committed Feb 25, 2024
1 parent fe13e47 commit aa808f7
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 74 deletions.
2 changes: 1 addition & 1 deletion generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package radio

//go:generate go generate ./rpc/generate.go
//go:generate moq -out mocks/radio.gen.go -pkg mocks . StorageService StorageTx TrackStorage SubmissionStorage UserStorage
//go:generate moq -out mocks/templates.gen.go -pkg mocks ./templates/ Executor
//go:generate moq -out mocks/templates.gen.go -pkg mocks ./templates/ Executor TemplateSelectable
//go:generate moq -out mocks/util.gen.go -pkg mocks ./mocks/ FS File FileInfo
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/alevinval/sse v1.0.2 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/containerd/containerd v1.7.11 // indirect
github.com/containerd/log v0.1.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/XSAM/otelsql v0.27.0 h1:i9xtxtdcqXV768a5C6SoT/RkG+ue3JTOgkYInzlTOqs=
github.com/XSAM/otelsql v0.27.0/go.mod h1:0mFB3TvLa7NCuhm/2nU7/b2wEtsczkj8Rey8ygO7V+A=
github.com/alevinval/sse v1.0.2 h1:ooc08hn9B5X/u7vOMpnYDkXxIKA0y5DOw9qBVVK3YKY=
github.com/alevinval/sse v1.0.2/go.mod h1:X4J1/nTNs4yKbvjXFWJB+NdF9gaYkoAC4sw9Z9h7ASk=
github.com/alexedwards/scs/v2 v2.7.0 h1:DY4rqLCM7UIR9iwxFS0++z1NhTzQlKV30aMHkJCDWKw=
github.com/alexedwards/scs/v2 v2.7.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
Expand Down
62 changes: 0 additions & 62 deletions streamer/streamer_test.go

This file was deleted.

4 changes: 2 additions & 2 deletions website/admin/pending.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"path/filepath"
"slices"
"strconv"
"time"

radio "github.com/R-a-dio/valkyrie"
"github.com/R-a-dio/valkyrie/errors"
Expand Down Expand Up @@ -427,8 +428,7 @@ func (pf *PendingForm) Update(form url.Values) {
pf.ReplacementID = radio.TrackID(id)
}
pf.Reason = form.Get("reason")
// TODO: move reviewedat into db layer
// pf.ReviewedAt = time.Now()
pf.ReviewedAt = time.Now()
pf.GoodUpload = form.Get("good") != ""
}

Expand Down
7 changes: 2 additions & 5 deletions website/api/php/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,7 @@ func (a *API) getSearch(w http.ResponseWriter, r *http.Request) {
rawLimit := values.Get("limit")
parsedLimit, err := strconv.Atoi(rawLimit)
if err == nil && parsedLimit < 20 {
// TODO: check if we just want to throw a fit if NaN
// only use the value if it's a number and it's
// not above the allowed limit
// if used defined limit isn't a number just return the standard 20
limit = parsedLimit
}
}
Expand All @@ -188,8 +186,7 @@ func (a *API) getSearch(w http.ResponseWriter, r *http.Request) {
rawPage := values.Get("page")
parsedPage, err := strconv.Atoi(rawPage)
if err == nil {
// TODO: check if we just want to throw a fit if NaN
// only use the value if it's a valid number
// if it's not a number just return the first page
page = parsedPage
}
}
Expand Down
10 changes: 6 additions & 4 deletions website/api/v1/sse.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ func (a *API) runStatusUpdates(ctx context.Context) error {
continue
}

// we send to the now playing sse stream and separately to
// a streamer sse stream
// only send events if the relevant data to said event has changed
// since our previous status
if !status.Song.EqualTo(previous.Song) {
log.Debug().Str("event", EventMetadata).Any("value", status).Msg("sending")
a.sse.SendNowPlaying(status)
Expand All @@ -79,6 +79,8 @@ func (a *API) runStatusUpdates(ctx context.Context) error {
if status.User.ID != previous.User.ID {
log.Debug().Str("event", EventStreamer).Any("value", status.User).Msg("sending")
a.sse.SendStreamer(status.User)
// TODO(wessie): queue is technically only used for the automated streamer
// and should probably have an extra event trigger here to make it disappear
}

previous = status
Expand Down Expand Up @@ -116,7 +118,7 @@ const (
)

const (
EventPing = "ping"
EventTime = "time"
EventMetadata = "metadata"
EventStreamer = "streamer"
EventQueue = "queue"
Expand Down Expand Up @@ -171,7 +173,7 @@ func (s *Stream) ServeHTTP(w http.ResponseWriter, r *http.Request) {

// send a sync timestamp
now := strconv.FormatInt(time.Now().UnixMilli(), 10)
_, _ = w.Write(sse.Event{Name: "time", Data: []byte(now)}.Encode())
_, _ = w.Write(sse.Event{Name: string(EventTime), Data: []byte(now)}.Encode())

// send events that have already happened, one for each event so that
// we're certain the page is current
Expand Down
152 changes: 152 additions & 0 deletions website/api/v1/sse_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package v1

import (
"context"
"encoding/json"
"net"
"net/http/httptest"
"reflect"
"sync"
"testing"
"time"

radio "github.com/R-a-dio/valkyrie"
"github.com/R-a-dio/valkyrie/mocks"
"github.com/R-a-dio/valkyrie/templates"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/arbitrary"
"github.com/leanovate/gopter/gen"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/alevinval/sse/pkg/eventsource"
)

func TestStream(t *testing.T) {
exec := &mocks.ExecutorMock{
ExecuteAllFunc: func(input templates.TemplateSelectable) (map[string][]byte, error) {
jsonData, err := json.Marshal(input)
if err != nil {
return nil, err
}

return map[string][]byte{
"json": jsonData,
}, nil
},
}

var muExpected sync.Mutex
var expected radio.Status

stream := NewStream(exec)
server := httptest.NewUnstartedServer(stream)
server.Config.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
return templates.SetTheme(ctx, "json")
}
server.Start()

t.Log(server.URL)
es1, err := eventsource.New(server.URL)
require.NoError(t, err)

sync := make(chan struct{})
go func() {
a := arbitrary.DefaultArbitraries()
timeGen := func(gp *gopter.GenParameters) *gopter.GenResult {
v := time.Date(2000, 10, 9, 8, 7, 6, 5, time.UTC)
res := gen.Time()(gp)
res.Result = v
return res
}
a.RegisterGen(timeGen)
a.RegisterGen(gen.PtrOf(timeGen))

genStatus := a.GenForType(reflect.TypeOf(radio.Status{}))
param := gopter.DefaultGenParameters()

for i := 0; i < 100; i++ {
res := genStatus(param)
<-sync
sendStatus := res.Result.(radio.Status)
muExpected.Lock()
expected = sendStatus
muExpected.Unlock()
stream.SendNowPlaying(sendStatus)
}
}()

ch1 := es1.MessageEvents()

jsonEvent := <-ch1

assert.Equal(t, EventTime, jsonEvent.Name)

for i := 0; i < 100; i++ {
sync <- struct{}{}
jsonEvent = <-ch1
assert.Equal(t, EventMetadata, jsonEvent.Name)

var status radio.Status

// check the json version
err = json.Unmarshal([]byte(jsonEvent.Data), &status)
assert.NoError(t, err)
muExpected.Lock()
assert.Equal(t, expected, status)
muExpected.Unlock()
}
}

func TestStreamSendInputs(t *testing.T) {
var name string

exec := &mocks.ExecutorMock{
ExecuteAllFunc: func(input templates.TemplateSelectable) (map[string][]byte, error) {
name = input.TemplateName()
return nil, nil
},
}

stream := NewStream(exec)
defer stream.Shutdown()

t.Run("SendStreamer", func(t *testing.T) {
stream.SendStreamer(radio.User{})
assert.Equal(t, "streamer", name)
})

t.Run("SendNowPlaying", func(t *testing.T) {
stream.SendNowPlaying(radio.Status{})
assert.Equal(t, "nowplaying", name)
})

t.Run("SendQueue", func(t *testing.T) {
stream.SendQueue([]radio.QueueEntry{})
assert.Equal(t, "queue", name)
})

t.Run("SendLastPlayed", func(t *testing.T) {
stream.SendLastPlayed([]radio.Song{})
assert.Equal(t, "lastplayed", name)
})
}

func TestStreamSlowSub(t *testing.T) {
exec := &mocks.ExecutorMock{
ExecuteAllFunc: func(input templates.TemplateSelectable) (map[string][]byte, error) {
return nil, nil
},
}

stream := NewStream(exec)

ctx := templates.SetTheme(context.Background(), "default")
req := httptest.NewRequest("GET", "/", nil)
req = req.WithContext(ctx)
w := httptest.NewRecorder()

go func() {
stream.ServeHTTP(w, req)
}()
}

0 comments on commit aa808f7

Please sign in to comment.