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)
|
h := NewHandler(db, nil)
|
||||||
r := NewRouter(h)
|
r := NewRouter(h)
|
||||||
|
|
||||||
users := setupUsers(t, db, r)
|
users := setupContactUsers(t, db, r)
|
||||||
|
|
||||||
t.Run("Create", testCreateContact(db, r, users))
|
t.Run("Create", testCreateContact(db, r, users))
|
||||||
t.Run("Get", testGetContacts(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{
|
users := []User{
|
||||||
User{
|
User{
|
||||||
|
|
|
@ -104,13 +104,13 @@ func (h *Handler) GetConversations(w http.ResponseWriter, r *http.Request, p htt
|
||||||
|
|
||||||
// Scan
|
// Scan
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var id, title, picture string
|
conversation := Conversation{}
|
||||||
if err := rows.Scan(&id, &title, &picture); err != nil {
|
if err := rows.Scan(&conversation.ID, &conversation.Title, &conversation.Picture, &conversation.Pinned); err != nil {
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conversations = append(conversations, Conversation{ID: id, Title: title, DM: false, Picture: picture})
|
conversations = append(conversations, conversation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond
|
// Respond
|
||||||
|
@ -136,7 +136,7 @@ func (h *Handler) GetConversation(w http.ResponseWriter, r *http.Request, p http
|
||||||
member.pinned
|
member.pinned
|
||||||
FROM "conversation", member
|
FROM "conversation", member
|
||||||
WHERE member.conversation = "conversation".id AND member.user = $1 AND member.conversation = $2
|
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 {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
|
@ -183,7 +183,7 @@ func (h *Handler) UpdateConversation(w http.ResponseWriter, r *http.Request, p h
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
if len(conversation.Title) > 0 {
|
if conversation.Title.Valid {
|
||||||
_, err = h.db.Exec(`
|
_, err = h.db.Exec(`
|
||||||
UPDATE "conversation"
|
UPDATE "conversation"
|
||||||
SET title = $2, picture = $3
|
SET title = $2, picture = $3
|
||||||
|
@ -429,13 +429,13 @@ func (h *Handler) GetConversationMembers(w http.ResponseWriter, r *http.Request,
|
||||||
|
|
||||||
// Scan
|
// Scan
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var id, username, bio, profilePic, firstName, lastName, phoneNumber string
|
user := User{}
|
||||||
if err := rows.Scan(&id, &username, &bio, &profilePic, &firstName, &lastName, &phoneNumber); err != nil {
|
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)
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
users = append(users, User{ID: id, Username: &username, Bio: bio, ProfilePic: profilePic, FirstName: firstName, LastName: lastName, PhoneNumber: phoneNumber})
|
users = append(users, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond
|
// Respond
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"gopkg.in/guregu/null.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConversation(t *testing.T) {
|
func TestConversation(t *testing.T) {
|
||||||
|
@ -19,13 +20,13 @@ func TestConversation(t *testing.T) {
|
||||||
h := NewHandler(db, nil)
|
h := NewHandler(db, nil)
|
||||||
r := NewRouter(h)
|
r := NewRouter(h)
|
||||||
|
|
||||||
users := setupUsers(t, db, r)
|
users := setupConversationUsers(t, db, r)
|
||||||
|
|
||||||
t.Run("Create", testCreateConversation(db, r, users))
|
t.Run("Create", testCreateConversation(db, r, users))
|
||||||
t.Run("Get", testGetConversations(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{
|
users := []User{
|
||||||
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) {
|
func testCreateConversation(db *sql.DB, router http.Handler, users []User) func(t *testing.T) {
|
||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
|
|
||||||
// Setup
|
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mockConversation := &Conversation{
|
mockConversation := &Conversation{
|
||||||
Title: "Test Conversation 1",
|
Title: null.StringFrom("Test Conversation 1"),
|
||||||
DM: true,
|
DM: false,
|
||||||
}
|
}
|
||||||
b, _ := json.Marshal(mockConversation)
|
b, _ := json.Marshal(mockConversation)
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
r := httptest.NewRequest("POST", "/user/conversation", bytes.NewBuffer(b))
|
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))
|
r.Header.Add("X-User-Claim", string(claim))
|
||||||
|
|
||||||
router.ServeHTTP(w, r)
|
router.ServeHTTP(w, r)
|
||||||
assertCode(t, w, 200)
|
assertCode(t, w, 200)
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
got, want := User{}, users[0]
|
got, want := &Conversation{}, mockConversation
|
||||||
json.NewDecoder(w.Body).Decode(&got)
|
json.NewDecoder(w.Body).Decode(&got)
|
||||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
if got.DM != want.DM || got.Title.String != want.Title.String {
|
||||||
t.Error(diff)
|
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) {
|
return func(t *testing.T) {
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
mockUser := &User{
|
mockConversation := &Conversation{
|
||||||
PhoneNumber: "+65 9999 1002",
|
Title: null.StringFrom("Test Conversation 2"),
|
||||||
FirstName: "ConversationOwner",
|
DM: false,
|
||||||
LastName: "User",
|
|
||||||
}
|
}
|
||||||
bs, _ := json.Marshal(mockUser)
|
bs, _ := json.Marshal(mockConversation)
|
||||||
|
|
||||||
ws := httptest.NewRecorder()
|
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)
|
router.ServeHTTP(ws, rs)
|
||||||
|
assertCode(t, ws, 200)
|
||||||
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)
|
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
w = httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
r = httptest.NewRequest("GET", "/user/contact", nil)
|
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))
|
r.Header.Add("X-User-Claim", string(claim))
|
||||||
|
|
||||||
router.ServeHTTP(w, r)
|
router.ServeHTTP(w, r)
|
||||||
assertCode(t, w, 200)
|
assertCode(t, w, 200)
|
||||||
|
conversations := make([]Conversation, 1)
|
||||||
|
json.NewDecoder(w.Body).Decode(&conversations)
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
got, want := []User{}, users
|
got, want := conversations[0], Conversation{}
|
||||||
json.NewDecoder(w.Body).Decode(&got)
|
json.NewDecoder(ws.Body).Decode(&want)
|
||||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||||
t.Error(diff)
|
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/builder v0.0.0-20170518171403-c099f663e1c2 // indirect
|
||||||
github.com/ttacon/libphonenumber v1.0.0
|
github.com/ttacon/libphonenumber v1.0.0
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
|
||||||
|
gopkg.in/guregu/null.v3 v3.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.13
|
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
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=
|
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
|
package main
|
||||||
|
|
||||||
// String pointer means nullable
|
import "gopkg.in/guregu/null.v3"
|
||||||
|
|
||||||
type UpdateMsg struct {
|
type UpdateMsg struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
@ -19,21 +19,21 @@ type Member struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Conversation struct {
|
type Conversation struct {
|
||||||
ID string `json:"id"` // id
|
ID string `json:"id"` // id
|
||||||
Title string `json:"title"` // title
|
Title null.String `json:"title"` // title
|
||||||
DM bool `json:"dm"` // dm
|
DM bool `json:"dm"` // dm
|
||||||
Picture string `json:"picture"` // picture
|
Picture null.String `json:"picture"` // picture
|
||||||
Pinned bool `json:"pinned"` // pinned
|
Pinned bool `json:"pinned"` // pinned
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID string `json:"id"` // id
|
ID string `json:"id"` // id
|
||||||
Username *string `json:"username"` // username
|
Username null.String `json:"username"` // username
|
||||||
Bio string `json:"bio"` // bio
|
Bio string `json:"bio"` // bio
|
||||||
ProfilePic string `json:"profile_pic"` // profile_pic
|
ProfilePic string `json:"profile_pic"` // profile_pic
|
||||||
FirstName string `json:"first_name"` // first_name
|
FirstName string `json:"first_name"` // first_name
|
||||||
LastName string `json:"last_name"` // last_name
|
LastName string `json:"last_name"` // last_name
|
||||||
PhoneNumber string `json:"phone_number"` // phone_number
|
PhoneNumber string `json:"phone_number"` // phone_number
|
||||||
}
|
}
|
||||||
|
|
||||||
type PhoneNumber struct {
|
type PhoneNumber struct {
|
||||||
|
|
Loading…
Reference in New Issue