api/clan_test.go
// khan
// https://github.com/topfreegames/khan
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Top Free Games <backend@tfgco.com>
package api_test
import (
"context"
"encoding/json"
"fmt"
"net/http"
"sort"
"strings"
"time"
"gopkg.in/olivere/elastic.v5"
"github.com/Pallinder/go-randomdata"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
uuid "github.com/satori/go.uuid"
"github.com/topfreegames/khan/api"
"github.com/topfreegames/khan/models"
"github.com/topfreegames/khan/models/fixtures"
"github.com/topfreegames/khan/testing"
)
var _ = Describe("Clan API Handler", func() {
var testDb, db models.DB
var app *api.App
var mongoWorker *models.MongoWorker
BeforeEach(func() {
var err error
testDb, err = GetTestDB()
Expect(err).NotTo(HaveOccurred())
app = GetDefaultTestApp()
db = app.Db(nil)
mongoWorker, _ = fixtures.ConfigureAndStartGoWorkers()
})
AfterEach(func() {
DestroyTestES()
})
Describe("Create Clan Handler", func() {
It("Should create clan", func() {
_, player, err := fixtures.CreatePlayerFactory(testDb, "")
Expect(err).NotTo(HaveOccurred())
clanPublicID := randomdata.FullName(randomdata.RandomGender)
payload := map[string]interface{}{
"publicID": clanPublicID,
"name": randomdata.FullName(randomdata.RandomGender),
"ownerPublicID": player.PublicID,
"metadata": map[string]interface{}{"x": "a"},
"allowApplication": true,
"autoJoin": true,
}
status, body := PostJSON(app, GetGameRoute(player.GameID, "/clans"), payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["publicID"]).To(Equal(clanPublicID))
dbClan, err := models.GetClanByPublicID(db, player.GameID, clanPublicID)
Expect(err).NotTo(HaveOccurred())
Expect(dbClan.GameID).To(Equal(player.GameID))
Expect(dbClan.OwnerID).To(Equal(player.ID))
Expect(dbClan.PublicID).To(Equal(payload["publicID"]))
Expect(dbClan.Name).To(Equal(payload["name"]))
Expect(dbClan.Metadata["x"]).To(
BeEquivalentTo(payload["metadata"].(map[string]interface{})["x"]),
)
Expect(dbClan.AllowApplication).To(Equal(payload["allowApplication"]))
Expect(dbClan.AutoJoin).To(Equal(payload["autoJoin"]))
})
It("Should create clan into mongodb if its configured", func() {
mongo, err := testing.GetTestMongo()
Expect(err).NotTo(HaveOccurred())
_, player, err := fixtures.CreatePlayerFactory(testDb, "")
Expect(err).NotTo(HaveOccurred())
metadata := map[string]interface{}{"x": "a"}
clanPublicID := randomdata.FullName(randomdata.RandomGender)
payload := map[string]interface{}{
"publicID": clanPublicID,
"name": randomdata.FullName(randomdata.RandomGender),
"ownerPublicID": player.PublicID,
"metadata": metadata,
"allowApplication": true,
"autoJoin": true,
}
status, body := PostJSON(app, GetGameRoute(player.GameID, "/clans"), payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["publicID"]).To(Equal(clanPublicID))
colName := fmt.Sprintf("clans_%s", player.GameID)
col, sess := mongo.C(colName)
defer sess.Close()
var res *models.Clan
Eventually(func() *models.Clan {
err = col.FindId(clanPublicID).One(&res)
return res
}, 5).Should(Not(BeNil()))
Expect(err).NotTo(HaveOccurred())
Expect(res).NotTo(BeNil())
Expect(res.PublicID).To(Equal(clanPublicID))
Expect(res.GameID).To(Equal(player.GameID))
Expect(res.Metadata).To(BeEquivalentTo(metadata))
})
// TODO: fix this when hardcoded boomforce is removed
XIt("Should index clan into ES when created", func() {
es := GetTestES()
_, player, err := fixtures.CreatePlayerFactory(testDb, "")
Expect(err).NotTo(HaveOccurred())
clanPublicID := randomdata.FullName(randomdata.RandomGender)
payload := map[string]interface{}{
"publicID": clanPublicID,
"name": randomdata.FullName(randomdata.RandomGender),
"ownerPublicID": player.PublicID,
"metadata": map[string]interface{}{"x": "a"},
"allowApplication": true,
"autoJoin": true,
}
status, body := PostJSON(app, GetGameRoute(player.GameID, "/clans"), payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["publicID"]).To(Equal(clanPublicID))
indexName := "khan-test"
var res *elastic.GetResult
err = testing.WaitForFunc(10, func() error {
var err error
res, err = es.Client.Get().Index(indexName).Type("clan").Id(clanPublicID).Do(context.TODO())
return err
})
Expect(err).NotTo(HaveOccurred())
Expect(res).NotTo(BeNil())
Expect(res.Index).To(Equal(indexName))
Expect(res.Type).To(Equal("clan"))
Expect(res.Id).To(Equal(clanPublicID))
})
It("Should not create clan if missing parameters", func() {
_, player, err := fixtures.CreatePlayerFactory(testDb, "")
Expect(err).NotTo(HaveOccurred())
clanPublicID := randomdata.FullName(randomdata.RandomGender)
payload := map[string]interface{}{
"publicID": clanPublicID,
"allowApplication": true,
"autoJoin": true,
}
status, body := PostJSON(app, GetGameRoute(player.GameID, "/clans"), payload)
Expect(status).To(Equal(http.StatusBadRequest))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal(fmt.Sprintf("name is required, ownerPublicID is required")))
})
It("Should not create clan if invalid payload", func() {
gameID := "gameID"
status, body := Post(app, GetGameRoute(gameID, "/clans"), "invalid")
Expect(status).To(Equal(http.StatusBadRequest))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(ContainSubstring(InvalidJSONError))
})
It("Should not create clan if owner does not exist", func() {
game, _, err := fixtures.CreatePlayerFactory(testDb, "")
Expect(err).NotTo(HaveOccurred())
payload := map[string]interface{}{
"publicID": randomdata.FullName(randomdata.RandomGender),
"name": randomdata.FullName(randomdata.RandomGender),
"ownerPublicID": randomdata.FullName(randomdata.RandomGender),
"metadata": map[string]interface{}{"x": "a"},
"allowApplication": true,
"autoJoin": true,
}
status, body := PostJSON(app, GetGameRoute(game.PublicID, "/clans"), payload)
Expect(status).To(Equal(http.StatusNotFound))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal(fmt.Sprintf("Player was not found with id: %s", payload["ownerPublicID"])))
})
It("Should not create clan if invalid data", func() {
_, player, err := fixtures.CreatePlayerFactory(testDb, "")
Expect(err).NotTo(HaveOccurred())
payload := map[string]interface{}{
"publicID": randomdata.FullName(randomdata.RandomGender),
"name": strings.Repeat("a", 256),
"ownerPublicID": player.PublicID,
"metadata": map[string]interface{}{"x": "a"},
"allowApplication": true,
"autoJoin": true,
}
status, body := PostJSON(app, GetGameRoute(player.GameID, "/clans"), payload)
Expect(status).To(Equal(http.StatusInternalServerError))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal("pq: value too long for type character varying(255)"))
})
})
Describe("Leave Clan Handler", func() {
It("Should leave a clan and transfer ownership", func() {
_, clan, owner, players, memberships, err := fixtures.GetClanWithMemberships(testDb, 1, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
route := GetGameRoute(clan.GameID, fmt.Sprintf("clans/%s/leave", clan.PublicID))
status, body := PostJSON(app, route, map[string]interface{}{})
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["previousOwner"]).NotTo(BeNil())
Expect(result["newOwner"]).NotTo(BeNil())
prevOwner := result["previousOwner"].(map[string]interface{})
Expect(prevOwner["publicID"]).To(BeEquivalentTo(owner.PublicID))
newOwner := result["newOwner"].(map[string]interface{})
Expect(newOwner["publicID"]).To(BeEquivalentTo(players[0].PublicID))
dbClan, err := models.GetClanByPublicID(db, clan.GameID, clan.PublicID)
Expect(err).NotTo(HaveOccurred())
Expect(dbClan.OwnerID).To(Equal(memberships[0].PlayerID))
})
It("Should leave and delete clan", func() {
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
route := GetGameRoute(clan.GameID, fmt.Sprintf("clans/%s/leave", clan.PublicID))
status, body := PostJSON(app, route, map[string]interface{}{})
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["previousOwner"]).NotTo(BeNil())
Expect(result["newOwner"]).To(BeNil())
prevOwner := result["previousOwner"].(map[string]interface{})
Expect(prevOwner["publicID"]).To(BeEquivalentTo(owner.PublicID))
dbClan, err := models.GetClanByPublicID(db, clan.GameID, clan.PublicID)
Expect(err).To(HaveOccurred())
Expect(dbClan).To(BeNil())
})
It("Should not leave a clan if invalid clan", func() {
route := GetGameRoute("game-id", fmt.Sprintf("clans/%s/leave", "random-id"))
status, body := Post(app, route, "")
Expect(status).To(Equal(http.StatusNotFound))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(strings.Contains(result["reason"].(string), "Clan was not found with id: random-id")).To(BeTrue())
})
})
Describe("Transfer Clan Ownership Handler", func() {
It("Should transfer a clan ownership", func() {
_, clan, owner, players, _, err := fixtures.GetClanWithMemberships(testDb, 1, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
ownerPublicID := owner.PublicID
playerPublicID := players[0].PublicID
payload := map[string]interface{}{
"ownerPublicID": ownerPublicID,
"playerPublicID": playerPublicID,
}
route := GetGameRoute(clan.GameID, fmt.Sprintf("clans/%s/transfer-ownership", clan.PublicID))
status, body := PostJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
dbClan, err := models.GetClanByPublicID(db, clan.GameID, clan.PublicID)
Expect(err).NotTo(HaveOccurred())
Expect(dbClan.OwnerID).To(Equal(players[0].ID))
})
It("Should not transfer a clan ownership if missing parameters", func() {
route := GetGameRoute("game-id", fmt.Sprintf("clans/%s/transfer-ownership", "public-id"))
status, body := PostJSON(app, route, map[string]interface{}{})
Expect(status).To(Equal(http.StatusBadRequest))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal("playerPublicID is required"))
})
It("Should not transfer a clan ownership if invalid payload", func() {
route := GetGameRoute("game-id", fmt.Sprintf("clans/%s/transfer-ownership", "random-id"))
status, body := Post(app, route, "invalid")
Expect(status).To(Equal(http.StatusBadRequest))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(ContainSubstring(InvalidJSONError))
})
})
Describe("Update Clan Handler", func() {
It("Should update clan", func() {
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
clanName := randomdata.FullName(randomdata.RandomGender)
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{"new": "metadata"}
payload := map[string]interface{}{
"name": clanName,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": !clan.AllowApplication,
"autoJoin": !clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
dbClan, err := models.GetClanByPublicID(db, gameID, publicID)
Expect(err).NotTo(HaveOccurred())
Expect(dbClan.GameID).To(Equal(gameID))
Expect(dbClan.PublicID).To(Equal(publicID))
Expect(dbClan.Name).To(Equal(clanName))
Expect(dbClan.OwnerID).To(Equal(owner.ID))
Expect(dbClan.Metadata).To(Equal(metadata))
Expect(dbClan.AllowApplication).To(Equal(!clan.AllowApplication))
Expect(dbClan.AutoJoin).To(Equal(!clan.AutoJoin))
})
It("Should update Mongo if update clan", func() {
mongo, err := testing.GetTestMongo()
Expect(err).NotTo(HaveOccurred())
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
colName := fmt.Sprintf("clans_%s", gameID)
col, sess := mongo.C(colName)
defer sess.Close()
var res *models.Clan
Eventually(func() *models.Clan {
err = col.FindId(publicID).One(&res)
return res
}, 5).Should(Not(BeNil()))
Expect(err).NotTo(HaveOccurred())
Expect(res).NotTo(BeNil())
Expect(res.Name).To(Equal(clan.Name))
Expect(res.OwnerID).To(Equal(owner.ID))
Expect(res.PublicID).To(Equal(publicID))
Expect(res.AutoJoin).To(Equal(clan.AutoJoin))
clanName := randomdata.FullName(randomdata.RandomGender)
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{"new": "metadata"}
payload := map[string]interface{}{
"name": clanName,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": !clan.AllowApplication,
"autoJoin": !clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", clan.PublicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Eventually(func() *models.Clan {
err = col.FindId(publicID).One(&res)
return res
}).Should(SatisfyAll(
Not(BeNil()),
WithTransform(func(res *models.Clan) string {
return res.Name
}, Equal(clanName)),
WithTransform(func(res *models.Clan) map[string]interface{} {
return res.Metadata
}, BeEquivalentTo(metadata)),
))
})
// TODO: fix this when hardcoded boomforce is removed
XIt("Should update ES if update clan", func() {
es := GetTestES()
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
clanName := randomdata.FullName(randomdata.RandomGender)
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{"new": "metadata"}
indexName := "khan-test"
Eventually(func() *elastic.GetResult {
res, _ := es.Client.Get().Index(indexName).Type("clan").Id(publicID).Do(context.TODO())
return res
}).Should(Not(BeNil()))
payload := map[string]interface{}{
"name": clanName,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": !clan.AllowApplication,
"autoJoin": !clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Eventually(func() *elastic.GetResult {
res, _ := es.Client.Get().Index(indexName).Type("clan").Id(publicID).Do(context.TODO())
return res
}).Should(SatisfyAll(
Not(BeNil()),
WithTransform(func(res *elastic.GetResult) string {
return res.Index
}, Equal(indexName)),
WithTransform(func(res *elastic.GetResult) string {
return res.Type
}, Equal("clan")),
WithTransform(func(res *elastic.GetResult) string {
return res.Id
}, Equal(publicID)),
WithTransform(func(res *elastic.GetResult) *models.Clan {
updClan, _ := models.GetClanFromJSON(*res.Source)
return updClan
}, SatisfyAll(
WithTransform(func(updClan *models.Clan) interface{} {
return updClan.Metadata["new"]
}, BeEquivalentTo(metadata["new"])),
WithTransform(func(updClan *models.Clan) interface{} {
return updClan.Metadata
}, HaveKeyWithValue("x", "a")),
WithTransform(func(updClan *models.Clan) bool {
return updClan.AllowApplication
}, BeEquivalentTo(!clan.AllowApplication)),
WithTransform(func(updClan *models.Clan) bool {
return updClan.AutoJoin
}, BeEquivalentTo(!clan.AutoJoin)),
)),
))
})
It("Should not update clan if missing parameters", func() {
route := GetGameRoute("gameID", fmt.Sprintf("/clans/%s", "publicID"))
status, body := PutJSON(app, route, map[string]interface{}{})
Expect(status).To(Equal(http.StatusBadRequest))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal("name is required, ownerPublicID is required"))
})
It("Should not update clan if invalid payload", func() {
route := GetGameRoute("game-id", fmt.Sprintf("/clans/%s", "random-id"))
status, body := Put(app, route, "invalid")
Expect(status).To(Equal(http.StatusBadRequest))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(ContainSubstring(InvalidJSONError))
})
It("Should not update clan if player is not the owner", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
metadata := map[string]interface{}{"x": "a"}
payload := map[string]interface{}{
"name": clan.Name,
"ownerPublicID": randomdata.FullName(randomdata.RandomGender),
"metadata": metadata,
"allowApplication": clan.AllowApplication,
"autoJoin": clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusNotFound))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal(fmt.Sprintf("Player was not found with id: %s", payload["ownerPublicID"])))
})
It("Should not update clan if invalid data", func() {
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
payload := map[string]interface{}{
"name": strings.Repeat("s", 256),
"ownerPublicID": owner.PublicID,
"metadata": map[string]interface{}{"x": "a"},
"allowApplication": clan.AllowApplication,
"autoJoin": clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusInternalServerError))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal("pq: value too long for type character varying(255)"))
})
})
Describe("List All Clans Handler", func() {
It("Should get all clans", func() {
mongoDB, err := testing.GetTestMongo()
Expect(err).NotTo(HaveOccurred())
player, expectedClans, err := fixtures.CreateTestClans(testDb, mongoDB, "", "", 10, fixtures.EnqueueClanForMongoUpdate)
Expect(err).NotTo(HaveOccurred())
sort.Sort(models.ClanByName(expectedClans))
status, body := Get(app, GetGameRoute(player.GameID, "/clans"))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
for index, clanObj := range result["clans"].([]interface{}) {
clan := clanObj.(map[string]interface{}) // Can't be map[string]interface{}
Expect(clan["name"]).To(Equal(expectedClans[index].Name))
clanMetadata := clan["metadata"].(map[string]interface{})
for k, v := range clanMetadata {
Expect(v).To(Equal(expectedClans[index].Metadata[k]))
}
Expect(clan["publicID"]).To(Equal(expectedClans[index].PublicID))
Expect(clan["ID"]).To(BeNil())
Expect(clan["autoJoin"]).To(Equal(expectedClans[index].AutoJoin))
Expect(clan["allowApplication"]).To(Equal(expectedClans[index].AllowApplication))
}
})
It("Should return empty list if invalid game query", func() {
status, body := Get(app, GetGameRoute("invalid-query-game-id", "/clans"))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(len(result["clans"].([]interface{}))).To(Equal(0))
})
})
Describe("Retrieve Clan Handler", func() {
It("Should get details for clan", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s", clan.PublicID)))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["name"]).To(Equal(clan.Name))
Expect(result["publicID"]).To(Equal(clan.PublicID))
resultMetadata := result["metadata"].(map[string]interface{})
for k, v := range resultMetadata {
Expect(v).To(Equal(clan.Metadata[k]))
}
})
It("Should get details for clan with short publicID", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?shortID=true", clan.PublicID[0:8])))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["name"]).To(Equal(clan.Name))
Expect(result["publicID"]).To(Equal(clan.PublicID))
resultMetadata := result["metadata"].(map[string]interface{})
for k, v := range resultMetadata {
Expect(v).To(Equal(clan.Metadata[k]))
}
})
It("Should get clan members", func() {
gameID := uuid.NewV4().String()
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(
testDb, 10, 0, 0, 0, gameID, "clan-details-api-clan",
)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s", clan.PublicID)))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["roster"] == nil).To(BeFalse())
})
It("Should fail with 400 if maxPendingApplications cannot be parsed as uint", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingApplications=xablau", clan.PublicID)))
Expect(status).To(Equal(http.StatusBadRequest))
Expect(body).To(ContainSubstring("invalid syntax"))
})
It("Should fail with 400 if maxPendingApplications is above allowed", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingApplications=101", clan.PublicID)))
Expect(status).To(Equal(http.StatusBadRequest))
Expect(body).To(ContainSubstring("above allowed"))
})
It("Should fail with 400 if maxPendingInvites cannot be parsed as uint", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingInvites=xablau", clan.PublicID)))
Expect(status).To(Equal(http.StatusBadRequest))
Expect(body).To(ContainSubstring("invalid syntax"))
})
It("Should fail with 400 if maxPendingInvites is above allowed", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingInvites=101", clan.PublicID)))
Expect(status).To(Equal(http.StatusBadRequest))
Expect(body).To(ContainSubstring("above allowed"))
})
It("Should fail with 400 if pendingApplicationsOrder is not a valid order string", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?pendingApplicationsOrder=xablau", clan.PublicID)))
Expect(status).To(Equal(http.StatusBadRequest))
Expect(body).To(ContainSubstring("order is invalid"))
})
It("Should fail with 400 if pendingInvitesOrder is not a valid order string", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?pendingInvitesOrder=xablau", clan.PublicID)))
Expect(status).To(Equal(http.StatusBadRequest))
Expect(body).To(ContainSubstring("order is invalid"))
})
type pendingMembershipPayload struct {
Player struct {
Metadata struct {
ID int `json:"id"`
} `json:"metadata"`
} `json:"player"`
}
type retrieveClanPayload struct {
Success bool `json:"success"`
Memberships struct {
PendingApplications []pendingMembershipPayload `json:"pendingApplications"`
PendingInvites []pendingMembershipPayload `json:"pendingInvites"`
} `json:"memberships"`
}
It("should get pending applications even if max amount is not set", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 10, "", "", false, false, true)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s", clan.PublicID)))
Expect(status).To(Equal(http.StatusOK))
var result retrieveClanPayload
json.Unmarshal([]byte(body), &result)
Expect(len(result.Memberships.PendingApplications)).To(BeNumerically(">", 0))
})
It("should get pending invites even if max amount is not set", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 10, "", "", false, true, true)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s", clan.PublicID)))
Expect(status).To(Equal(http.StatusOK))
var result retrieveClanPayload
json.Unmarshal([]byte(body), &result)
Expect(len(result.Memberships.PendingInvites)).To(BeNumerically(">", 0))
})
validateRetrieveClanResponse := func(memberships []*models.Membership, body, pendingsOrder string, pendingsLength int, pendingsAreInvites bool) {
Expect(pendingsLength).To(BeNumerically("<", len(memberships)))
var result retrieveClanPayload
json.Unmarshal([]byte(body), &result)
Expect(result.Success).To(BeTrue())
pendings := result.Memberships.PendingApplications
if pendingsAreInvites {
pendings = result.Memberships.PendingInvites
}
Expect(len(pendings)).To(Equal(pendingsLength))
lastOrFirstFromAllPendingMemberships := memberships[len(memberships)-1].ID
if pendingsOrder == ">" {
lastOrFirstFromAllPendingMemberships = memberships[0].ID
}
for _, pending := range pendings {
Expect(pending.Player.Metadata.ID).To(BeNumerically(pendingsOrder, lastOrFirstFromAllPendingMemberships))
}
}
It("Should get newest pending applications if order is not set", func() {
maxPending := 7
_, clan, _, _, memberships, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 10, "", "", false, false, true)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingApplications=%v", clan.PublicID, maxPending)))
Expect(status).To(Equal(http.StatusOK))
validateRetrieveClanResponse(memberships, body, ">", maxPending, false)
})
It("Should get newest pending applications", func() {
maxPending := 7
_, clan, _, _, memberships, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 10, "", "", false, false, true)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingApplications=%v&pendingApplicationsOrder=newest", clan.PublicID, maxPending)))
Expect(status).To(Equal(http.StatusOK))
validateRetrieveClanResponse(memberships, body, ">", maxPending, false)
})
It("Should get oldest pending applications", func() {
maxPending := 7
_, clan, _, _, memberships, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 10, "", "", false, false, true)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingApplications=%v&pendingApplicationsOrder=oldest", clan.PublicID, maxPending)))
Expect(status).To(Equal(http.StatusOK))
validateRetrieveClanResponse(memberships, body, "<", maxPending, false)
})
It("Should get newest pending invites if order is not set", func() {
maxPending := 7
_, clan, _, _, memberships, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 10, "", "", false, true, true)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingInvites=%v", clan.PublicID, maxPending)))
Expect(status).To(Equal(http.StatusOK))
validateRetrieveClanResponse(memberships, body, ">", maxPending, true)
})
It("Should get newest pending invites", func() {
maxPending := 7
_, clan, _, _, memberships, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 10, "", "", false, true, true)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingInvites=%v&pendingInvitesOrder=newest", clan.PublicID, maxPending)))
Expect(status).To(Equal(http.StatusOK))
validateRetrieveClanResponse(memberships, body, ">", maxPending, true)
})
It("Should get oldest pending invites", func() {
maxPending := 7
_, clan, _, _, memberships, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 10, "", "", false, true, true)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s?maxPendingInvites=%v&pendingInvitesOrder=oldest", clan.PublicID, maxPending)))
Expect(status).To(Equal(http.StatusOK))
validateRetrieveClanResponse(memberships, body, "<", maxPending, true)
})
})
Describe("Retrieve Clan Members Handler", func() {
It("Should get clans player ids", func() {
gameID := uuid.NewV4().String()
_, clan, owner, players, _, err := fixtures.GetClanWithMemberships(testDb, 10, 0, 0, 0, gameID, "clan1")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s/members", clan.PublicID)))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(len(result["members"].([]interface{}))).To(Equal(clan.MembershipCount))
Expect(result["members"].([]interface{})).To(ContainElement(owner.PublicID))
for _, p := range players {
Expect(result["members"].([]interface{})).To(ContainElement(p.PublicID))
}
})
})
Describe("Retrieve Clans Handler", func() {
It("Should get details for clans", func() {
gameID := uuid.NewV4().String()
_, clan1, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, gameID, "clan1")
Expect(err).NotTo(HaveOccurred())
_, clan2, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, gameID, "clan2", true)
Expect(err).NotTo(HaveOccurred())
_, clan3, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, gameID, "clan3", true)
Expect(err).NotTo(HaveOccurred())
clanIDs := []string{clan1.PublicID, clan2.PublicID, clan3.PublicID}
url := fmt.Sprintf(
"%s?clanPublicIds=%s",
GetGameRoute(clan1.GameID, "clans-summary"),
strings.Join(clanIDs, ","),
)
status, body := Get(app, url)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
resultClans := result["clans"].([]interface{})
Expect(len(resultClans)).To(Equal(3))
for _, resultClan := range resultClans {
resultClanMap := resultClan.(map[string]interface{})
Expect(resultClanMap["membershipCount"] == nil).To(BeFalse())
Expect(resultClanMap["publicID"] == nil).To(BeFalse())
Expect(resultClanMap["metadata"] == nil).To(BeFalse())
Expect(resultClanMap["name"] == nil).To(BeFalse())
Expect(resultClanMap["allowApplication"] == nil).To(BeFalse())
Expect(resultClanMap["autoJoin"] == nil).To(BeFalse())
Expect(len(resultClanMap)).To(Equal(6))
idExist := false
// check if publicID is in clanIDs
for _, clanID := range clanIDs {
if resultClanMap["publicID"] == clanID {
idExist = true
}
}
Expect(idExist).To(BeTrue())
}
})
It("Should not get details for clans for unexistent game", func() {
gameID := uuid.NewV4().String()
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(
testDb, 10, 0, 0, 0, gameID, uuid.NewV4().String(),
)
Expect(err).NotTo(HaveOccurred())
clanIDs := []string{clan.PublicID}
url := fmt.Sprintf(
"%s?clanPublicIds=%s",
GetGameRoute("unexistent_game", "clans-summary"),
strings.Join(clanIDs, ","),
)
status, body := Get(app, url)
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["missingClans"] == nil).To(BeFalse())
missingClans := result["missingClans"].([]interface{})
Expect(len(missingClans)).To(Equal(1))
Expect(status).To(Equal(http.StatusOK))
})
It("Should fail with 400 if empty query string", func() {
gameID := uuid.NewV4().String()
_, clan1, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, gameID, uuid.NewV4().String())
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan1.GameID, "clans-summary"))
Expect(status).To(Equal(http.StatusBadRequest))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal("No clanPublicIds provided"))
})
It("Should not fail if some clans do not exists", func() {
gameID := uuid.NewV4().String()
_, clan1, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, gameID, "clan1")
Expect(err).NotTo(HaveOccurred())
_, clan2, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, gameID, "clan2", true)
Expect(err).NotTo(HaveOccurred())
_, clan3, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, gameID, "clan3", true)
Expect(err).NotTo(HaveOccurred())
clanIDs := []string{clan1.PublicID, clan2.PublicID, clan3.PublicID, "unexistent_clan", "unexistent_clan2"}
url := fmt.Sprintf(
"%s?clanPublicIds=%s",
GetGameRoute(clan1.GameID, "clans-summary"),
strings.Join(clanIDs, ","),
)
status, body := Get(app, url)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
resultClans := result["clans"].([]interface{})
Expect(len(resultClans)).To(Equal(3))
Expect(result["missingClans"] == nil).To(BeFalse())
missingClans := result["missingClans"].([]interface{})
Expect(len(missingClans)).To(Equal(2))
for _, resultClan := range resultClans {
resultClanMap := resultClan.(map[string]interface{})
Expect(resultClanMap["membershipCount"] == nil).To(BeFalse())
Expect(resultClanMap["publicID"] == nil).To(BeFalse())
Expect(resultClanMap["metadata"] == nil).To(BeFalse())
Expect(resultClanMap["name"] == nil).To(BeFalse())
Expect(resultClanMap["allowApplication"] == nil).To(BeFalse())
Expect(resultClanMap["autoJoin"] == nil).To(BeFalse())
Expect(len(resultClanMap)).To(Equal(6))
idExist := false
// check if publicID is in clanIDs
for _, clanID := range clanIDs {
if resultClanMap["publicID"] == clanID {
idExist = true
}
}
Expect(idExist).To(BeTrue())
}
})
})
Describe("Retrieve Clan Summary Handler", func() {
It("Should get details for clan", func() {
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, "", "")
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(clan.GameID, fmt.Sprintf("/clans/%s/summary", clan.PublicID)))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["membershipCount"].(float64)).To(BeEquivalentTo(clan.MembershipCount))
Expect(result["publicID"]).To(Equal(clan.PublicID))
Expect(result["name"]).To(Equal(clan.Name))
Expect(result["allowApplication"]).To(Equal(clan.AllowApplication))
Expect(result["autoJoin"]).To(Equal(clan.AutoJoin))
resultMetadata := result["metadata"].(map[string]interface{})
for k, v := range resultMetadata {
Expect(v).To(Equal(clan.Metadata[k]))
}
})
It("Should not get details for clan that does not exist", func() {
status, body := Get(app, GetGameRoute("game-id", "/clans/dont-exist/summary"))
Expect(status).To(Equal(http.StatusNotFound))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeFalse())
Expect(result["reason"]).To(Equal("Clan was not found with id: dont-exist"))
})
})
Describe("Search Clan Handler", func() {
It("Should search for a clan", func() {
insertClanIntoMongo := func(player *models.Player, clan *models.Clan) error {
return mongoWorker.InsertGame(context.Background(), player.GameID, clan)
}
gameID := uuid.NewV4().String()
mongoDB, err := testing.GetTestMongo()
Expect(err).NotTo(HaveOccurred())
player, expectedClans, err := fixtures.CreateTestClans(
testDb, mongoDB, gameID, "clan-apisearch-clan", 10, insertClanIntoMongo,
)
Expect(err).NotTo(HaveOccurred())
status, body := Get(app, GetGameRoute(player.GameID, "clans/search?term=APISEARCH"))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
clans := result["clans"].([]interface{})
Expect(len(clans)).To(Equal(10))
clansDict := map[string]map[string]interface{}{}
for _, cl := range clans {
clan := cl.(map[string]interface{})
clansDict[clan["publicID"].(string)] = clan
}
for _, expectedClan := range expectedClans {
clan := clansDict[expectedClan.PublicID]
Expect(clan["name"]).To(Equal(expectedClan.Name))
Expect(clan["membershipCount"].(float64)).To(BeEquivalentTo(expectedClan.MembershipCount))
Expect(clan["autoJoin"]).To(Equal(expectedClan.AutoJoin))
Expect(clan["allowApplication"]).To(Equal(expectedClan.AllowApplication))
}
})
It("Should search for a clan by publicID", func() {
mongoDB, err := testing.GetTestMongo()
Expect(err).NotTo(HaveOccurred())
gameID := uuid.NewV4().String()
player, expectedClans, err := fixtures.CreateTestClans(
testDb, mongoDB, gameID, "clan-apisearch-clan", 10, fixtures.EnqueueClanForMongoUpdate,
)
Expect(err).NotTo(HaveOccurred())
time.Sleep(1000 * time.Millisecond)
status, body := Get(app, GetGameRoute(
player.GameID, fmt.Sprintf("clans/search?term=%s", expectedClans[3].PublicID),
))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
clans := result["clans"].([]interface{})
Expect(len(clans)).To(Equal(1))
Expect(clans[0].(map[string]interface{})["publicID"].(string)).
To(Equal(expectedClans[3].PublicID))
})
It("Should unicode search for a clan", func() {
mongoDB, err := testing.GetTestMongo()
Expect(err).NotTo(HaveOccurred())
gameID := uuid.NewV4().String()
player, expectedClans, err := fixtures.CreateTestClans(
testDb, mongoDB, gameID, "clan-apisearch-clan", 10, fixtures.EnqueueClanForMongoUpdate,
)
Expect(err).NotTo(HaveOccurred())
url := "clans/search?term=💩clán-clan-APISEARCH"
status, body := Get(app, GetGameRoute(player.GameID, url))
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
clans := result["clans"].([]interface{})
Expect(len(clans)).To(Equal(10))
clansDict := map[string]map[string]interface{}{}
for _, cl := range clans {
clan := cl.(map[string]interface{})
clansDict[clan["publicID"].(string)] = clan
}
for _, expectedClan := range expectedClans {
clan := clansDict[expectedClan.PublicID]
Expect(clan["name"]).To(Equal(expectedClan.Name))
Expect(clan["membershipCount"].(float64)).To(BeEquivalentTo(expectedClan.MembershipCount))
Expect(clan["autoJoin"]).To(Equal(expectedClan.AutoJoin))
Expect(clan["allowApplication"]).To(Equal(expectedClan.AllowApplication))
}
})
})
Describe("Clan Hooks", func() {
It("Should call create clan hook", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clancreated",
}, models.ClanCreatedHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clancreated"}, 52525)
_, player, err := fixtures.CreatePlayerFactory(testDb, hooks[0].GameID, true)
Expect(err).NotTo(HaveOccurred())
clanPublicID := uuid.NewV4().String()
payload := map[string]interface{}{
"publicID": clanPublicID,
"name": randomdata.FullName(randomdata.RandomGender),
"ownerPublicID": player.PublicID,
"metadata": map[string]interface{}{"x": "a"},
"allowApplication": true,
"autoJoin": true,
}
status, body := PostJSON(app, GetGameRoute(player.GameID, "/clans"), payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["publicID"]).To(Equal(clanPublicID))
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
hookRes := (*responses)[0]["payload"].(map[string]interface{})
Expect(hookRes["gameID"]).To(Equal(player.GameID))
clan := hookRes["clan"].(map[string]interface{})
Expect(clan["publicID"]).To(Equal(payload["publicID"]))
Expect(clan["name"]).To(Equal(payload["name"]))
Expect(str(clan["membershipCount"])).To(Equal("1"))
Expect(clan["allowApplication"]).To(Equal(payload["allowApplication"]))
Expect(clan["autoJoin"]).To(Equal(payload["autoJoin"]))
clanMetadata := clan["metadata"].(map[string]interface{})
metadata := payload["metadata"].(map[string]interface{})
for k, v := range clanMetadata {
Expect(str(v)).To(Equal(str(metadata[k])))
}
})
Describe("Update Clan Hook", func() {
Describe("Without whitelist", func() {
It("Should not call update clan hook", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanupdated",
}, models.ClanUpdatedHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanupdated"}, 52525)
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
clanName := clan.Name
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{"new": "metadata"}
payload := map[string]interface{}{
"name": clanName,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": clan.AllowApplication,
"autoJoin": clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Consistently(func() int {
return len(*responses)
}, 100*time.Millisecond, time.Millisecond).Should(Equal(0))
})
})
Describe("With whitelist", func() {
It("Should call update clan hook if field in whitelist", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanupdatedhookwhitelist",
}, models.ClanUpdatedHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanupdatedhookwhitelist"}, 52525)
sqlRes, err := testDb.Exec(
"UPDATE games SET clan_metadata_fields_whitelist='something,new' WHERE public_id=$1",
hooks[0].GameID,
)
Expect(err).NotTo(HaveOccurred())
count, err := sqlRes.RowsAffected()
Expect(err).NotTo(HaveOccurred())
Expect(count).To(BeEquivalentTo(1))
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{"new": "metadata"}
payload := map[string]interface{}{
"name": clan.Name,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": clan.AllowApplication,
"autoJoin": clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
hookRes := (*responses)[0]["payload"].(map[string]interface{})
Expect(hookRes["gameID"]).To(Equal(hooks[0].GameID))
rClan := hookRes["clan"].(map[string]interface{})
Expect(rClan["publicID"]).To(Equal(publicID))
Expect(rClan["name"]).To(Equal(payload["name"]))
Expect(str(rClan["membershipCount"])).To(Equal("1"))
Expect(rClan["allowApplication"]).To(Equal(payload["allowApplication"]))
Expect(rClan["autoJoin"]).To(Equal(payload["autoJoin"]))
clanMetadata := rClan["metadata"].(map[string]interface{})
metadata = payload["metadata"].(map[string]interface{})
for k, v := range clanMetadata {
Expect(str(v)).To(Equal(str(metadata[k])))
}
})
It("Should call update clan hook if field in whitelist is new", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanupdatedhookwhitelist3",
}, models.ClanUpdatedHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanupdatedhookwhitelist3"}, 52525)
sqlRes, err := testDb.Exec(
"UPDATE games SET clan_metadata_fields_whitelist='something,else' WHERE public_id=$1",
hooks[0].GameID,
)
Expect(err).NotTo(HaveOccurred())
count, err := sqlRes.RowsAffected()
Expect(err).NotTo(HaveOccurred())
Expect(count).To(BeEquivalentTo(1))
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{"else": "metadata"}
payload := map[string]interface{}{
"name": clan.Name,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": clan.AllowApplication,
"autoJoin": clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
hookRes := (*responses)[0]["payload"].(map[string]interface{})
Expect(hookRes["gameID"]).To(Equal(hooks[0].GameID))
rClan := hookRes["clan"].(map[string]interface{})
Expect(rClan["publicID"]).To(Equal(publicID))
Expect(rClan["name"]).To(Equal(payload["name"]))
Expect(str(rClan["membershipCount"])).To(Equal("1"))
Expect(rClan["allowApplication"]).To(Equal(payload["allowApplication"]))
Expect(rClan["autoJoin"]).To(Equal(payload["autoJoin"]))
clanMetadata := rClan["metadata"].(map[string]interface{})
metadata = payload["metadata"].(map[string]interface{})
for k, v := range clanMetadata {
Expect(str(v)).To(Equal(str(metadata[k])))
}
})
It("Should not call update clan hook if field not in whitelist", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanupdatedhookwhitelist2",
}, models.ClanUpdatedHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanupdatedhookwhitelist2"}, 52525)
sqlRes, err := testDb.Exec(
"UPDATE games SET clan_metadata_fields_whitelist='other,else' WHERE public_id=$1",
hooks[0].GameID,
)
Expect(err).NotTo(HaveOccurred())
count, err := sqlRes.RowsAffected()
Expect(err).NotTo(HaveOccurred())
Expect(count).To(BeEquivalentTo(1))
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{"new": "metadata"}
payload := map[string]interface{}{
"name": clan.Name,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": clan.AllowApplication,
"autoJoin": clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Consistently(func() int {
return len(*responses)
}, 100*time.Millisecond, time.Millisecond).Should(Equal(0))
})
Describe("Should call update clan hook if clan details changed", func() {
It("by name", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanupdatedhookwhitelist4",
}, models.ClanUpdatedHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanupdatedhookwhitelist4"}, 52525)
sqlRes, err := testDb.Exec(
"UPDATE games SET clan_metadata_fields_whitelist='something,else' WHERE public_id=$1",
hooks[0].GameID,
)
Expect(err).NotTo(HaveOccurred())
count, err := sqlRes.RowsAffected()
Expect(err).NotTo(HaveOccurred())
Expect(count).To(BeEquivalentTo(1))
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{}
payload := map[string]interface{}{
"name": uuid.NewV4().String(),
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": clan.AllowApplication,
"autoJoin": clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
})
It("by AutoJoin", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanupdatedhookwhitelist6",
}, models.ClanUpdatedHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanupdatedhookwhitelist6"}, 52525)
sqlRes, err := testDb.Exec(
"UPDATE games SET clan_metadata_fields_whitelist='something,else' WHERE public_id=$1",
hooks[0].GameID,
)
Expect(err).NotTo(HaveOccurred())
count, err := sqlRes.RowsAffected()
Expect(err).NotTo(HaveOccurred())
Expect(count).To(BeEquivalentTo(1))
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{}
payload := map[string]interface{}{
"name": clan.Name,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": clan.AllowApplication,
"autoJoin": !clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
})
It("by AllowApplication", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanupdatedhookwhitelist5",
}, models.ClanUpdatedHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanupdatedhookwhitelist5"}, 52525)
sqlRes, err := testDb.Exec(
"UPDATE games SET clan_metadata_fields_whitelist='something,else' WHERE public_id=$1",
hooks[0].GameID,
)
Expect(err).NotTo(HaveOccurred())
count, err := sqlRes.RowsAffected()
Expect(err).NotTo(HaveOccurred())
Expect(count).To(BeEquivalentTo(1))
_, clan, owner, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
ownerPublicID := owner.PublicID
metadata := map[string]interface{}{}
payload := map[string]interface{}{
"name": clan.Name,
"ownerPublicID": ownerPublicID,
"metadata": metadata,
"allowApplication": !clan.AllowApplication,
"autoJoin": clan.AutoJoin,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s", publicID))
status, body := PutJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
})
})
})
})
It("Should call leave clan hook", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanleave",
}, models.ClanLeftHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanleave"}, 52525)
_, clan, _, players, _, err := fixtures.GetClanWithMemberships(testDb, 1, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
payload := map[string]interface{}{}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s/leave", publicID))
status, body := PostJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
rClan := (*responses)[0]["payload"].(map[string]interface{})
Expect(rClan["gameID"]).To(Equal(hooks[0].GameID))
Expect(rClan["type"].(float64)).To(BeEquivalentTo(5))
Expect(rClan["id"]).NotTo(BeEquivalentTo(nil))
_, err = uuid.FromString(rClan["id"].(string))
Expect(err).NotTo(HaveOccurred())
Expect(rClan["timestamp"]).NotTo(BeEquivalentTo(nil))
clanDetails := rClan["clan"].(map[string]interface{})
Expect(clanDetails["publicID"]).To(Equal(clan.PublicID))
Expect(clanDetails["name"]).To(Equal(clan.Name))
Expect(clanDetails["membershipCount"]).To(BeEquivalentTo(1))
Expect(clanDetails["allowApplication"]).To(Equal(clan.AllowApplication))
Expect(clanDetails["autoJoin"]).To(Equal(clan.AutoJoin))
newOwner := players[0]
ownerDetails := rClan["newOwner"].(map[string]interface{})
Expect(ownerDetails["publicID"]).To(Equal(newOwner.PublicID))
Expect(ownerDetails["name"]).To(Equal(newOwner.Name))
Expect(ownerDetails["membershipCount"]).To(BeEquivalentTo(0))
Expect(ownerDetails["ownershipCount"]).To(BeEquivalentTo(1))
})
It("Should call leave clan hook when last member", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clanleave2",
}, models.ClanLeftHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clanleave2"}, 52525)
_, clan, _, _, _, err := fixtures.GetClanWithMemberships(testDb, 0, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
payload := map[string]interface{}{}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s/leave", publicID))
status, body := PostJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["isDeleted"]).To(BeTrue())
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
rClan := (*responses)[0]["payload"].(map[string]interface{})
Expect(rClan["gameID"]).To(Equal(hooks[0].GameID))
Expect(rClan["type"].(float64)).To(BeEquivalentTo(5))
Expect(rClan["id"]).NotTo(BeEquivalentTo(nil))
_, err = uuid.FromString(rClan["id"].(string))
Expect(err).NotTo(HaveOccurred())
Expect(rClan["timestamp"]).NotTo(BeEquivalentTo(nil))
clanDetails := rClan["clan"].(map[string]interface{})
Expect(clanDetails["publicID"]).To(Equal(clan.PublicID))
Expect(clanDetails["name"]).To(Equal(clan.Name))
Expect(clanDetails["membershipCount"]).To(BeEquivalentTo(1))
Expect(clanDetails["allowApplication"]).To(Equal(clan.AllowApplication))
Expect(clanDetails["autoJoin"]).To(Equal(clan.AutoJoin))
Expect(rClan["newOwner"]).To(BeNil())
})
It("Should call transfer ownership hook", func() {
hooks, err := fixtures.GetHooksForRoutes(testDb, []string{
"http://localhost:52525/clantransfer",
}, models.ClanOwnershipTransferredHook)
Expect(err).NotTo(HaveOccurred())
responses := startRouteHandler([]string{"/clantransfer"}, 52525)
_, clan, owner, players, _, err := fixtures.GetClanWithMemberships(testDb, 1, 0, 0, 0, hooks[0].GameID, "", true)
Expect(err).NotTo(HaveOccurred())
gameID := clan.GameID
publicID := clan.PublicID
payload := map[string]interface{}{
"playerPublicID": players[0].PublicID,
}
route := GetGameRoute(gameID, fmt.Sprintf("/clans/%s/transfer-ownership", publicID))
status, body := PostJSON(app, route, payload)
Expect(status).To(Equal(http.StatusOK))
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
Expect(result["success"]).To(BeTrue())
Expect(result["newOwner"]).NotTo(BeNil())
Expect(result["previousOwner"]).NotTo(BeNil())
Eventually(func() int {
return len(*responses)
}).Should(Equal(1))
rClan := (*responses)[0]["payload"].(map[string]interface{})
Expect(rClan["gameID"]).To(Equal(hooks[0].GameID))
clanDetails := rClan["clan"].(map[string]interface{})
Expect(clanDetails["publicID"]).To(Equal(clan.PublicID))
Expect(clanDetails["name"]).To(Equal(clan.Name))
Expect(clanDetails["membershipCount"]).To(BeEquivalentTo(2))
Expect(clanDetails["allowApplication"]).To(Equal(clan.AllowApplication))
Expect(clanDetails["autoJoin"]).To(Equal(clan.AutoJoin))
newOwner := players[0]
ownerDetails := rClan["newOwner"].(map[string]interface{})
Expect(ownerDetails["publicID"]).To(Equal(newOwner.PublicID))
Expect(ownerDetails["name"]).To(Equal(newOwner.Name))
Expect(ownerDetails["membershipCount"]).To(BeEquivalentTo(0))
Expect(ownerDetails["ownershipCount"]).To(BeEquivalentTo(1))
previousOwnerDetails := rClan["previousOwner"].(map[string]interface{})
Expect(previousOwnerDetails["publicID"]).To(Equal(owner.PublicID))
Expect(previousOwnerDetails["name"]).To(Equal(owner.Name))
Expect(previousOwnerDetails["membershipCount"]).To(BeEquivalentTo(1))
Expect(previousOwnerDetails["ownershipCount"]).To(BeEquivalentTo(0))
})
})
})