Fix conversations, add integration tests
continuous-integration/drone/pr Build is passing
Details
continuous-integration/drone/pr Build is passing
Details
parent
f03de17d64
commit
d7a27e5c52
|
@ -19,13 +19,13 @@ func TestContact(t *testing.T) {
|
|||
h := NewHandler(db, nil)
|
||||
r := NewRouter(h)
|
||||
|
||||
users := setupUsers(t, db, r)
|
||||
users := setupContactUsers(t, db, r)
|
||||
|
||||
t.Run("Create", testCreateContact(db, r, users))
|
||||
t.Run("Get", testGetContacts(db, r, users))
|
||||
}
|
||||
|
||||
func setupUsers(t *testing.T, db *sql.DB, router http.Handler) []User {
|
||||
func setupContactUsers(t *testing.T, db *sql.DB, router http.Handler) []User {
|
||||
|
||||
users := []User{
|
||||
User{
|
||||
|
|
|
@ -104,13 +104,13 @@ func (h *Handler) GetConversations(w http.ResponseWriter, r *http.Request, p htt
|
|||
|
||||
// Scan
|
||||
for rows.Next() {
|
||||
var id, title, picture string
|
||||
if err := rows.Scan(&id, &title, &picture); err != nil {
|
||||
conversation := Conversation{}
|
||||
if err := rows.Scan(&conversation.ID, &conversation.Title, &conversation.Picture, &conversation.Pinned); err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
conversations = append(conversations, Conversation{ID: id, Title: title, DM: false, Picture: picture})
|
||||
conversations = append(conversations, conversation)
|
||||
}
|
||||
|
||||
// Respond
|
||||
|
@ -136,7 +136,7 @@ func (h *Handler) GetConversation(w http.ResponseWriter, r *http.Request, p http
|
|||
member.pinned
|
||||
FROM "conversation", member
|
||||
WHERE member.conversation = "conversation".id AND member.user = $1 AND member.conversation = $2
|
||||
`, userID, conversationID).Scan(&conversation.ID, &conversation.Title, &conversation.Picture)
|
||||
`, userID, conversationID).Scan(&conversation.ID, &conversation.Title, &conversation.Picture, &conversation.Pinned)
|
||||
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
|
@ -183,7 +183,7 @@ func (h *Handler) UpdateConversation(w http.ResponseWriter, r *http.Request, p h
|
|||
}
|
||||
|
||||
// Update
|
||||
if len(conversation.Title) > 0 {
|
||||
if conversation.Title.Valid {
|
||||
_, err = h.db.Exec(`
|
||||
UPDATE "conversation"
|
||||
SET title = $2, picture = $3
|
||||
|
@ -429,13 +429,13 @@ func (h *Handler) GetConversationMembers(w http.ResponseWriter, r *http.Request,
|
|||
|
||||
// Scan
|
||||
for rows.Next() {
|
||||
var id, username, bio, profilePic, firstName, lastName, phoneNumber string
|
||||
if err := rows.Scan(&id, &username, &bio, &profilePic, &firstName, &lastName, &phoneNumber); err != nil {
|
||||
user := User{}
|
||||
if err := rows.Scan(&user.ID, &user.Username, &user.Bio, &user.ProfilePic, &user.FirstName, &user.LastName, &user.PhoneNumber); err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
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)
|
||||
}
|
||||
|
||||
// Respond
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"gopkg.in/guregu/null.v3"
|
||||
)
|
||||
|
||||
func TestConversation(t *testing.T) {
|
||||
|
@ -19,13 +20,13 @@ func TestConversation(t *testing.T) {
|
|||
h := NewHandler(db, nil)
|
||||
r := NewRouter(h)
|
||||
|
||||
users := setupUsers(t, db, r)
|
||||
users := setupConversationUsers(t, db, r)
|
||||
|
||||
t.Run("Create", testCreateConversation(db, r, users))
|
||||
t.Run("Get", testGetConversations(db, r, users))
|
||||
}
|
||||
|
||||
func setupUsers(t *testing.T, db *sql.DB, router http.Handler) []User {
|
||||
func setupConversationUsers(t *testing.T, db *sql.DB, router http.Handler) []User {
|
||||
|
||||
users := []User{
|
||||
User{
|
||||
|
@ -68,31 +69,30 @@ func setupUsers(t *testing.T, db *sql.DB, router http.Handler) []User {
|
|||
func testCreateConversation(db *sql.DB, router http.Handler, users []User) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
|
||||
// Setup
|
||||
|
||||
// Test
|
||||
mockConversation := &Conversation{
|
||||
Title: "Test Conversation 1",
|
||||
DM: true,
|
||||
Title: null.StringFrom("Test Conversation 1"),
|
||||
DM: false,
|
||||
}
|
||||
b, _ := json.Marshal(mockConversation)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("POST", "/user/conversation", bytes.NewBuffer(b))
|
||||
claim, _ := json.Marshal(&RawClient{UserId: createdUser.ID, ClientId: "test"})
|
||||
claim, _ := json.Marshal(&RawClient{UserId: users[0].ID, ClientId: "test"})
|
||||
r.Header.Add("X-User-Claim", string(claim))
|
||||
|
||||
router.ServeHTTP(w, r)
|
||||
assertCode(t, w, 200)
|
||||
|
||||
// Assert
|
||||
got, want := User{}, users[0]
|
||||
got, want := &Conversation{}, mockConversation
|
||||
json.NewDecoder(w.Body).Decode(&got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Error(diff)
|
||||
if got.DM != want.DM || got.Title.String != want.Title.String {
|
||||
t.Error("Wanted a Conversation with same Title, DM. Got something else")
|
||||
}
|
||||
|
||||
assertDB(t, db, `SELECT * FROM contact WHERE "user" = $1 AND contact = $2`, createdUser.ID, users[0].ID)
|
||||
assertDB(t, db, `SELECT * FROM "conversation" WHERE title = $1 AND dm = $2`, mockConversation.Title, mockConversation.DM)
|
||||
assertDB(t, db, `SELECT * FROM member WHERE "user" = $1 AND "conversation" = $2`, users[0].ID, got.ID)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -101,59 +101,34 @@ func testGetConversations(db *sql.DB, router http.Handler, users []User) func(t
|
|||
return func(t *testing.T) {
|
||||
|
||||
// Setup
|
||||
mockUser := &User{
|
||||
PhoneNumber: "+65 9999 1002",
|
||||
FirstName: "ConversationOwner",
|
||||
LastName: "User",
|
||||
mockConversation := &Conversation{
|
||||
Title: null.StringFrom("Test Conversation 2"),
|
||||
DM: false,
|
||||
}
|
||||
bs, _ := json.Marshal(mockUser)
|
||||
bs, _ := json.Marshal(mockConversation)
|
||||
|
||||
ws := httptest.NewRecorder()
|
||||
rs := httptest.NewRequest("POST", "/user", bytes.NewBuffer(bs))
|
||||
rs := httptest.NewRequest("POST", "/user/conversation", bytes.NewBuffer(bs))
|
||||
claims, _ := json.Marshal(&RawClient{UserId: users[1].ID, ClientId: "test"})
|
||||
rs.Header.Add("X-User-Claim", string(claims))
|
||||
|
||||
router.ServeHTTP(ws, rs)
|
||||
|
||||
createdUser := new(User)
|
||||
json.NewDecoder(ws.Body).Decode(createdUser)
|
||||
|
||||
b := []byte(`{"phone_number": "` + users[0].PhoneNumber + `"}`)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("POST", "/user/contact", bytes.NewBuffer(b))
|
||||
claim, _ := json.Marshal(&RawClient{UserId: createdUser.ID, ClientId: "test"})
|
||||
r.Header.Add("X-User-Claim", string(claim))
|
||||
|
||||
router.ServeHTTP(w, r)
|
||||
assertCode(t, w, 200)
|
||||
|
||||
b = []byte(`{"phone_number": "` + users[1].PhoneNumber + `"}`)
|
||||
|
||||
w = httptest.NewRecorder()
|
||||
r = httptest.NewRequest("POST", "/user/contact", bytes.NewBuffer(b))
|
||||
r.Header.Add("X-User-Claim", string(claim))
|
||||
|
||||
router.ServeHTTP(w, r)
|
||||
assertCode(t, w, 200)
|
||||
|
||||
b = []byte(`{"phone_number": "` + users[2].PhoneNumber + `"}`)
|
||||
|
||||
w = httptest.NewRecorder()
|
||||
r = httptest.NewRequest("POST", "/user/contact", bytes.NewBuffer(b))
|
||||
r.Header.Add("X-User-Claim", string(claim))
|
||||
|
||||
router.ServeHTTP(w, r)
|
||||
assertCode(t, w, 200)
|
||||
assertCode(t, ws, 200)
|
||||
|
||||
// Test
|
||||
w = httptest.NewRecorder()
|
||||
r = httptest.NewRequest("GET", "/user/contact", nil)
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/user/conversation", nil)
|
||||
claim, _ := json.Marshal(&RawClient{UserId: users[1].ID, ClientId: "test"})
|
||||
r.Header.Add("X-User-Claim", string(claim))
|
||||
|
||||
router.ServeHTTP(w, r)
|
||||
assertCode(t, w, 200)
|
||||
conversations := make([]Conversation, 1)
|
||||
json.NewDecoder(w.Body).Decode(&conversations)
|
||||
|
||||
// Assert
|
||||
got, want := []User{}, users
|
||||
json.NewDecoder(w.Body).Decode(&got)
|
||||
got, want := conversations[0], Conversation{}
|
||||
json.NewDecoder(ws.Body).Decode(&want)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Error(diff)
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -12,6 +12,7 @@ require (
|
|||
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect
|
||||
github.com/ttacon/libphonenumber v1.0.0
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
|
||||
gopkg.in/guregu/null.v3 v3.4.0
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
|
2
go.sum
2
go.sum
|
@ -27,3 +27,5 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/guregu/null.v3 v3.4.0 h1:AOpMtZ85uElRhQjEDsFx21BkXqFPwA7uoJukd4KErIs=
|
||||
gopkg.in/guregu/null.v3 v3.4.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y=
|
||||
|
|
26
types.go
26
types.go
|
@ -1,6 +1,6 @@
|
|||
package main
|
||||
|
||||
// String pointer means nullable
|
||||
import "gopkg.in/guregu/null.v3"
|
||||
|
||||
type UpdateMsg struct {
|
||||
Type string `json:"type"`
|
||||
|
@ -19,21 +19,21 @@ type Member struct {
|
|||
}
|
||||
|
||||
type Conversation struct {
|
||||
ID string `json:"id"` // id
|
||||
Title string `json:"title"` // title
|
||||
DM bool `json:"dm"` // dm
|
||||
Picture string `json:"picture"` // picture
|
||||
Pinned bool `json:"pinned"` // pinned
|
||||
ID string `json:"id"` // id
|
||||
Title null.String `json:"title"` // title
|
||||
DM bool `json:"dm"` // dm
|
||||
Picture null.String `json:"picture"` // picture
|
||||
Pinned bool `json:"pinned"` // pinned
|
||||
}
|
||||
|
||||
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 null.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 {
|
||||
|
|
Loading…
Reference in New Issue