From a2b14c88ea5022d14aa34ac66cf7f99744b9a37b Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 16 Jun 2023 23:35:41 -0700 Subject: [PATCH] Initial commit: conversaions, status, version --- data/generators.go | 118 ++++++++++++++++++++++++++++++++++++++++++ go.mod | 5 ++ go.sum | 2 + main.go | 23 ++++++++ model/conversation.go | 11 ++++ server/server.go | 40 ++++++++++++++ web/server.go | 56 ++++++++++++++++++++ web/server_test.go | 106 +++++++++++++++++++++++++++++++++++++ 8 files changed, 361 insertions(+) create mode 100644 data/generators.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 model/conversation.go create mode 100644 server/server.go create mode 100644 web/server.go create mode 100644 web/server_test.go diff --git a/data/generators.go b/data/generators.go new file mode 100644 index 0000000..e6b84d8 --- /dev/null +++ b/data/generators.go @@ -0,0 +1,118 @@ +package data + +import ( + "math/rand" + "time" + + "code.severnaya.net/kordophone-mock/v2/model" + "github.com/google/uuid" +) + +func GenerateRandomName() string { + // Copilot generated these names. + names := []string{ + "John", + "Jane", + "Joe", + "Jill", + "Jack", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + "Jesse", + "Jenny", + "Jasper", + "Jill", + "Jen", + "Jared", + } + + return names[rand.Intn(len(names))] +} + +func GenerateRandomMessage() string { + // Copilot generated these messages. + messages := []string{ + "Hello, how are you?", + "I'm doing well, how about you?", + "Good, thanks.", + "Great!", + "Awesome!", + "Wow!", + "Amazing!", + "Fantastic!", + "Stupendous!", + "Outstanding!", + "Unbelievable!", + "Unreal!", + "Whoa!", + "Rad!", + "Excellent!", + "Terrific!", + "Superb!", + "Marvelous!", + "Phenomenal!", + "Mind-blowing!", + "Incredible!", + "Extraordinary!", + } + + return messages[rand.Intn(len(messages))] +} + +func GenerateRandomConversation() model.Conversation { + conversation := model.Conversation{ + Participants: []string{GenerateRandomName()}, + UnreadCount: 0, + LastMessagePreview: GenerateRandomMessage(), + Guid: uuid.New().String(), + Date: time.Now().Add(-1 * time.Duration(rand.Intn(1000000)) * time.Second), + } + + return conversation +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ab8e074 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module code.severnaya.net/kordophone-mock/v2 + +go 1.17 + +require github.com/google/uuid v1.3.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3dfe1c9 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/main.go b/main.go new file mode 100644 index 0000000..e5d7f82 --- /dev/null +++ b/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "log" + "net/http" + + "code.severnaya.net/kordophone-mock/v2/web" +) + +func main() { + log.Println("Initializing") + + s := web.NewMockHTTPServer() + httpServer := &http.Server{ + Addr: ":5738", + Handler: s, + } + + // Populate with test data + s.Server.PopulateWithTestData() + + log.Fatal(httpServer.ListenAndServe()) +} diff --git a/model/conversation.go b/model/conversation.go new file mode 100644 index 0000000..035ab35 --- /dev/null +++ b/model/conversation.go @@ -0,0 +1,11 @@ +package model + +import "time" + +type Conversation struct { + Date time.Time `json:"date"` + Participants []string `json:"participantDisplayNames"` + UnreadCount int `json:"unreadCount"` + LastMessagePreview string `json:"lastMessagePreview"` + Guid string `json:"guid"` +} diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..e401e21 --- /dev/null +++ b/server/server.go @@ -0,0 +1,40 @@ +package server + +import ( + "code.severnaya.net/kordophone-mock/v2/data" + "code.severnaya.net/kordophone-mock/v2/model" +) + +type Server struct { + version string + conversations []model.Conversation +} + +func NewServer() *Server { + return &Server{ + version: "1.0", + conversations: []model.Conversation{}, + } +} + +func (s *Server) Version() string { + return s.version +} + +func (s *Server) Conversations() []model.Conversation { + return s.conversations +} + +func (s *Server) AddConversation(c model.Conversation) { + s.conversations = append(s.conversations, c) +} + +func (s *Server) PopulateWithTestData() { + numConversations := 100 + cs := make([]model.Conversation, numConversations) + for i := 0; i < numConversations; i++ { + cs[i] = data.GenerateRandomConversation() + } + + s.conversations = cs +} diff --git a/web/server.go b/web/server.go new file mode 100644 index 0000000..5bacb8f --- /dev/null +++ b/web/server.go @@ -0,0 +1,56 @@ +package web + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + + "code.severnaya.net/kordophone-mock/v2/server" +) + +type MockHTTPServer struct { + Server server.Server + mux http.ServeMux +} + +func (m *MockHTTPServer) handleVersion(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "%s", m.Server.Version()) +} + +func (m *MockHTTPServer) handleStatus(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "OK") +} + +func (m *MockHTTPServer) handleConversations(w http.ResponseWriter, r *http.Request) { + convos := m.Server.Conversations() + + // Encode convos as JSON + jsonData, err := json.Marshal(convos) + if err != nil { + log.Printf("Error marshalling conversations: %s", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Write JSON to response + w.Header().Set("Content-Type", "application/json") + w.Write(jsonData) +} + +func (m *MockHTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + m.mux.ServeHTTP(w, r) +} + +func NewMockHTTPServer() *MockHTTPServer { + this := MockHTTPServer{ + Server: *server.NewServer(), + mux: *http.NewServeMux(), + } + + this.mux.Handle("/version", http.HandlerFunc(this.handleVersion)) + this.mux.Handle("/conversations", http.HandlerFunc(this.handleConversations)) + this.mux.Handle("/status", http.HandlerFunc(this.handleStatus)) + + return &this +} diff --git a/web/server_test.go b/web/server_test.go new file mode 100644 index 0000000..03e7167 --- /dev/null +++ b/web/server_test.go @@ -0,0 +1,106 @@ +package web_test + +import ( + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "testing" + "time" + + "code.severnaya.net/kordophone-mock/v2/model" + "code.severnaya.net/kordophone-mock/v2/web" +) + +func TestVersion(t *testing.T) { + s := httptest.NewServer(web.NewMockHTTPServer()) + + resp, err := http.Get(s.URL + "/version") + if err != nil { + t.Fatalf("TestVersion error: %s", err) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatalf("Error decoding body: %s", body) + } + + if string(body) != "1.0" { + t.Fatalf("Unexpected return value: %s (expected %s)", body, "1.0") + } +} + +func TestStatus(t *testing.T) { + s := httptest.NewServer(web.NewMockHTTPServer()) + + resp, err := http.Get(s.URL + "/status") + if err != nil { + t.Fatalf("TestStatus error: %s", err) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatalf("Error decoding body: %s", body) + } + + if string(body) != "OK" { + t.Fatalf("Unexpected return value: %s (expected %s)", body, "OK") + } +} + +func TestConversations(t *testing.T) { + server := web.NewMockHTTPServer() + httpServer := httptest.NewServer(server) + + conversation := model.Conversation{ + Date: time.Now(), + Participants: []string{"Alice", "Bob"}, + UnreadCount: 1, + LastMessagePreview: "Hello world", + Guid: "1234567890", + } + + server.Server.AddConversation(conversation) + + resp, err := http.Get(httpServer.URL + "/conversations") + if err != nil { + t.Fatalf("TestConversations error: %s", err) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatalf("Error decoding body: %s", body) + } + + var convos []model.Conversation + err = json.Unmarshal(body, &convos) + if err != nil { + t.Fatalf("Error unmarshalling JSON: %s", err) + } + + if len(convos) != 1 { + t.Fatalf("Unexpected number of conversations: %d (expected %d)", len(convos), 1) + } + + if convos[0].Guid != conversation.Guid { + t.Fatalf("Unexpected conversation GUID: %s (expected %s)", convos[0].Guid, conversation.Guid) + } + + if convos[0].LastMessagePreview != conversation.LastMessagePreview { + t.Fatalf("Unexpected conversation LastMessagePreview: %s (expected %s)", convos[0].LastMessagePreview, conversation.LastMessagePreview) + } + + if convos[0].UnreadCount != conversation.UnreadCount { + t.Fatalf("Unexpected conversation UnreadCount: %d (expected %d)", convos[0].UnreadCount, conversation.UnreadCount) + } + + for i, p := range convos[0].Participants { + if p != conversation.Participants[i] { + t.Fatalf("Unexpected conversation Participants: %s (expected %s)", p, conversation.Participants[i]) + } + } + + if !convos[0].Date.Equal(conversation.Date) { + t.Fatalf("Unexpected conversation Date: %s (expected %s)", convos[0].Date, conversation.Date) + } +}