package back_test import ( "context" "math/rand" "sort" "testing" "time" "github.com/matryer/is" "github.com/rickb777/date" "gitlab.codemonkeysoftware.net/b/henwen/internal/back" ) func TestNewMemoryStore(t *testing.T) { is := is.New(t) store, err := back.NewMemoryStore(back.SecureGenString) is.NoErr(err) is.True(store != nil) store.Close() } func TestCreateEvent(t *testing.T) { is := is.New(t) store, err := back.NewMemoryStore(back.SecureGenString) is.NoErr(err) defer store.Close() earliest := date.New(2020, 4, 5) latest := date.New(2020, 4, 5) const name = "abc" const description = "def" createResult, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: name, Description: description, Earliest: earliest, Latest: latest, }) is.NoErr(err) metadataResult, err := store.GetEventMetadata(context.Background(), back.GetEventMetadataQuery{ EventID: createResult.EventID, }) is.NoErr(err) is.Equal(metadataResult.Name, name) is.Equal(metadataResult.Description, description) is.True(metadataResult.Earliest.Equal(earliest)) is.True(metadataResult.Latest.Equal(latest)) } func TestGetEventResponseSummary(t *testing.T) { store, err := back.NewMemoryStore(back.SecureGenString) is.New(t).NoErr(err) defer store.Close() createEvent := func(is *is.I) (eventID string) { event, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: "blah", Description: "stuff happening", Earliest: date.Today(), Latest: date.Today().Add(1), }) is.NoErr(err) return event.EventID } t.Run("does not include responses to other events", func(t *testing.T) { is := is.New(t) d := date.New(1999, 12, 31) wrongEvent, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: "Beach party", Description: "Come on in! The water's fine!", Earliest: d, Latest: d, }) is.NoErr(err) _, err = store.CreateEventResponse(context.Background(), back.CreateEventResponseCommand{ EventID: wrongEvent.EventID, GuestName: "Matt Hooper", DateHours: map[date.Date]map[int]struct{}{d: {0: {}}}, }) is.NoErr(err) summary, err := store.GetEventResponseSummary(context.Background(), back.GetEventResponseSummaryQuery{ EventID: createEvent(is), }) is.NoErr(err) is.Equal(summary, back.GetEventResponseSummaryResult{ RespondentNames: nil, PerHourCounts: map[date.Date]map[int]int{}, }) }) t.Run("RespondentNames lists all respondents alphabetically", func(t *testing.T) { is := is.New(t) var names = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"} rand.Shuffle(len(names), func(i, j int) { names[i], names[j] = names[j], names[i] }) d := date.New(1963, time.May, 1) event, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: "It's my party!", Description: "I can cry if I want to.", Latest: d, Earliest: d, }) is.NoErr(err) for _, name := range names { _, err = store.CreateEventResponse(context.Background(), back.CreateEventResponseCommand{ EventID: event.EventID, GuestName: name, }) is.NoErr(err) } summary, err := store.GetEventResponseSummary(context.Background(), back.GetEventResponseSummaryQuery{ EventID: event.EventID, }) is.NoErr(err) sort.Strings(names) is.Equal(summary.RespondentNames, names) }) t.Run("PerHourCounts counts votes per hour", func(t *testing.T) { is := is.New(t) dayOne := date.New(2012, 12, 21) dayTwo := dayOne.Add(1) createResult, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: "Apocalypse", Description: "It's over.", Earliest: dayOne, Latest: dayTwo, }) is.NoErr(err) _, err = store.CreateEventResponse(context.Background(), back.CreateEventResponseCommand{ EventID: createResult.EventID, GuestName: "Thanos", DateHours: map[date.Date]map[int]struct{}{ dayOne: {0: {}, 1: {}, 2: {}, 3: {}}, dayTwo: {1: {}, 2: {}, 3: {}, 4: {}}, }, }) is.NoErr(err) _, err = store.CreateEventResponse(context.Background(), back.CreateEventResponseCommand{ EventID: createResult.EventID, GuestName: "Magog", DateHours: map[date.Date]map[int]struct{}{ dayOne: {1: {}, 2: {}, 3: {}, 4: {}}, dayTwo: {2: {}, 3: {}, 4: {}, 5: {}}, }, }) is.NoErr(err) summary, err := store.GetEventResponseSummary(context.Background(), back.GetEventResponseSummaryQuery{ EventID: createResult.EventID, }) is.NoErr(err) is.Equal(summary.PerHourCounts, map[date.Date]map[int]int{ dayOne: {0: 1, 1: 2, 2: 2, 3: 2, 4: 1}, dayTwo: {1: 1, 2: 2, 3: 2, 4: 2, 5: 1}, }) }) } func TestCreateEventResponse(t *testing.T) { store, err := back.NewMemoryStore(back.SecureGenString) is.New(t).NoErr(err) defer store.Close() createEvent := func(is *is.I) (eventID string) { event, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: "blah", Description: "stuff happening", Earliest: date.Today(), Latest: date.Today().Add(1), }) is.NoErr(err) return event.EventID } t.Run("saves GuestName", func(t *testing.T) { is := is.New(t) eventID := createEvent(is) const guestName = "Etaoin Shrdlu" createResult, err := store.CreateEventResponse(context.Background(), back.CreateEventResponseCommand{ EventID: eventID, GuestName: guestName, }) is.NoErr(err) getResult, err := store.GetEventResponse(context.Background(), back.GetEventResponseQuery{ EventID: eventID, ResponseID: createResult.ResponseID, }) is.NoErr(err) is.Equal(getResult.GuestName, guestName) }) t.Run("DateHours saves multiple times on multiple dates", func(t *testing.T) { is := is.New(t) earliest := date.Today() latest := earliest.Add(1) event, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: "blah", Description: "stuff happening", Earliest: earliest, Latest: latest, }) is.NoErr(err) var dateHours = map[date.Date]map[int]struct{}{ earliest: {1: {}, 3: {}, 5: {}, 7: {}}, latest: {2: {}, 4: {}, 6: {}}, } createResponseResult, err := store.CreateEventResponse(context.Background(), back.CreateEventResponseCommand{ EventID: event.EventID, GuestName: "Etaoin Shrdlu", DateHours: dateHours, }) is.NoErr(err) response, err := store.GetEventResponse(context.Background(), back.GetEventResponseQuery{ EventID: event.EventID, ResponseID: createResponseResult.ResponseID, }) is.NoErr(err) is.Equal(dateHours, response.DateHours) }) } func TestAuthorizeEventAdmin(t *testing.T) { store, err := back.NewMemoryStore(back.SecureGenString) is.New(t).NoErr(err) defer store.Close() t.Run("returns ErrUnauthorized if admin code is wrong", func(t *testing.T) { is := is.New(t) event, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: "my event", Description: "stuff happening", Earliest: date.Today(), Latest: date.Today(), }) is.NoErr(err) badAdminCode := event.AdminCode + "x" err = store.AuthorizeEventAdmin(context.Background(), back.CheckEventAdminCodeQuery{ EventID: event.EventID, AdminCode: badAdminCode, }) is.Equal(err, back.UnauthorizedError{ EventID: event.EventID, AdminCode: badAdminCode, }) }) t.Run("return ErrUnauthorized if event does not exist", func(t *testing.T) { is := is.New(t) randString, err := back.SecureGenString(10) is.NoErr(err) err = store.AuthorizeEventAdmin(context.Background(), back.CheckEventAdminCodeQuery{ EventID: randString, AdminCode: randString, }) is.Equal(err, back.UnauthorizedError{ EventID: randString, AdminCode: randString, }) }) t.Run("returns nil if admin code is correct", func(t *testing.T) { is := is.New(t) event, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ Name: "my event", Description: "stuff happening", Earliest: date.Today(), Latest: date.Today(), }) is.NoErr(err) err = store.AuthorizeEventAdmin(context.Background(), back.CheckEventAdminCodeQuery{ EventID: event.EventID, AdminCode: event.AdminCode, }) is.NoErr(err) }) }