From 079dc940a36e1f5048f0035dfc952db5b3299eff Mon Sep 17 00:00:00 2001 From: Ambrose Chua Date: Sat, 28 Sep 2019 23:01:36 +0800 Subject: [PATCH] More tests and test tools --- Makefile | 34 +++++++++++++++ contact.go | 2 +- contact_test.go | 88 +++++++++++++++++++++++++++++++++++++++ conversation.go | 2 +- go.mod | 2 + postgres/1_initial.up.sql | 2 +- scripts/testutils.go | 59 ++++++++++++++++++++++++++ types.go | 16 +++---- user.go | 13 ------ user_test.go | 8 ++-- 10 files changed, 199 insertions(+), 27 deletions(-) create mode 100644 Makefile create mode 100644 contact_test.go create mode 100644 scripts/testutils.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b63e37b --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +GOCMD=go +GORUN=$(GOCMD) run +GOBUILD=$(GOCMD) build +GOCLEAN=$(GOCMD) clean +GOTEST=$(GOCMD) test +DOCKERCOMPOSE=docker-compose + + +BINARY_NAME=core + +DOCKERCOMPOSE_INTEGRATION_CONFIG=docker-compose.integration.yml + + +all: test_unit build + +build: + $(GOBUILD) -o $(BINARY_NAME) -v + +test: test_unit test_integration + +test_unit: + $(GOTEST) -tags=unit -v -cover + +test_integration: test_integration_prepare + $(GOTEST) -tags=integration -v -cover +test_integration_prepare: + $(GORUN) scripts/testutils.go isrunning || $(DOCKERCOMPOSE) -f $(DOCKERCOMPOSE_INTEGRATION_CONFIG) up -d + $(GORUN) scripts/testutils.go wait +test_integration_cleanup: + $(DOCKERCOMPOSE) -f $(DOCKERCOMPOSE_INTEGRATION_CONFIG) down + +clean: + $(GOCLEAN) + rm -f $(BINARY_NAME) diff --git a/contact.go b/contact.go index 9e4a4d5..0e35363 100644 --- a/contact.go +++ b/contact.go @@ -88,7 +88,7 @@ func (h *Handler) GetContacts(w http.ResponseWriter, r *http.Request, p httprout log.Print(err) return } - contacts = append(contacts, User{id, username, bio, profilePic, firstName, lastName, phone}) + contacts = append(contacts, User{id, &username, bio, profilePic, firstName, lastName, phone}) } // Respond diff --git a/contact_test.go b/contact_test.go new file mode 100644 index 0000000..2ebc6de --- /dev/null +++ b/contact_test.go @@ -0,0 +1,88 @@ +// +build integration + +package main + +import ( + "bytes" + "database/sql" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + // "github.com/google/go-cmp/cmp" +) + +func TestContact(t *testing.T) { + db := connect() + defer db.Close() + h := NewHandler(db) + r := NewRouter(h) + + setupUsers(t, db, r) + + t.Run("Create", testCreateContact(db, r)) +} + +func setupUsers(t *testing.T, db *sql.DB, router http.Handler) { + + users := []User{ + User{ + PhoneNumber: "+65 9999 0001", + FirstName: "Contact 1", + LastName: "User", + }, + User{ + PhoneNumber: "+65 9999 0002", + FirstName: "Contact 2", + LastName: "User", + }, + User{ + PhoneNumber: "+65 9999 0003", + FirstName: "Contact 3", + LastName: "User", + }, + } + + for _, user := range users { + b, _ := json.Marshal(user) + w := httptest.NewRecorder() + r := httptest.NewRequest("POST", "/user", bytes.NewBuffer(b)) + + router.ServeHTTP(w, r) + assertCode(t, w, 200) + } + +} + +func testCreateContact(db *sql.DB, router http.Handler) func(t *testing.T) { + return func(t *testing.T) { + + /* + // Setup + mockUser := &User{ + PhoneNumber: "+65 99999999", + FirstName: "Test", + LastName: "User 1", + } + b, _ := json.Marshal(mockUser) + + // Test + w := httptest.NewRecorder() + r := httptest.NewRequest("POST", "/user", bytes.NewBuffer(b)) + + router.ServeHTTP(w, r) + assertCode(t, w, 200) + + // Assert + got, want := new(User), mockUser + wantPhone, _ := ParsePhone(want.PhoneNumber) + json.NewDecoder(w.Body).Decode(got) + if got.FirstName != want.FirstName || got.LastName != want.LastName || got.PhoneNumber != wantPhone { + t.Error("Wanted a User with same FirstName, LastName, PhoneNumber. Got something else") + } + + assertDB(t, db, `SELECT * FROM "user" WHERE phone_number = '+65 9999 9999' AND first_name = 'Test' AND last_name = 'User 1'`) + */ + + } +} diff --git a/conversation.go b/conversation.go index b525ecb..d7093d5 100644 --- a/conversation.go +++ b/conversation.go @@ -367,7 +367,7 @@ func (h *Handler) GetConversationMembers(w http.ResponseWriter, r *http.Request, log.Print(err) return } - users = append(users, User{ID: id, Username: username, Bio: bio, ProfilePic: profilePic, FirstName: firstName, LastName: lastName, PhoneNumber: phoneNumber}) + users = append(users, User{ID: id, Username: &username, Bio: bio, ProfilePic: profilePic, FirstName: firstName, LastName: lastName, PhoneNumber: phoneNumber}) } // Respond diff --git a/go.mod b/go.mod index 8a9832b..ba5dd0c 100644 --- a/go.mod +++ b/go.mod @@ -10,3 +10,5 @@ require ( github.com/ttacon/libphonenumber v1.0.0 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect ) + +go 1.13 diff --git a/postgres/1_initial.up.sql b/postgres/1_initial.up.sql index 2e7410c..4d80275 100644 --- a/postgres/1_initial.up.sql +++ b/postgres/1_initial.up.sql @@ -1,7 +1,7 @@ CREATE TABLE IF NOT EXISTS "user" ( id BYTEA PRIMARY KEY, - username VARCHAR(63555), + username VARCHAR(63555) UNIQUE, bio VARCHAR(63535) DEFAULT '', profile_pic VARCHAR(63535) DEFAULT '', first_name VARCHAR(65535) DEFAULT '', diff --git a/scripts/testutils.go b/scripts/testutils.go new file mode 100644 index 0000000..5eb3627 --- /dev/null +++ b/scripts/testutils.go @@ -0,0 +1,59 @@ +package main + +import ( + "database/sql" + "flag" + "log" + "os" + "time" + + "github.com/joho/godotenv" + _ "github.com/lib/pq" +) + +func init() { + // Load .env + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } +} + +func main() { + flag.Parse() + + exit := 1 + if flag.Arg(0) == "isrunning" { + exit = isrunning() + } else if flag.Arg(0) == "wait" { + exit = wait() + } else { + log.Print("No command specified") + } + os.Exit(exit) +} + +func isrunning() int { + db, err := sql.Open("postgres", os.Getenv("POSTGRES")) + if err != nil { + return 1 + } + defer db.Close() + err = db.Ping() + if err != nil { + return 1 + } + return 0 +} + +func wait() int { + for i := 0; i < 60; i += 1 { + timer := time.NewTimer(1 * time.Second) + if isrunning() == 0 { + return 0 + } + <-timer.C + } + log.Print("Timed out trying to connect to postgres") + return 1 +} diff --git a/types.go b/types.go index 970eaac..59773f3 100644 --- a/types.go +++ b/types.go @@ -1,5 +1,7 @@ package main +// String pointer means nullable + type Conversation struct { ID string `json:"id"` // id Title string `json:"title"` // title @@ -9,13 +11,13 @@ type Conversation struct { } type User struct { - ID string `json:"id"` // id - Username string `json:"username"` // username - Bio string `json:"bio"` // bio - ProfilePic string `json:"profile_pic"` // profile_pic - FirstName string `json:"first_name"` // first_name - LastName string `json:"last_name"` // last_name - PhoneNumber string `json:"phone_number"` // phone_number + ID string `json:"id"` // id + Username *string `json:"username"` // username + Bio string `json:"bio"` // bio + ProfilePic string `json:"profile_pic"` // profile_pic + FirstName string `json:"first_name"` // first_name + LastName string `json:"last_name"` // last_name + PhoneNumber string `json:"phone_number"` // phone_number } type PhoneNumber struct { diff --git a/user.go b/user.go index b084132..647c460 100644 --- a/user.go +++ b/user.go @@ -149,19 +149,6 @@ func (h *Handler) UpdateUser(w http.ResponseWriter, r *http.Request, p httproute return } - // Check for duplicate username - var _id string - err = h.db.QueryRow(` - SELECT id FROM "user" WHERE "user".id <> $1 AND "user".username = $2 - `, userID, user.Username).Scan(&_id) - if err == nil { - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return - } else if err != sql.ErrNoRows { - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) - return - } - // Update _, err = h.db.Exec(` UPDATE "user" diff --git a/user_test.go b/user_test.go index 4d1603d..62802dd 100644 --- a/user_test.go +++ b/user_test.go @@ -28,7 +28,7 @@ func testCreateUser(db *sql.DB, router http.Handler) func(t *testing.T) { return func(t *testing.T) { // Setup - mockUser := &User{ + mockUser := User{ PhoneNumber: "+65 99999999", FirstName: "Test", LastName: "User 1", @@ -59,7 +59,7 @@ func testGetUserByPhone(db *sql.DB, router http.Handler) func(t *testing.T) { return func(t *testing.T) { // Setup - mockUser := &User{ + mockUser := User{ PhoneNumber: "+65 99999998", FirstName: "Test", LastName: "User 2", @@ -94,7 +94,7 @@ func testGetUser(db *sql.DB, router http.Handler) func(t *testing.T) { return func(t *testing.T) { // Setup - mockUser := &User{ + mockUser := User{ PhoneNumber: "+65 99999997", FirstName: "User", LastName: "Test 2", @@ -129,7 +129,7 @@ func testUpdateUser(db *sql.DB, router http.Handler) func(t *testing.T) { return func(t *testing.T) { // Setup - mockUser := &User{ + mockUser := User{ PhoneNumber: "+65 99999996", FirstName: "User", LastName: "Test 3",