diff --git a/coolfacts/cmd/coolfacts_server/main.go b/coolfacts/cmd/coolfacts_server/main.go index 1dade50..13d8ca4 100644 --- a/coolfacts/cmd/coolfacts_server/main.go +++ b/coolfacts/cmd/coolfacts_server/main.go @@ -4,12 +4,17 @@ import ( "fmt" "log" "net/http" + + "github.com/FTBpro/go-workshop/coolfacts/coolfact" + "github.com/FTBpro/go-workshop/coolfacts/inmem" ) func main() { fmt.Println("Hello, Server!") - server := NewServer() + factsRepo := inmem.NewFactsRepository(seedFacts()...) + service := coolfact.NewService(factsRepo) + server := NewServer(service) log.Println("starting server on port 9002") log.Println("You can go to http://127.0.0.1:9002/ping") @@ -17,3 +22,16 @@ func main() { panic(fmt.Errorf("server crashed! err: %w", err)) } } + +func seedFacts() []coolfact.Fact { + return []coolfact.Fact{ + { + Topic: "Games", + Description: "Did you know sonic is a hedgehog?!", + }, + { + Topic: "TV", + Description: "You won't believe what happened to Arya!", + }, + } +} diff --git a/coolfacts/cmd/coolfacts_server/server.go b/coolfacts/cmd/coolfacts_server/server.go index cc2c9bd..29cb62b 100644 --- a/coolfacts/cmd/coolfacts_server/server.go +++ b/coolfacts/cmd/coolfacts_server/server.go @@ -8,15 +8,24 @@ import ( "strings" ) -type server struct{} +type FactsService interface { + // TODO: add methods declerations + // 1. getFacts - returns a slice of fact.Fact and an error +} + +type server struct { + // TODO: add factsService field +} func NewServer() *server { + // TODO: returns an initializes server with the factsService return &server{} } func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { log.Println("incoming request", r.Method, r.URL.Path) + // TODO: add case for GET /facts, that will call to `HandleGetFacts` switch r.Method { case http.MethodGet: switch strings.ToLower(r.URL.Path) { @@ -41,6 +50,30 @@ func (s *server) HandlePing(w http.ResponseWriter, _ *http.Request) { } } +func (s *server) HandleGetFacts(w http.ResponseWriter, _ *http.Request) { + log.Println("Handling getFact ...") + + facts, err := s.factsService.GetFacts() + if err != nil { + s.HandleError(w, fmt.Errorf("server.GetFactsHandler: %w", err)) + return + } + + // TODO: + // 1. format the facts to a json response + // 2. write status 200 + // 3. set content type application/json + // 4. write json response: + // { + // "facts": [ + // { + // "id": "..." + // "description": "..." + // }, + // ... + // ] +} + func (s *server) HandleNotFound(w http.ResponseWriter, r *http.Request) { log.Println("Handling notFound ...") diff --git a/coolfacts/coolfact/fact.go b/coolfacts/coolfact/fact.go new file mode 100644 index 0000000..51a28ad --- /dev/null +++ b/coolfacts/coolfact/fact.go @@ -0,0 +1,5 @@ +package coolfact + +type Fact struct { + // TODO: add fields for the entity fact: topic and description (strings) +} diff --git a/coolfacts/coolfact/service.go b/coolfacts/coolfact/service.go new file mode 100644 index 0000000..389c309 --- /dev/null +++ b/coolfacts/coolfact/service.go @@ -0,0 +1,18 @@ +package coolfact + +type Repository interface { + // TODO: add functions decleration + // - getFacts. Returns a slice of Fact and an error +} + +type service struct { + // TODO: add field factsRepo +} + +func NewService(factsRepo Repository) *service { + // TODO: init a new service with factsRepo +} + +func (s *service) GetFacts() ([]Fact, error) { + // TODO: implement getFacts, using the factsRepo +} diff --git a/coolfacts/coolfact/service_test.go b/coolfacts/coolfact/service_test.go new file mode 100644 index 0000000..b1bd197 --- /dev/null +++ b/coolfacts/coolfact/service_test.go @@ -0,0 +1,98 @@ +package coolfact_test + +import ( + "fmt" + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/FTBpro/go-workshop/coolfacts/coolfact" + "github.com/FTBpro/go-workshop/coolfacts/inmem" +) + +func Test_service_GetFacts(t *testing.T) { + facts := generateRandomFactsDesc(10) + + testCases := []struct { + name string + repoField coolfact.Repository + want []coolfact.Fact + wantErr bool + }{ + { + name: "with facts", + repoField: inmem.NewFactsRepository(facts...), + want: facts, + wantErr: false, + }, + { + name: "no facts - should get nil", + repoField: inmem.NewFactsRepository(), + want: nil, + wantErr: false, + }, + { + name: "repo returns error", + repoField: mockRepoError{}, + want: nil, + wantErr: true, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + s := coolfact.NewService(tc.repoField) + got, err := s.GetFacts() + if err != nil { + require.True(t, tc.wantErr, "got an unexpected error from service") + return + } + + require.False(t, tc.wantErr, "expected an error but didn't receive one.") + expectEqualFacts(t, tc.want, got) + }) + } +} + +// generateRandomFactsDesc creates new random facts sorted by DESC +func generateRandomFactsDesc(n int) []coolfact.Fact { + var facts []coolfact.Fact + for i := 0; i < n; i++ { + fact := randomFact() + facts = append(facts, fact) + } + + return facts +} + +func randomFact() coolfact.Fact { + rand.Seed(time.Now().UnixNano()) + return coolfact.Fact{ + Topic: fmt.Sprintf("Topic %d", rand.Intn(10000)), + Description: fmt.Sprintf("Some Description %d", rand.Intn(10000)), + } +} + +func expectEqualFacts(t *testing.T, expected, got []coolfact.Fact) { + require.Equalf(t, len(expected), len(got), "expectEqualFacts: different length") + + for _, fact := range got { + require.Contains(t, expected, fact, "expectEqualFacts: got unexpected fact") + } + + for _, fact := range expected { + require.Contains(t, got, fact, "expectEqualFacts: didn't got expected fact") + } +} + +type mockRepoError struct { +} + +func (m mockRepoError) GetFacts() ([]coolfact.Fact, error) { + return nil, fmt.Errorf("mock repo returns error") +} + +func (m mockRepoError) CreateFact(fact coolfact.Fact) error { + return fmt.Errorf("mock repo returns error") +} diff --git a/coolfacts/go.mod b/coolfacts/go.mod index b1dd8ae..479e548 100644 --- a/coolfacts/go.mod +++ b/coolfacts/go.mod @@ -1,3 +1,11 @@ module github.com/FTBpro/go-workshop/coolfacts go 1.18 + +require github.com/stretchr/testify v1.8.1 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/coolfacts/go.sum b/coolfacts/go.sum new file mode 100644 index 0000000..2ec90f7 --- /dev/null +++ b/coolfacts/go.sum @@ -0,0 +1,17 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/coolfacts/inmem/factsrepo.go b/coolfacts/inmem/factsrepo.go new file mode 100644 index 0000000..46e3c3c --- /dev/null +++ b/coolfacts/inmem/factsrepo.go @@ -0,0 +1,17 @@ +package inmem + +import ( + "github.com/FTBpro/go-workshop/coolfacts/coolfact" +) + +type factsRepo struct { + facts []coolfact.Fact +} + +func NewFactsRepository(facts ...coolfact.Fact) *factsRepo { + // TODO: init facts repo +} + +func (r *factsRepo) GetFacts() ([]coolfact.Fact, error) { + // TODO: implement +}