Browse Source

Add tests for friend list

pull/4/head
Tovi Jaeschke-Rogers 2 years ago
parent
commit
d3553d5955
14 changed files with 471 additions and 121 deletions
  1. +87
    -0
      Backend/Api/Friends/CreateFriendRequest.go
  2. +0
    -41
      Backend/Api/Friends/EncryptedFriendsList.go
  3. +17
    -56
      Backend/Api/Friends/Friends.go
  4. +124
    -0
      Backend/Api/Friends/Friends_test.go
  5. +1
    -5
      Backend/Api/Messages/Conversations.go
  6. +1
    -0
      Backend/Api/Messages/Conversations_test.go
  7. +12
    -1
      Backend/Api/Messages/MessageThread.go
  8. +88
    -0
      Backend/Api/Messages/MessageThread_test.go
  9. +0
    -1
      Backend/Api/Users/SearchUsers.go
  10. +106
    -0
      Backend/Api/Users/SearchUsers_test.go
  11. +7
    -1
      Backend/Database/FriendRequests.go
  12. +7
    -2
      Backend/Database/Messages.go
  13. +2
    -0
      Backend/Models/Friends.go
  14. +19
    -14
      Backend/Tests/Init.go

+ 87
- 0
Backend/Api/Friends/CreateFriendRequest.go View File

@ -0,0 +1,87 @@
package Friends
import (
"encoding/json"
"io/ioutil"
"net/http"
"time"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Models"
)
// CreateFriendRequest creates a FriendRequest from post data
func CreateFriendRequest(w http.ResponseWriter, r *http.Request) {
var (
friendRequest Models.FriendRequest
requestBody []byte
returnJSON []byte
err error
)
requestBody, err = ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
err = json.Unmarshal(requestBody, &friendRequest)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
friendRequest.AcceptedAt.Scan(nil)
err = Database.CreateFriendRequest(&friendRequest)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
returnJSON, err = json.MarshalIndent(friendRequest, "", " ")
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
// Return updated json
w.WriteHeader(http.StatusOK)
w.Write(returnJSON)
}
// CreateFriendRequestQrCode creates a FriendRequest from post data from qr code scan
func CreateFriendRequestQrCode(w http.ResponseWriter, r *http.Request) {
var (
friendRequests []Models.FriendRequest
requestBody []byte
i int
err error
)
requestBody, err = ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
err = json.Unmarshal(requestBody, &friendRequests)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
for i = range friendRequests {
friendRequests[i].AcceptedAt.Time = time.Now()
friendRequests[i].AcceptedAt.Valid = true
}
err = Database.CreateFriendRequests(&friendRequests)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
// Return updated json
w.WriteHeader(http.StatusOK)
}

+ 0
- 41
Backend/Api/Friends/EncryptedFriendsList.go View File

@ -1,41 +0,0 @@
package Friends
import (
"encoding/json"
"net/http"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Api/Auth"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Models"
)
// FriendRequestList gets friend request list
func FriendRequestList(w http.ResponseWriter, r *http.Request) {
var (
userSession Models.Session
friends []Models.FriendRequest
returnJSON []byte
err error
)
userSession, err = Auth.CheckCookie(r)
if err != nil {
http.Error(w, "Forbidden", http.StatusUnauthorized)
return
}
friends, err = Database.GetFriendRequestsByUserID(userSession.UserID.String())
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
returnJSON, err = json.MarshalIndent(friends, "", " ")
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write(returnJSON)
}

+ 17
- 56
Backend/Api/Friends/Friends.go View File

@ -2,86 +2,47 @@ package Friends
import ( import (
"encoding/json" "encoding/json"
"io/ioutil"
"net/http" "net/http"
"time"
"net/url"
"strconv"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Api/Auth"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models"
) )
// CreateFriendRequest creates a FriendRequest from post data
func CreateFriendRequest(w http.ResponseWriter, r *http.Request) {
// FriendRequestList gets friend request list
func FriendRequestList(w http.ResponseWriter, r *http.Request) {
var ( var (
friendRequest Models.FriendRequest
requestBody []byte
returnJSON []byte
err error
userSession Models.Session
friends []Models.FriendRequest
values url.Values
returnJSON []byte
page int
err error
) )
requestBody, err = ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
values = r.URL.Query()
err = json.Unmarshal(requestBody, &friendRequest)
page, err = strconv.Atoi(values.Get("page"))
if err != nil { if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
page = 0
} }
friendRequest.AcceptedAt.Scan(nil)
userSession, _ = Auth.CheckCookie(r)
err = Database.CreateFriendRequest(&friendRequest)
friends, err = Database.GetFriendRequestsByUserID(userSession.UserID.String(), page)
if err != nil { if err != nil {
http.Error(w, "Error", http.StatusInternalServerError) http.Error(w, "Error", http.StatusInternalServerError)
return return
} }
returnJSON, err = json.MarshalIndent(friendRequest, "", " ")
returnJSON, err = json.MarshalIndent(friends, "", " ")
if err != nil { if err != nil {
http.Error(w, "Error", http.StatusInternalServerError) http.Error(w, "Error", http.StatusInternalServerError)
return return
} }
// Return updated json
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(returnJSON) w.Write(returnJSON)
} }
// CreateFriendRequestQrCode creates a FriendRequest from post data from qr code scan
func CreateFriendRequestQrCode(w http.ResponseWriter, r *http.Request) {
var (
friendRequests []Models.FriendRequest
requestBody []byte
i int
err error
)
requestBody, err = ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
err = json.Unmarshal(requestBody, &friendRequests)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
for i = range friendRequests {
friendRequests[i].AcceptedAt.Time = time.Now()
friendRequests[i].AcceptedAt.Valid = true
}
err = Database.CreateFriendRequests(&friendRequests)
if err != nil {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
// Return updated json
w.WriteHeader(http.StatusOK)
}

+ 124
- 0
Backend/Api/Friends/Friends_test.go View File

@ -0,0 +1,124 @@
package Friends_test
import (
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"testing"
"time"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database/Seeder"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Models"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Tests"
)
func Test_FriendRequestList(t *testing.T) {
client, ts, err := Tests.InitTestEnv()
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
u, err := Database.GetUserByUsername("test")
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
for i := 0; i < 30; i++ {
u2, err := Tests.InitTestCreateUser(fmt.Sprintf("test%d", i))
decodedPublicKey := Seeder.GetPubKey()
key, err := Seeder.GenerateAesKey()
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
encPublicKey, err := key.AesEncrypt([]byte(Seeder.PublicKey))
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
friendReq := Models.FriendRequest{
UserID: u.ID,
FriendID: base64.StdEncoding.EncodeToString(
Seeder.EncryptWithPublicKey(
[]byte(u2.ID.String()),
decodedPublicKey,
),
),
FriendUsername: base64.StdEncoding.EncodeToString(
Seeder.EncryptWithPublicKey(
[]byte(u2.Username),
decodedPublicKey,
),
),
FriendPublicAsymmetricKey: base64.StdEncoding.EncodeToString(
encPublicKey,
),
SymmetricKey: base64.StdEncoding.EncodeToString(
Seeder.EncryptWithPublicKey(key.Key, decodedPublicKey),
),
}
if i > 20 {
friendReq.AcceptedAt.Time = time.Now()
friendReq.AcceptedAt.Valid = true
}
err = Database.CreateFriendRequest(&friendReq)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
}
req, _ := http.NewRequest("GET", ts.URL+"/api/v1/auth/friend_requests", nil)
resp, err := client.Do(req)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
if resp.StatusCode != http.StatusOK {
t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
return
}
requestBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
return
}
var users []Models.FriendRequest
json.Unmarshal(requestBody, &users)
if len(users) != 20 {
t.Errorf("Expected %d, recieved %d", 1, len(users))
return
}
for i := 0; i < 20; i++ {
eq := true
if i > 8 {
eq = false
}
if users[i].AcceptedAt.Valid != eq {
t.Errorf(
"Expected %v, recieved %v, on user %d",
eq, users[i].AcceptedAt.Valid,
i,
)
return
}
}
}

+ 1
- 5
Backend/Api/Messages/Conversations.go View File

@ -30,11 +30,7 @@ func ConversationList(w http.ResponseWriter, r *http.Request) {
page = 0 page = 0
} }
userSession, err = Auth.CheckCookie(r)
if err != nil {
http.Error(w, "Forbidden", http.StatusUnauthorized)
return
}
userSession, _ = Auth.CheckCookie(r)
conversationDetails, err = Database.GetUserConversationsByUserId( conversationDetails, err = Database.GetUserConversationsByUserId(
userSession.UserID.String(), userSession.UserID.String(),


+ 1
- 0
Backend/Api/Messages/Conversations_test.go View File

@ -102,6 +102,7 @@ func Test_ConversationsList(t *testing.T) {
if len(conversations) != 1 { if len(conversations) != 1 {
t.Errorf("Expected %d, recieved %d", 1, len(conversations)) t.Errorf("Expected %d, recieved %d", 1, len(conversations))
return
} }
conv := conversations[0] conv := conversations[0]


+ 12
- 1
Backend/Api/Messages/MessageThread.go View File

@ -3,6 +3,8 @@ package Messages
import ( import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"net/url"
"strconv"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models"
@ -17,7 +19,9 @@ func Messages(w http.ResponseWriter, r *http.Request) {
message Models.Message message Models.Message
urlVars map[string]string urlVars map[string]string
associationKey string associationKey string
values url.Values
returnJSON []byte returnJSON []byte
page int
i int i int
ok bool ok bool
err error err error
@ -30,7 +34,14 @@ func Messages(w http.ResponseWriter, r *http.Request) {
return return
} }
messages, err = Database.GetMessagesByAssociationKey(associationKey)
values = r.URL.Query()
page, err = strconv.Atoi(values.Get("page"))
if err != nil {
page = 0
}
messages, err = Database.GetMessagesByAssociationKey(associationKey, page)
if !ok { if !ok {
http.Error(w, "Not Found", http.StatusNotFound) http.Error(w, "Not Found", http.StatusNotFound)
return return


+ 88
- 0
Backend/Api/Messages/MessageThread_test.go View File

@ -115,3 +115,91 @@ func Test_Messages(t *testing.T) {
t.Errorf("Expected %s, recieved %s", "Test converation", string(decrypedData)) t.Errorf("Expected %s, recieved %s", "Test converation", string(decrypedData))
} }
} }
func Test_MessagesPagination(t *testing.T) {
client, ts, err := Tests.InitTestEnv()
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
u, err := Database.GetUserByUsername("test")
userKey, err := Seeder.GenerateAesKey()
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
key, err := Seeder.GenerateAesKey()
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
dataCiphertext, err := key.AesEncrypt([]byte("Test message"))
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
senderIDCiphertext, err := key.AesEncrypt([]byte(u.ID.String()))
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
keyCiphertext, err := userKey.AesEncrypt(
[]byte(base64.StdEncoding.EncodeToString(key.Key)),
)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
pubKey := Seeder.GetPubKey()
for i := 0; i < 50; i++ {
message := Models.Message{
MessageData: Models.MessageData{
Data: base64.StdEncoding.EncodeToString(dataCiphertext),
SenderID: base64.StdEncoding.EncodeToString(senderIDCiphertext),
SymmetricKey: base64.StdEncoding.EncodeToString(keyCiphertext),
},
SymmetricKey: base64.StdEncoding.EncodeToString(
Seeder.EncryptWithPublicKey(userKey.Key, pubKey),
),
AssociationKey: "AssociationKey",
}
err = Database.CreateMessage(&message)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
}
resp, err := client.Get(ts.URL + "/api/v1/auth/messages/AssociationKey")
if err != nil {
t.Errorf("Expected user record, recieved %s", err.Error())
return
}
if resp.StatusCode != http.StatusOK {
t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
return
}
requestBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
var m []Models.Message
err = json.Unmarshal(requestBody, &m)
if len(m) != 20 {
t.Errorf("Expected %d, recieved %d", 20, len(m))
}
}

+ 0
- 1
Backend/Api/Users/SearchUsers.go View File

@ -46,7 +46,6 @@ func SearchUsers(w http.ResponseWriter, r *http.Request) {
returnJSON, err = json.MarshalIndent(user, "", " ") returnJSON, err = json.MarshalIndent(user, "", " ")
if err != nil { if err != nil {
panic(err)
http.Error(w, "Not Found", http.StatusNotFound) http.Error(w, "Not Found", http.StatusNotFound)
return return
} }


+ 106
- 0
Backend/Api/Users/SearchUsers_test.go View File

@ -0,0 +1,106 @@
package Users_test
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"testing"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Models"
"git.tovijaeschke.xyz/tovi/Capsule/Backend/Tests"
)
func Test_SearchUsers(t *testing.T) {
client, ts, err := Tests.InitTestEnv()
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
u2, err := Tests.InitTestCreateUser("abcd")
req, _ := http.NewRequest(
"GET",
fmt.Sprintf("%s/api/v1/auth/users?username=%s", ts.URL, u2.Username),
nil,
)
resp, err := client.Do(req)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
if resp.StatusCode != http.StatusOK {
t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
return
}
requestBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
return
}
var user Models.User
json.Unmarshal(requestBody, &user)
if user.Username != "abcd" {
t.Errorf("Expected abcd, recieved %s", user.Username)
return
}
if user.Password != "" {
t.Errorf("Expected \"\", recieved %s", user.Password)
return
}
if user.AsymmetricPrivateKey != "" {
t.Errorf("Expected \"\", recieved %s", user.AsymmetricPrivateKey)
return
}
}
func Test_SearchUsersPartialMatchFails(t *testing.T) {
client, ts, err := Tests.InitTestEnv()
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
_, err = Tests.InitTestCreateUser("abcd")
req, _ := http.NewRequest(
"GET",
fmt.Sprintf("%s/api/v1/auth/users?username=%s", ts.URL, "abc"),
nil,
)
resp, err := client.Do(req)
if err != nil {
t.Errorf("Expected nil, recieved %s", err.Error())
return
}
if resp.StatusCode != http.StatusNotFound {
t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
return
}
requestBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
return
}
var user interface{}
json.Unmarshal(requestBody, &user)
if user != nil {
t.Errorf("Expected nil, recieved %+v", user)
return
}
}

+ 7
- 1
Backend/Database/FriendRequests.go View File

@ -22,14 +22,20 @@ func GetFriendRequestByID(id string) (Models.FriendRequest, error) {
} }
// GetFriendRequestsByUserID gets friend request by user id // GetFriendRequestsByUserID gets friend request by user id
func GetFriendRequestsByUserID(userID string) ([]Models.FriendRequest, error) {
func GetFriendRequestsByUserID(userID string, page int) ([]Models.FriendRequest, error) {
var ( var (
friends []Models.FriendRequest friends []Models.FriendRequest
offset int
err error err error
) )
offset = page * PageSize
err = DB.Model(Models.FriendRequest{}). err = DB.Model(Models.FriendRequest{}).
Where("user_id = ?", userID). Where("user_id = ?", userID).
Offset(offset).
Limit(PageSize).
Order("created_at DESC").
Find(&friends). Find(&friends).
Error Error


+ 7
- 2
Backend/Database/Messages.go View File

@ -22,15 +22,20 @@ func GetMessageByID(id string) (Models.Message, error) {
} }
// GetMessagesByAssociationKey for getting whole thread // GetMessagesByAssociationKey for getting whole thread
// TODO: Add pagination
func GetMessagesByAssociationKey(associationKey string) ([]Models.Message, error) {
func GetMessagesByAssociationKey(associationKey string, page int) ([]Models.Message, error) {
var ( var (
messages []Models.Message messages []Models.Message
offset int
err error err error
) )
offset = page * PageSize
err = DB.Preload("MessageData"). err = DB.Preload("MessageData").
Preload("MessageData.Attachment"). Preload("MessageData.Attachment").
Offset(offset).
Limit(PageSize).
Order("created_at DESC").
Find(&messages, "association_key = ?", associationKey). Find(&messages, "association_key = ?", associationKey).
Error Error


+ 2
- 0
Backend/Models/Friends.go View File

@ -2,6 +2,7 @@ package Models
import ( import (
"database/sql" "database/sql"
"time"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
) )
@ -17,4 +18,5 @@ type FriendRequest struct {
FriendPublicAsymmetricKey string ` json:"asymmetric_public_key"` // Stored encrypted FriendPublicAsymmetricKey string ` json:"asymmetric_public_key"` // Stored encrypted
SymmetricKey string `gorm:"not null" json:"symmetric_key"` // Stored encrypted SymmetricKey string `gorm:"not null" json:"symmetric_key"` // Stored encrypted
AcceptedAt sql.NullTime ` json:"accepted_at"` AcceptedAt sql.NullTime ` json:"accepted_at"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
} }

+ 19
- 14
Backend/Tests/Init.go View File

@ -19,28 +19,17 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
// InitTestEnv initializes the test environment
// client is used for making authenticated requests
// ts is the testing server
// err, in case it fails ¯\_(ツ)_/¯
func InitTestEnv() (*http.Client, *httptest.Server, error) {
log.SetOutput(ioutil.Discard)
Database.InitTest()
r := mux.NewRouter()
Api.InitAPIEndpoints(r)
ts := httptest.NewServer(r)
func InitTestCreateUser(username string) (Models.User, error) {
userKey, err := Seeder.GenerateAesKey() userKey, err := Seeder.GenerateAesKey()
if err != nil { if err != nil {
return http.DefaultClient, ts, err
return Models.User{}, err
} }
pubKey := Seeder.GetPubKey() pubKey := Seeder.GetPubKey()
p, _ := Auth.HashPassword("password") p, _ := Auth.HashPassword("password")
u := Models.User{ u := Models.User{
Username: "test",
Username: username,
Password: p, Password: p,
AsymmetricPublicKey: Seeder.PublicKey, AsymmetricPublicKey: Seeder.PublicKey,
AsymmetricPrivateKey: Seeder.EncryptedPrivateKey, AsymmetricPrivateKey: Seeder.EncryptedPrivateKey,
@ -50,6 +39,22 @@ func InitTestEnv() (*http.Client, *httptest.Server, error) {
} }
err = Database.CreateUser(&u) err = Database.CreateUser(&u)
return u, err
}
// InitTestEnv initializes the test environment
// client is used for making authenticated requests
// ts is the testing server
// err, in case it fails ¯\_(ツ)_/¯
func InitTestEnv() (*http.Client, *httptest.Server, error) {
log.SetOutput(ioutil.Discard)
Database.InitTest()
r := mux.NewRouter()
Api.InitAPIEndpoints(r)
ts := httptest.NewServer(r)
u, err := InitTestCreateUser("test")
if err != nil { if err != nil {
return http.DefaultClient, ts, err return http.DefaultClient, ts, err
} }


Loading…
Cancel
Save