Skip to content

Commit

Permalink
Add tests, clean up makefile (#12)
Browse files Browse the repository at this point in the history
* fix up circle handler tests

* add no circle test

* add circle invalid request test

* clean up makefile
  • Loading branch information
mattbonnell authored Jun 6, 2020
1 parent a34ff48 commit 5f6b001
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 117 deletions.
21 changes: 14 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,37 @@ BINARY_NAME_CONSUMER=consumer.out
BINARY_UNIX=$(BINARY_NAME)_unix
GOOGLE_GCR_HOSTNAME=gcr.io
GOOGLE_PROJECT_ID=spatiumsocialis
SOURCE_ENV=source .env


ifeq ($(env),)
env := dev
endif

all: deps test build
# TODO: Clean this mess up
test:
$(GOTEST) -coverprofile=/tmp/coverage.out ./$(package)... $(ARGS)
go tool cover -html=/tmp/coverage.out
$(SOURCE_ENV) && $(GOTEST) -coverprofile=/tmp/coverage.out ./pkg/... $(ARGS)
.PHONY: test
coverage:
go tool cover -html=/tmp/coverage.out
build-token:
$(GOBUILD) -o ./tools/tokengen/cmd/tokengen/tokengen.out ./tools/tokengen/cmd/tokengen
token:
./tools/tokengen/cmd/tokengen/tokengen.out -u $(uid)
$(SOURCE_ENV) && ./tools/tokengen/cmd/tokengen/tokengen.out -u $(uid)
push-deps:
docker push ${GOOGLE_GCR_HOSTNAME}/${GOOGLE_PROJECT_ID}/deps:latest
$(SOURCE_ENV) && docker push ${GOOGLE_GCR_HOSTNAME}/${GOOGLE_PROJECT_ID}/deps:latest
push:
docker-compose -f ${BUILD_DEPLOY_DIR}/docker-compose.yml -f ${BUILD_DEPLOY_DIR}/docker-compose.build.yml push ${service}
$(SOURCE_ENV) && docker-compose -f ${BUILD_DEPLOY_DIR}/docker-compose.yml -f ${BUILD_DEPLOY_DIR}/docker-compose.build.yml push ${service}
pull:
docker-compose pull ${service}
build-deps:
sh ./scripts/build-deps.sh ${GOOGLE_GCR_HOSTNAME} ${GOOGLE_PROJECT_ID} ${BUILD_PACKAGE_DIR} ${PWD}
$(SOURCE_ENV) && sh ./scripts/build-deps.sh ${GOOGLE_GCR_HOSTNAME} ${GOOGLE_PROJECT_ID} ${BUILD_PACKAGE_DIR} ${PWD}
start:
sh ./scripts/start.sh ${BUILD_DEPLOY_DIR} ${env} ${service}

build: build-deps
sh ./scripts/build.sh ${PWD} ${SERVICE_DOCKERFILE} ${BUILD_DEPLOY_DIR} ${service}
$(SOURCE_ENV) && sh ./scripts/build.sh ${PWD} ${SERVICE_DOCKERFILE} ${BUILD_DEPLOY_DIR} ${service}

stop:
docker-compose ${BUILD_DEPLOY_DIR}/docker-compose.yml down ${service}
Expand Down
7 changes: 3 additions & 4 deletions pkg/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,10 @@ func GetUserProfiles(users ...User) ([]Profile, error) {
for i, u := range users {
p := Profile{UID: u.ID}
userRecord, err := client.GetUser(ctx, u.ID)
if err != nil {
return []Profile{}, fmt.Errorf("error getting user '%v': %v", u.ID, err)
if err == nil {
p.Name = userRecord.DisplayName
p.ProfilePicture = userRecord.PhotoURL
}
p.Name = userRecord.DisplayName
p.ProfilePicture = userRecord.PhotoURL
profiles[i] = p
}
return profiles, nil
Expand Down
17 changes: 15 additions & 2 deletions pkg/services/circle/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ func AddToCircle(s *common.Service) http.Handler {
// Read the request body
body, err := ioutil.ReadAll(r.Body)
if err != nil {
common.ThrowError(w, fmt.Errorf("Error reading request body: %v", err.Error()), http.StatusInternalServerError)
common.ThrowError(w, fmt.Errorf("error reading request body: %v", err.Error()), http.StatusBadRequest)
return
}
// Unmarshal the circle
var circle models.Circle
if err := json.Unmarshal(body, &circle); err != nil {
common.ThrowError(w, fmt.Errorf("Error unmarshalling circle: %v", err.Error()), http.StatusInternalServerError)
common.ThrowError(w, fmt.Errorf("Error unmarshalling circle: %v", err.Error()), http.StatusBadRequest)
return
}

Expand All @@ -42,6 +42,19 @@ func AddToCircle(s *common.Service) http.Handler {
return
}

// Check if circle exists
query := s.DB.Find(&circle)
if query.RecordNotFound() {
// doesn't exist
common.ThrowError(w, fmt.Errorf("bad request: circle %v doesn't exist", circle.ID), http.StatusBadRequest)
return
}

if query.Error != nil {
common.ThrowError(w, query.Error, http.StatusInternalServerError)
return
}

err = models.AddUserToCircle(s, &user, &circle, true)
if err != nil {
common.ThrowError(w, fmt.Errorf("error adding user to circle: %v", err.Error()), http.StatusInternalServerError)
Expand Down
169 changes: 70 additions & 99 deletions pkg/services/circle/handlers/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
Expand All @@ -16,122 +15,94 @@ import (
"github.com/safe-distance/socium-infra/pkg/auth"
"github.com/safe-distance/socium-infra/pkg/common"
"github.com/safe-distance/socium-infra/pkg/services/circle/models"
"github.com/stretchr/testify/assert"
)

var s *common.Service

var saramaConfig *sarama.Config
var producer sarama.AsyncProducer
var validUsers = []auth.User{
{ID: "1"},
{ID: "2"},
{ID: "3"},
}

var validCircle = models.Circle{ID: "123", Users: validUsers}
var testUID = "TEST_UID"
var testToken = &auth.Token{UID: testUID}

func TestMain(m *testing.M) {
os.Setenv("DB_PROVIDER", "sqlite3")
os.Setenv("DB_CONNECTION_STRING", ":memory:")
saramaConfig = sarama.NewConfig()
saramaConfig.Producer.Return.Successes = true
producer := common.NewNullAsyncProducer()
s = common.NewService(config.ServiceName, config.ServicePathPrefix, models.Schema, producer, config.ProductionTopic)
producer = common.NewNullAsyncProducer()
os.Exit(m.Run())
}

func TestUserHandler(t *testing.T) {
// Create a test user and a test token
testUID := "TEST_UID"
testCircleID := "TEST_CIRCLE_ID"
testCircle := models.Circle{ID: testCircleID}
testToken := &auth.Token{UID: testUID}

// Marshal the text interaction to JSON, as it would be received in a POST request
payload, err := json.Marshal(testCircle)
if err != nil {
t.Fatalf("Error marshaling test circle: %v", err.Error())
}

// Create a test request and add the test token to its context
r := httptest.NewRequest("PATCH", "/circles/add", bytes.NewBuffer(payload))
ctx := auth.AddTokenTo(context.Background(), testToken)
func TestGetCircle_Valid(t *testing.T) {
s = common.NewService(config.ServiceName, config.ServicePathPrefix, models.Schema, producer, config.ProductionTopic)
err := s.DB.Create(&validCircle).Error
assert.Nil(t, err)
token := &auth.Token{UID: "1"}
r := httptest.NewRequest("GET", "/irrelevant", nil)
ctx := auth.AddTokenTo(context.Background(), token)
w := httptest.NewRecorder()
// Call the interaction handler with the response recorder and test request
AddToCircle(s).ServeHTTP(w, r.WithContext(ctx))

if w.Code != http.StatusOK {
body, _ := ioutil.ReadAll(w.Result().Body)
t.Fatalf("Error adding user to circle: %v", string(body))
}

// Read the body of the response recorder
resBuffer := bytes.NewBuffer([]byte{})
_, err = resBuffer.ReadFrom(w.Result().Body)
if err != nil {
t.Fatalf("Error reading from response buffer: %v", err.Error())
}

// Unmarshal the returned interaction
var createdCircle models.Circle
err = json.Unmarshal(resBuffer.Bytes(), &createdCircle)
if err != nil {
t.Fatalf("Error unmarshalling response body into Circle: %v", err.Error())
}

t.Logf("PATCH response circle: %+v", createdCircle)

// PATCH
newUserID := "NEW_USER_ID"
newTestToken := &auth.Token{UID: newUserID}

// Marshal the text interaction to JSON, as it would be received in a PATCH request
payload, err = json.Marshal(testCircle)
if err != nil {
t.Fatalf("Error marshaling test circle: %v", err.Error())
}

// Make a PATCH request to update the user
r = httptest.NewRequest("PATCH", "/circles", bytes.NewBuffer(payload))
w = httptest.NewRecorder()
ctx = auth.AddTokenTo(context.Background(), newTestToken)

AddToCircle(s).ServeHTTP(w, r.WithContext(ctx))

// Read the body of the response recorder
resBuffer = bytes.NewBuffer([]byte{})
_, err = resBuffer.ReadFrom(w.Result().Body)
if err != nil {
t.Fatalf("Error reading from response buffer: %v", err.Error())
}

// Unmarshal the returned interaction
var updatedCircle models.Circle
err = json.Unmarshal(resBuffer.Bytes(), &updatedCircle)
if err != nil {
t.Fatalf("Error unmarshalling response body into Circle: %v", err.Error())
}

t.Logf("PATCH response circle: %+v", updatedCircle)

// Make a GET request to retrieve the interaction
r = httptest.NewRequest("GET", "/circles", nil)
w = httptest.NewRecorder()
ctx = auth.AddTokenTo(r.Context(), testToken)
// Call the interaction handler with the response recorder and test request
GetCircle(s).ServeHTTP(w, r.WithContext(ctx))
assert.Equal(t, http.StatusOK, w.Code)
var responseCircle models.CircleResponse
err = json.Unmarshal(w.Body.Bytes(), &responseCircle)
assert.Nil(t, err)
assert.Equal(t, validCircle.ID, responseCircle.ID)
assert.Equal(t, len(validCircle.Users), len(responseCircle.Users))

// Read the body of the response recorder
resBuffer = bytes.NewBuffer([]byte{})
_, err = resBuffer.ReadFrom(w.Result().Body)
if err != nil {
t.Fatalf("Error reading from response buffer: %v", err.Error())
}

// Unmarshal the returned interaction
var retrievedCircle models.Circle
err = json.Unmarshal(resBuffer.Bytes(), &retrievedCircle)
if err != nil {
t.Fatalf("Error unmarshalling response body into Circle: %v", err.Error())
}
}

t.Logf("GET response circle: %+v", retrievedCircle)
func TestGetCircle_NoCircle(t *testing.T) {
s = common.NewService(config.ServiceName, config.ServicePathPrefix, models.Schema, producer, config.ProductionTopic)
err := s.DB.Create(&validCircle).Error
assert.Nil(t, err)
token := &auth.Token{UID: "99"}
r := httptest.NewRequest("GET", "/irrelevant", nil)
ctx := auth.AddTokenTo(context.Background(), token)
w := httptest.NewRecorder()
GetCircle(s).ServeHTTP(w, r.WithContext(ctx))
assert.Equal(t, http.StatusOK, w.Code)
var responseCircle models.CircleResponse
err = json.Unmarshal(w.Body.Bytes(), &responseCircle)
assert.Nil(t, err)
assert.Equal(t, 1, len(responseCircle.Users))
assert.Equal(t, token.UID, responseCircle.Users[0].UID)
}

// Check that the two interactions are equal
if len(updatedCircle.Users) != len(retrievedCircle.Users) {
t.Fatal("Fail: circles returned by PATCH and by GET are not equal")
}
func TestAddToCircle_Valid(t *testing.T) {
s = common.NewService(config.ServiceName, config.ServicePathPrefix, models.Schema, producer, config.ProductionTopic)
err := s.DB.Create(&validCircle).Error
assert.Nil(t, err)
token := &auth.Token{UID: "4"}
payload, err := json.Marshal(map[string]string{"id": "123"})
assert.Nil(t, err)
r := httptest.NewRequest("PATCH", "/irrelevant", bytes.NewBuffer(payload))
ctx := auth.AddTokenTo(context.Background(), token)
w := httptest.NewRecorder()
AddToCircle(s).ServeHTTP(w, r.WithContext(ctx))
assert.Equal(t, http.StatusOK, w.Code)
var responseCircle models.CircleResponse
err = json.Unmarshal(w.Body.Bytes(), &responseCircle)
assert.Equal(t, 4, len(responseCircle.Users))
}

func TestAddToCircle_Invalid(t *testing.T) {
s = common.NewService(config.ServiceName, config.ServicePathPrefix, models.Schema, producer, config.ProductionTopic)
err := s.DB.Create(&validCircle).Error
assert.Nil(t, err)
token := &auth.Token{UID: "4"}
payload, err := json.Marshal(map[string]string{"id": "9999"})
assert.Nil(t, err)
r := httptest.NewRequest("PATCH", "/irrelevant", bytes.NewBuffer(payload))
ctx := auth.AddTokenTo(context.Background(), token)
w := httptest.NewRecorder()
AddToCircle(s).ServeHTTP(w, r.WithContext(ctx))
assert.Equal(t, http.StatusBadRequest, w.Code)
}
1 change: 0 additions & 1 deletion pkg/services/circle/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ func AddUserToCircle(s *common.Service, user *auth.User, circle *Circle, mergeCi
if err := s.DB.Preload("Users").FirstOrCreate(circle, Circle{ID: circle.ID}).Error; err != nil {
return fmt.Errorf("error retrieving/creating circle: %v", err.Error())
}
fmt.Printf("circle: %+v\n", circle)
oldCircleID := user.CircleID
// Start association mode
association := s.DB.Model(circle).Association("Users")
Expand Down
3 changes: 0 additions & 3 deletions scripts/deploy

This file was deleted.

2 changes: 1 addition & 1 deletion scripts/deploy.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
gcloud beta compute scp --zone "us-central1-a" --project "spatiumsocialis" ./docker-compose.yml ./docker-compose.prod.yml Makefile spatium-prod:~/
gcloud beta compute scp --zone "us-central1-a" --project "spatiumsocialis" ./build Makefile spatium-prod:~/
gcloud beta compute ssh 'spatium-prod' --zone "us-central1-a" --project "spatiumsocialis" --command 'make pull; make start env=prod; exit'

0 comments on commit 5f6b001

Please sign in to comment.