Published an OpportunityMarksUpdated event when an opportunity's marks change over the API

This commit is contained in:
bwilliams committed 2026-10-16 13:19:58 +01:00
1 parent 70d62f280e
commit 848edc73e2
7 files changed
+203 -34

No files matched your search

+66 -7
View File
@@ -20,6 +20,7 @@ import (
"github.com/spf13/viper"
"git.avsdev.uk/Go/job-search/internal/config"
"git.avsdev.uk/Go/job-search/internal/events"
"git.avsdev.uk/Go/job-search/internal/middleware"
"git.avsdev.uk/Go/job-search/internal/store"
"git.avsdev.uk/Go/job-search/internal/types"
@@ -336,10 +337,11 @@ func (b *syncBuffer) String() string {
return b.buffer.String()
}
// With WithOpportunityStore the opportunities are served, and changing a mark
// needs the CSRF token; without it there are no opportunity routes.
func TestOpportunityRoutes(t *testing.T) {
opportunityStore, err := store.Open(
// opportunityStore returns a store, in a temporary file, holding one
// opportunity, ocds-1.
func opportunityStore(t *testing.T) *store.Store {
t.Helper()
st, err := store.Open(
context.Background(),
filepath.Join(t.TempDir(), "server.db"),
store.WithAutoMigrate(),
@@ -348,9 +350,9 @@ func TestOpportunityRoutes(t *testing.T) {
t.Fatal(err)
}
t.Cleanup(func() {
opportunityStore.Close()
st.Close()
})
_, err = opportunityStore.SaveOpportunity(
_, err = st.SaveOpportunity(
context.Background(),
&types.Opportunity{
UUID: "ocds-1",
@@ -368,7 +370,13 @@ func TestOpportunityRoutes(t *testing.T) {
t.Fatal(err)
}
ts := newTestServer(t, nil, WithStore(opportunityStore))
return st
}
// With WithStore the opportunities are served, and changing a mark needs
// the CSRF token; without it there are no opportunity routes.
func TestOpportunityRoutes(t *testing.T) {
ts := newTestServer(t, nil, WithStore(opportunityStore(t)))
c := clientWithJar(t)
do := apiClient(t, ts, c, getToken(t, c, ts.URL))
@@ -393,3 +401,54 @@ func TestOpportunityRoutes(t *testing.T) {
t.Errorf("no store: %d; want 404", res.StatusCode)
}
}
// With WithEvents, events published to the bus, and the API's own, such as
// a changed mark, are pushed to WebSocket clients.
func TestEventsPushed(t *testing.T) {
var bus events.Bus
ts := newTestServer(
t, nil, WithStore(opportunityStore(t)), WithEvents(&bus),
)
c := clientWithJar(t)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
conn, _, err := websocket.Dial(
ctx,
"ws"+strings.TrimPrefix(ts.URL, "http")+"/ws",
&websocket.DialOptions{
HTTPClient: c,
},
)
if err != nil {
t.Fatal(err)
}
defer conn.CloseNow()
read := func() ws.Envelope {
var e ws.Envelope
if err := wsjson.Read(ctx, conn, &e); err != nil {
t.Fatal(err)
}
return e
}
read() // welcome
bus.Publish(events.Event{
Type: events.OpportunitiesUpdated,
Payload: map[string]int{"n": 1},
})
e := read()
if e.Type != ws.TypeEvent || e.EventType != events.OpportunitiesUpdated {
t.Fatalf("want the published event, got %+v", e)
}
do := apiClient(t, ts, c, getToken(t, c, ts.URL))
mark := "/api/opportunities/ocds-1/marks/interested"
if res := do("PUT", mark, "", true); res.StatusCode != 200 {
t.Fatalf("mark: %d", res.StatusCode)
}
e = read()
if e.EventType != events.OpportunityMarksUpdated ||
!strings.Contains(string(e.Payload), `"interested":true`) {
t.Fatalf("want the marks event, got %+v", e)
}
}