| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- package http
- import (
- "io"
- "log/slog"
- "net/http"
- "net/http/httptest"
- "strings"
- "testing"
- "time"
- "github.com/google/uuid"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "github.com/mk6i/retro-aim-server/state"
- "github.com/mk6i/retro-aim-server/wire"
- )
- func TestSessionHandler_GET(t *testing.T) {
- fnNewSess := func(screenName string) *state.Session {
- sess := state.NewSession()
- sess.SetIdentScreenName(state.NewIdentScreenName(screenName))
- sess.SetDisplayScreenName(state.DisplayScreenName(screenName))
- return sess
- }
- tt := []struct {
- name string
- sessions []*state.Session
- userHandlerErr error
- want string
- statusCode int
- }{
- {
- name: "without sessions",
- sessions: []*state.Session{},
- want: `{"count":0,"sessions":[]}`,
- statusCode: http.StatusOK,
- },
- {
- name: "with sessions",
- sessions: []*state.Session{
- fnNewSess("userA"),
- fnNewSess("userB"),
- },
- want: `{"count":2,"sessions":[{"id":"usera","screen_name":"userA"},{"id":"userb","screen_name":"userB"}]}`,
- statusCode: http.StatusOK,
- },
- }
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- request := httptest.NewRequest(http.MethodGet, "/session", nil)
- responseRecorder := httptest.NewRecorder()
- sessionRetriever := newMockSessionRetriever(t)
- sessionRetriever.EXPECT().
- AllSessions().
- Return(tc.sessions)
- sessionHandler(responseRecorder, request, sessionRetriever)
- if responseRecorder.Code != tc.statusCode {
- t.Errorf("Want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
- }
- if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
- t.Errorf("Want '%s', got '%s'", tc.want, responseRecorder.Body)
- }
- })
- }
- }
- func TestSessionHandler_DisallowedMethod(t *testing.T) {
- request := httptest.NewRequest(http.MethodPut, "/session", nil)
- responseRecorder := httptest.NewRecorder()
- sessionHandler(responseRecorder, request, nil)
- wantCode := http.StatusMethodNotAllowed
- if responseRecorder.Code != wantCode {
- t.Errorf("want status '%d', got '%d'", http.StatusMethodNotAllowed, responseRecorder.Code)
- }
- wantBody := `method not allowed`
- if strings.TrimSpace(responseRecorder.Body.String()) != wantBody {
- t.Errorf("want '%s', got '%s'", wantBody, responseRecorder.Body)
- }
- }
- func TestUserHandler_GET(t *testing.T) {
- tt := []struct {
- name string
- users []state.User
- userHandlerErr error
- want string
- statusCode int
- }{
- {
- name: "empty user store",
- users: []state.User{},
- want: `[]`,
- statusCode: http.StatusOK,
- },
- {
- name: "user store containing 2 users",
- users: []state.User{
- {
- DisplayScreenName: "userA",
- IdentScreenName: state.NewIdentScreenName("userA"),
- },
- {
- DisplayScreenName: "userB",
- IdentScreenName: state.NewIdentScreenName("userB"),
- },
- },
- want: `[{"id":"usera","screen_name":"userA"},{"id":"userb","screen_name":"userB"}]`,
- statusCode: http.StatusOK,
- },
- {
- name: "user handler error",
- users: []state.User{},
- userHandlerErr: io.EOF,
- want: `internal server error`,
- statusCode: http.StatusInternalServerError,
- },
- }
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- request := httptest.NewRequest(http.MethodGet, "/user", nil)
- responseRecorder := httptest.NewRecorder()
- userManager := newMockUserManager(t)
- userManager.EXPECT().
- AllUsers().
- Return(tc.users, tc.userHandlerErr)
- userHandler(responseRecorder, request, userManager, nil, slog.Default())
- if responseRecorder.Code != tc.statusCode {
- t.Errorf("Want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
- }
- if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
- t.Errorf("Want '%s', got '%s'", tc.want, responseRecorder.Body)
- }
- })
- }
- }
- func TestUserHandler_POST(t *testing.T) {
- tt := []struct {
- name string
- body string
- UUID uuid.UUID
- user state.User
- userHandlerErr error
- want string
- statusCode int
- }{
- {
- name: "with valid user",
- body: `{"screen_name":"userA", "password":"thepassword"}`,
- UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
- user: func() state.User {
- user := state.User{
- AuthKey: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
- DisplayScreenName: "userA",
- IdentScreenName: state.NewIdentScreenName("userA"),
- }
- assert.NoError(t, user.HashPassword("thepassword"))
- return user
- }(),
- want: `User account created successfully.`,
- statusCode: http.StatusCreated,
- },
- {
- name: "with malformed body",
- body: `{"screen_name":"userA", "password":"thepassword"`,
- user: state.User{},
- want: `malformed input`,
- statusCode: http.StatusBadRequest,
- },
- {
- name: "user handler error",
- body: `{"screen_name":"userA", "password":"thepassword"}`,
- UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
- user: func() state.User {
- user := state.User{
- AuthKey: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
- DisplayScreenName: "userA",
- IdentScreenName: state.NewIdentScreenName("userA"),
- }
- assert.NoError(t, user.HashPassword("thepassword"))
- return user
- }(),
- userHandlerErr: io.EOF,
- want: `internal server error`,
- statusCode: http.StatusInternalServerError,
- },
- {
- name: "duplicate user",
- body: `{"screen_name":"userA", "password":"thepassword"}`,
- UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
- user: func() state.User {
- user := state.User{
- AuthKey: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
- DisplayScreenName: "userA",
- IdentScreenName: state.NewIdentScreenName("userA"),
- }
- assert.NoError(t, user.HashPassword("thepassword"))
- return user
- }(),
- userHandlerErr: state.ErrDupUser,
- want: `user already exists`,
- statusCode: http.StatusConflict,
- },
- }
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- request := httptest.NewRequest(http.MethodPost, "/user", strings.NewReader(tc.body))
- responseRecorder := httptest.NewRecorder()
- userManager := newMockUserManager(t)
- if tc.user.IdentScreenName.String() != "" {
- userManager.EXPECT().
- InsertUser(tc.user).
- Return(tc.userHandlerErr)
- }
- newUUID := func() uuid.UUID { return tc.UUID }
- userHandler(responseRecorder, request, userManager, newUUID, slog.Default())
- if responseRecorder.Code != tc.statusCode {
- t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
- }
- if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
- t.Errorf("want '%s', got '%s'", tc.want, responseRecorder.Body)
- }
- })
- }
- }
- func TestUserHandler_DELETE(t *testing.T) {
- tt := []struct {
- name string
- body string
- user state.User
- userHandlerErr error
- want string
- statusCode int
- }{
- {
- name: "with valid user",
- body: `{"screen_name":"userA"}`,
- user: state.User{
- IdentScreenName: state.NewIdentScreenName("userA"),
- },
- want: `User account successfully deleted.`,
- statusCode: http.StatusNoContent,
- },
- {
- name: "with non-existent user",
- body: `{"screen_name":"userA"}`,
- user: state.User{
- IdentScreenName: state.NewIdentScreenName("userA"),
- },
- userHandlerErr: state.ErrNoUser,
- want: `user does not exist`,
- statusCode: http.StatusNotFound,
- },
- {
- name: "with malformed body",
- body: `{"screen_name":"userA"`,
- user: state.User{},
- want: `malformed input`,
- statusCode: http.StatusBadRequest,
- },
- {
- name: "user handler error",
- body: `{"screen_name":"userA"}`,
- user: state.User{
- IdentScreenName: state.NewIdentScreenName("userA"),
- },
- userHandlerErr: io.EOF,
- want: `internal server error`,
- statusCode: http.StatusInternalServerError,
- },
- }
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- request := httptest.NewRequest(http.MethodDelete, "/user", strings.NewReader(tc.body))
- responseRecorder := httptest.NewRecorder()
- userManager := newMockUserManager(t)
- if tc.user.IdentScreenName.String() != "" {
- userManager.EXPECT().
- DeleteUser(tc.user.IdentScreenName).
- Return(tc.userHandlerErr)
- }
- userHandler(responseRecorder, request, userManager, nil, slog.Default())
- if responseRecorder.Code != tc.statusCode {
- t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
- }
- if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
- t.Errorf("want '%s', got '%s'", tc.want, responseRecorder.Body)
- }
- })
- }
- }
- func TestUserPasswordHandler_PUT(t *testing.T) {
- tt := []struct {
- name string
- body string
- user state.User
- UUID uuid.UUID
- userHandlerErr error
- want string
- statusCode int
- }{
- {
- name: "with valid password",
- body: `{"screen_name":"userA", "password":"thepassword"}`,
- UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
- user: func() state.User {
- user := state.User{
- AuthKey: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
- IdentScreenName: state.NewIdentScreenName("userA"),
- }
- assert.NoError(t, user.HashPassword("thepassword"))
- return user
- }(),
- want: ``,
- statusCode: http.StatusNoContent,
- },
- {
- name: "with malformed body",
- body: `{"screen_name":"userA", "password":"thepassword"`,
- user: state.User{},
- want: `malformed input`,
- statusCode: http.StatusBadRequest,
- },
- {
- name: "user password handler error",
- body: `{"screen_name":"userA", "password":"thepassword"}`,
- UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
- user: func() state.User {
- user := state.User{
- AuthKey: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
- IdentScreenName: state.NewIdentScreenName("userA"),
- }
- assert.NoError(t, user.HashPassword("thepassword"))
- return user
- }(),
- userHandlerErr: io.EOF,
- want: `internal server error`,
- statusCode: http.StatusInternalServerError,
- },
- {
- name: "user doesn't exist",
- body: `{"screen_name":"userA", "password":"thepassword"}`,
- UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
- user: func() state.User {
- user := state.User{
- AuthKey: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
- IdentScreenName: state.NewIdentScreenName("userA"),
- }
- assert.NoError(t, user.HashPassword("thepassword"))
- return user
- }(),
- userHandlerErr: state.ErrNoUser,
- want: `user does not exist`,
- statusCode: http.StatusNotFound,
- },
- }
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- request := httptest.NewRequest(http.MethodPut, "/user", strings.NewReader(tc.body))
- responseRecorder := httptest.NewRecorder()
- userManager := newMockUserManager(t)
- if tc.user.IdentScreenName.String() != "" {
- userManager.EXPECT().
- SetUserPassword(tc.user).
- Return(tc.userHandlerErr)
- }
- newUUID := func() uuid.UUID { return tc.UUID }
- userPasswordHandler(responseRecorder, request, userManager, newUUID, slog.Default())
- if responseRecorder.Code != tc.statusCode {
- t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
- }
- if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
- t.Errorf("want '%s', got '%s'", tc.want, responseRecorder.Body)
- }
- })
- }
- }
- func TestUserHandler_DisallowedMethod(t *testing.T) {
- request := httptest.NewRequest(http.MethodPut, "/user", nil)
- responseRecorder := httptest.NewRecorder()
- userHandler(responseRecorder, request, nil, nil, nil)
- wantCode := http.StatusMethodNotAllowed
- if responseRecorder.Code != wantCode {
- t.Errorf("want status '%d', got '%d'", http.StatusMethodNotAllowed, responseRecorder.Code)
- }
- wantBody := `method not allowed`
- if strings.TrimSpace(responseRecorder.Body.String()) != wantBody {
- t.Errorf("want '%s', got '%s'", wantBody, responseRecorder.Body)
- }
- }
- func TestPublicChatHandler_GET(t *testing.T) {
- fnNewSess := func(screenName string) *state.Session {
- sess := state.NewSession()
- sess.SetIdentScreenName(state.NewIdentScreenName(screenName))
- sess.SetDisplayScreenName(state.DisplayScreenName(screenName))
- return sess
- }
- type allChatRoomsParams struct {
- exchange uint16
- result []state.ChatRoom
- err error
- }
- type allSessionsParams struct {
- cookie string
- result []*state.Session
- }
- tt := []struct {
- name string
- allChatRoomsParams allChatRoomsParams
- allSessionsParams []allSessionsParams
- userHandlerErr error
- want string
- statusCode int
- }{
- {
- name: "multiple chat rooms with participants",
- allChatRoomsParams: allChatRoomsParams{
- exchange: state.PublicExchange,
- result: []state.ChatRoom{
- {
- Cookie: "chat-room-1-cookie",
- Creator: state.NewIdentScreenName("chat-room-1-creator"),
- Name: "chat-room-1-name",
- CreateTime: time.Date(2024, 06, 01, 1, 2, 3, 4, time.UTC),
- },
- {
- Cookie: "chat-room-2-cookie",
- Creator: state.NewIdentScreenName("chat-room-2-creator"),
- Name: "chat-room-2-name",
- CreateTime: time.Date(2022, 01, 04, 6, 8, 1, 2, time.UTC),
- },
- },
- },
- allSessionsParams: []allSessionsParams{
- {
- cookie: "chat-room-1-cookie",
- result: []*state.Session{
- fnNewSess("userA"),
- fnNewSess("userB"),
- },
- },
- {
- cookie: "chat-room-2-cookie",
- result: []*state.Session{
- fnNewSess("userC"),
- fnNewSess("userD"),
- },
- },
- },
- want: `[{"name":"chat-room-1-name","create_time":"2024-06-01T01:02:03.000000004Z","url":"aim:gochat?exchange=0\u0026roomname=chat-room-1-name","participants":[{"id":"usera","screen_name":"userA"},{"id":"userb","screen_name":"userB"}]},{"name":"chat-room-2-name","create_time":"2022-01-04T06:08:01.000000002Z","url":"aim:gochat?exchange=0\u0026roomname=chat-room-2-name","participants":[{"id":"userc","screen_name":"userC"},{"id":"userd","screen_name":"userD"}]}]`,
- statusCode: http.StatusOK,
- },
- {
- name: "chat room without participants",
- allChatRoomsParams: allChatRoomsParams{
- exchange: state.PublicExchange,
- result: []state.ChatRoom{
- {
- Cookie: "chat-room-1-cookie",
- Creator: state.NewIdentScreenName("chat-room-1-creator"),
- Name: "chat-room-1-name",
- CreateTime: time.Date(2024, 06, 01, 1, 2, 3, 4, time.UTC),
- },
- },
- },
- allSessionsParams: []allSessionsParams{
- {
- cookie: "chat-room-1-cookie",
- result: []*state.Session{},
- },
- },
- want: `[{"name":"chat-room-1-name","create_time":"2024-06-01T01:02:03.000000004Z","url":"aim:gochat?exchange=0\u0026roomname=chat-room-1-name","participants":[]}]`,
- statusCode: http.StatusOK,
- },
- {
- name: "no chat rooms",
- allChatRoomsParams: allChatRoomsParams{
- exchange: state.PublicExchange,
- result: []state.ChatRoom{},
- },
- allSessionsParams: []allSessionsParams{},
- want: `[]`,
- statusCode: http.StatusOK,
- },
- }
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- request := httptest.NewRequest(http.MethodGet, "/chat/room/public", nil)
- responseRecorder := httptest.NewRecorder()
- chatRoomRetriever := newMockChatRoomRetriever(t)
- chatRoomRetriever.EXPECT().
- AllChatRooms(tc.allChatRoomsParams.exchange).
- Return(tc.allChatRoomsParams.result, tc.allChatRoomsParams.err)
- chatSessionRetriever := newMockChatSessionRetriever(t)
- for _, params := range tc.allSessionsParams {
- chatSessionRetriever.EXPECT().
- AllSessions(params.cookie).
- Return(params.result)
- }
- getPublicChatHandler(responseRecorder, request, chatRoomRetriever, chatSessionRetriever, slog.Default())
- if responseRecorder.Code != tc.statusCode {
- t.Errorf("Want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
- }
- if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
- t.Errorf("Want '%s', got '%s'", tc.want, responseRecorder.Body)
- }
- })
- }
- }
- func TestPrivateChatHandler_GET(t *testing.T) {
- fnNewSess := func(screenName string) *state.Session {
- sess := state.NewSession()
- sess.SetIdentScreenName(state.NewIdentScreenName(screenName))
- sess.SetDisplayScreenName(state.DisplayScreenName(screenName))
- return sess
- }
- type allChatRoomsParams struct {
- exchange uint16
- result []state.ChatRoom
- err error
- }
- type allSessionsParams struct {
- cookie string
- result []*state.Session
- }
- tt := []struct {
- name string
- allChatRoomsParams allChatRoomsParams
- allSessionsParams []allSessionsParams
- userHandlerErr error
- want string
- statusCode int
- }{
- {
- name: "multiple chat rooms with participants",
- allChatRoomsParams: allChatRoomsParams{
- exchange: state.PrivateExchange,
- result: []state.ChatRoom{
- {
- Cookie: "chat-room-1-cookie",
- Creator: state.NewIdentScreenName("chat-room-1-creator"),
- Name: "chat-room-1-name",
- CreateTime: time.Date(2024, 06, 01, 1, 2, 3, 4, time.UTC),
- },
- {
- Cookie: "chat-room-2-cookie",
- Creator: state.NewIdentScreenName("chat-room-2-creator"),
- Name: "chat-room-2-name",
- CreateTime: time.Date(2022, 01, 04, 6, 8, 1, 2, time.UTC),
- },
- },
- },
- allSessionsParams: []allSessionsParams{
- {
- cookie: "chat-room-1-cookie",
- result: []*state.Session{
- fnNewSess("userA"),
- fnNewSess("userB"),
- },
- },
- {
- cookie: "chat-room-2-cookie",
- result: []*state.Session{
- fnNewSess("userC"),
- fnNewSess("userD"),
- },
- },
- },
- want: `[{"name":"chat-room-1-name","create_time":"2024-06-01T01:02:03.000000004Z","creator_id":"chat-room-1-creator","url":"aim:gochat?exchange=0\u0026roomname=chat-room-1-name","participants":[{"id":"usera","screen_name":"userA"},{"id":"userb","screen_name":"userB"}]},{"name":"chat-room-2-name","create_time":"2022-01-04T06:08:01.000000002Z","creator_id":"chat-room-2-creator","url":"aim:gochat?exchange=0\u0026roomname=chat-room-2-name","participants":[{"id":"userc","screen_name":"userC"},{"id":"userd","screen_name":"userD"}]}]`,
- statusCode: http.StatusOK,
- },
- {
- name: "chat room without participants",
- allChatRoomsParams: allChatRoomsParams{
- exchange: state.PrivateExchange,
- result: []state.ChatRoom{
- {
- Cookie: "chat-room-1-cookie",
- Creator: state.NewIdentScreenName("chat-room-1-creator"),
- Name: "chat-room-1-name",
- CreateTime: time.Date(2024, 06, 01, 1, 2, 3, 4, time.UTC),
- },
- },
- },
- allSessionsParams: []allSessionsParams{
- {
- cookie: "chat-room-1-cookie",
- result: []*state.Session{},
- },
- },
- want: `[{"name":"chat-room-1-name","create_time":"2024-06-01T01:02:03.000000004Z","creator_id":"chat-room-1-creator","url":"aim:gochat?exchange=0\u0026roomname=chat-room-1-name","participants":[]}]`,
- statusCode: http.StatusOK,
- },
- {
- name: "no chat rooms",
- allChatRoomsParams: allChatRoomsParams{
- exchange: state.PrivateExchange,
- result: []state.ChatRoom{},
- },
- allSessionsParams: []allSessionsParams{},
- want: `[]`,
- statusCode: http.StatusOK,
- },
- }
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- request := httptest.NewRequest(http.MethodGet, "/chat/room/private", nil)
- responseRecorder := httptest.NewRecorder()
- chatRoomRetriever := newMockChatRoomRetriever(t)
- chatRoomRetriever.EXPECT().
- AllChatRooms(tc.allChatRoomsParams.exchange).
- Return(tc.allChatRoomsParams.result, tc.allChatRoomsParams.err)
- chatSessionRetriever := newMockChatSessionRetriever(t)
- for _, params := range tc.allSessionsParams {
- chatSessionRetriever.EXPECT().
- AllSessions(params.cookie).
- Return(params.result)
- }
- getPrivateChatHandler(responseRecorder, request, chatRoomRetriever, chatSessionRetriever, slog.Default())
- if responseRecorder.Code != tc.statusCode {
- t.Errorf("Want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
- }
- if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
- t.Errorf("Want '%s', got '%s'", tc.want, responseRecorder.Body)
- }
- })
- }
- }
- func TestInstantMessageHandler_POST(t *testing.T) {
- type relayToScreenNameParams struct {
- sender state.IdentScreenName
- recipient state.IdentScreenName
- msg string
- }
- tt := []struct {
- name string
- relayToScreenNameParams []relayToScreenNameParams
- body string
- want string
- statusCode int
- }{
- {
- name: "send an instant message",
- relayToScreenNameParams: []relayToScreenNameParams{
- {
- sender: state.NewIdentScreenName("sender_sn"),
- recipient: state.NewIdentScreenName("recip_sn"),
- msg: "hello world!",
- },
- },
- body: `{"from":"sender_sn","to":"recip_sn","text":"hello world!"}`,
- want: `Message sent successfully.`,
- statusCode: http.StatusOK,
- },
- {
- name: "with malformed body",
- body: `{"screen_name":"userA", "password":"thepassword"`,
- want: `malformed input`,
- statusCode: http.StatusBadRequest,
- },
- }
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- request := httptest.NewRequest(http.MethodPost, "/user", strings.NewReader(tc.body))
- responseRecorder := httptest.NewRecorder()
- messageRelayer := newMockMessageRelayer(t)
- for _, params := range tc.relayToScreenNameParams {
- validateSNAC := func(msg wire.SNACMessage) bool {
- body := msg.Body.(wire.SNAC_0x04_0x07_ICBMChannelMsgToClient)
- assert.Equal(t, params.sender.String(), body.TLVUserInfo.ScreenName)
- b, ok := body.Slice(wire.ICBMTLVAOLIMData)
- assert.True(t, ok)
- txt, err := wire.UnmarshalICBMMessageText(b)
- assert.NoError(t, err)
- assert.Equal(t, params.msg, txt)
- return true
- }
- messageRelayer.EXPECT().
- RelayToScreenName(mock.Anything, params.recipient, mock.MatchedBy(validateSNAC))
- }
- postInstantMessageHandler(responseRecorder, request, messageRelayer, slog.Default())
- if responseRecorder.Code != tc.statusCode {
- t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
- }
- if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
- t.Errorf("want '%s', got '%s'", tc.want, responseRecorder.Body)
- }
- })
- }
- }
|