databag/net/server/internal/testApp.go
2022-07-22 14:42:58 -07:00

909 lines
28 KiB
Go

package databag
import (
"encoding/json"
"errors"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"net/http"
"net/http/httptest"
"strconv"
"strings"
"sync"
"time"
)
const testTimeout = 5
type testCondition struct {
check func(*TestApp) bool
channel chan bool
}
type testTopic struct {
topic Topic
tags map[string]*Tag
}
type testChannel struct {
channel Channel
topics map[string]*testTopic
}
//TestContactData holds contact data for a test
type TestContactData struct {
token string
card Card
profileRevision int64
viewRevision int64
articleRevision int64
channelRevision int64
cardDetailRevision int64
cardProfileRevision int64
articles map[string]*Article
channels map[string]*testChannel
offsync bool
}
func (c *TestContactData) updateContact() (err error) {
if c.cardDetailRevision != c.card.Data.DetailRevision {
if err = c.updateContactCardDetail(); err != nil {
return
}
c.cardDetailRevision = c.card.Data.DetailRevision
}
if c.cardProfileRevision != c.card.Data.ProfileRevision {
if err = c.updateContactCardProfile(); err != nil {
return
}
c.cardProfileRevision = c.card.Data.ProfileRevision
}
// sync rest only if connected
if c.card.Data.CardDetail.Status != APPCardConnected {
return
}
if c.profileRevision != c.card.Data.NotifiedProfile {
if err = c.updateContactProfile(); err != nil {
return
}
c.profileRevision = c.card.Data.NotifiedProfile
}
if c.viewRevision != c.card.Data.NotifiedView {
if err = c.updateContactArticle(); err != nil {
return
} else if err = c.updateContactChannels(); err != nil {
return
}
c.articleRevision = c.card.Data.NotifiedArticle
c.channelRevision = c.card.Data.NotifiedChannel
c.viewRevision = c.card.Data.NotifiedView
}
if c.articleRevision != c.card.Data.NotifiedArticle {
if err = c.updateContactArticle(); err != nil {
return
}
c.articleRevision = c.card.Data.NotifiedArticle
}
if c.channelRevision != c.card.Data.NotifiedChannel {
if err = c.updateContactChannels(); err != nil {
return
}
c.channelRevision = c.card.Data.NotifiedChannel
}
return
}
func (c *TestContactData) updateContactProfile() (err error) {
var msg DataMessage
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
params := &TestAPIParams{query: "/profile/message", tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &msg}
if err = TestAPIRequest(GetProfileMessage, params, response); err != nil {
return
}
params = &TestAPIParams{restType: "PUT", query: "/contact/cards/{cardID}/profile", tokenType: APPTokenAgent, token: c.token,
path: map[string]string{"cardID": c.card.ID}, body: &msg}
response = &TestAPIResponse{}
if err = TestAPIRequest(SetCardProfile, params, response); err != nil {
return
}
return
}
func (c *TestContactData) updateContactArticle() (err error) {
var articles []Article
if c.articleRevision == 0 || c.viewRevision != c.card.Data.NotifiedView {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
params := &TestAPIParams{query: "/articles", tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &articles}
if err = TestAPIRequest(GetArticles, params, response); err != nil {
return
}
c.articles = make(map[string]*Article)
} else {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
viewRevision := strconv.FormatInt(c.viewRevision, 10)
articleRevision := strconv.FormatInt(c.articleRevision, 10)
params := &TestAPIParams{query: "/articles?articleRevision=" + articleRevision + "&viewRevision=" + viewRevision,
tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &articles}
if err = TestAPIRequest(GetArticles, params, response); err != nil {
return
}
}
for _, article := range articles {
if article.Data == nil {
delete(c.articles, article.ID)
} else {
c.articles[article.ID] = &article
}
}
return nil
}
func (c *TestContactData) updateContactChannels() (err error) {
var channels []Channel
if c.channelRevision == 0 || c.viewRevision != c.card.Data.NotifiedView {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
params := &TestAPIParams{query: "/channels", tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &channels}
if err = TestAPIRequest(GetChannels, params, response); err != nil {
return
}
} else {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
viewRevision := strconv.FormatInt(c.viewRevision, 10)
channelRevision := strconv.FormatInt(c.channelRevision, 10)
params := &TestAPIParams{query: "/channels?channelRevision=" + channelRevision + "&viewRevision=" + viewRevision,
tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &channels}
if err = TestAPIRequest(GetChannels, params, response); err != nil {
return
}
}
for _, channel := range channels {
if channel.Data == nil {
delete(c.channels, channel.ID)
} else {
tc, set := c.channels[channel.ID]
if set {
if channel.Revision != tc.channel.Revision {
if err = c.updateContactChannel(tc, &channel); err != nil {
return
}
tc.channel.Revision = channel.Revision
}
} else {
tc := &testChannel{channel: Channel{ID: channel.ID, Data: &ChannelData{}}}
c.channels[channel.ID] = tc
if err = c.updateContactChannel(tc, &channel); err != nil {
return
}
tc.channel.Revision = channel.Revision
}
}
}
return
}
func (c *TestContactData) updateContactChannel(storeChannel *testChannel, channel *Channel) (err error) {
if storeChannel.channel.Revision != channel.Revision {
if storeChannel.channel.Data.TopicRevision != channel.Data.TopicRevision {
if err = c.updateContactChannelTopics(storeChannel); err != nil {
return
}
storeChannel.channel.Data.TopicRevision = channel.Data.TopicRevision
}
if channel.Data.ChannelDetail != nil {
storeChannel.channel.Data.ChannelDetail = channel.Data.ChannelDetail
storeChannel.channel.Data.DetailRevision = channel.Data.DetailRevision
} else if storeChannel.channel.Data.DetailRevision != channel.Data.DetailRevision {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
params := &TestAPIParams{query: "/channel/{channelID}", path: map[string]string{"channelID": channel.ID},
tokenType: APPTokenContact, token: token}
detail := &ChannelDetail{}
response := &TestAPIResponse{data: &detail}
if err = TestAPIRequest(GetChannelDetail, params, response); err != nil {
return
}
if channel.Data == nil {
err = errors.New("channel removed during update")
return
}
storeChannel.channel.Data.ChannelDetail = detail
storeChannel.channel.Data.DetailRevision = channel.Data.DetailRevision
}
}
return
}
func (c *TestContactData) updateContactChannelTopics(storeChannel *testChannel) (err error) {
var topics []Topic
if storeChannel.channel.Revision == 0 {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
params := &TestAPIParams{query: "/channels/{channelID}/topics",
path: map[string]string{"channelID": storeChannel.channel.ID}, tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &topics}
if err = TestAPIRequest(GetChannelTopics, params, response); err != nil {
return
}
storeChannel.topics = make(map[string]*testTopic)
} else {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
revision := strconv.FormatInt(storeChannel.channel.Revision, 10)
params := &TestAPIParams{query: "/channels/{channelID}/topics?revision=" + revision,
path: map[string]string{"channelID": storeChannel.channel.ID}, tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &topics}
if err = TestAPIRequest(GetChannelTopics, params, response); err != nil {
return
}
}
for _, topic := range topics {
if topic.Data == nil {
delete(storeChannel.topics, topic.ID)
} else {
storeTopic, set := storeChannel.topics[topic.ID]
if set {
if topic.Revision != storeTopic.topic.Revision {
if err = c.updateContactChannelTopic(storeChannel, storeTopic, &topic); err != nil {
return
}
storeTopic.topic.Revision = topic.Revision
}
} else {
storeTopic := &testTopic{topic: Topic{ID: topic.ID, Data: &TopicData{}}}
storeChannel.topics[topic.ID] = storeTopic
if err = c.updateContactChannelTopic(storeChannel, storeTopic, &topic); err != nil {
return
}
storeTopic.topic.Revision = topic.Revision
}
}
}
return
}
func (c *TestContactData) updateContactChannelTopic(storeChannel *testChannel, storeTopic *testTopic, topic *Topic) (err error) {
if storeTopic.topic.Revision != topic.Revision {
if storeTopic.topic.Data.TagRevision != topic.Data.TagRevision {
if err = c.updateContactChannelTopicTags(storeChannel, storeTopic); err != nil {
return
}
storeTopic.topic.Data.TagRevision = topic.Data.TagRevision
}
if topic.Data.TopicDetail != nil {
storeTopic.topic.Data.TopicDetail = topic.Data.TopicDetail
storeTopic.topic.Data.DetailRevision = topic.Data.DetailRevision
} else if storeTopic.topic.Data.DetailRevision != topic.Data.DetailRevision {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
params := &TestAPIParams{query: "/channels/{channelID}/topics/{topicID}",
path: map[string]string{"channelID": storeChannel.channel.ID, "topicID": topic.ID},
tokenType: APPTokenContact, token: token}
topic := Topic{}
response := &TestAPIResponse{data: &topic}
if err = TestAPIRequest(GetChannelTopic, params, response); err != nil {
return
}
if topic.Data == nil {
err = errors.New("topic removed during update")
return
}
storeTopic.topic.Data.TopicDetail = topic.Data.TopicDetail
storeTopic.topic.Data.DetailRevision = topic.Data.DetailRevision
}
}
return
}
func (c *TestContactData) updateContactChannelTopicTags(storeChannel *testChannel, storeTopic *testTopic) (err error) {
var tags []Tag
if storeTopic.topic.Revision == 0 {
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
params := &TestAPIParams{query: "/channels/{channelID}/topics/{topicID}/tags",
path: map[string]string{"channelID": storeChannel.channel.ID, "topicID": storeTopic.topic.ID},
tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &tags}
if err = TestAPIRequest(GetChannelTopicTags, params, response); err != nil {
return
}
storeTopic.tags = make(map[string]*Tag)
} else {
revision := strconv.FormatInt(storeTopic.topic.Revision, 10)
token := c.card.Data.CardProfile.GUID + "." + c.card.Data.CardDetail.Token
params := &TestAPIParams{query: "/channels/{channelID}/topics/{topicID}/tags?revision=" + revision,
path: map[string]string{"channelID": storeChannel.channel.ID, "topicID": storeTopic.topic.ID},
tokenType: APPTokenContact, token: token}
response := &TestAPIResponse{data: &tags}
if err = TestAPIRequest(GetChannelTopicTags, params, response); err != nil {
return
}
}
for _, tag := range tags {
if tag.Data == nil {
delete(storeTopic.tags, tag.ID)
} else {
storeTopic.tags[tag.ID] = &tag
}
}
return
}
func (c *TestContactData) updateContactCardDetail() (err error) {
var cardDetail CardDetail
params := &TestAPIParams{query: "/contact/cards/{cardID}/detail", tokenType: APPTokenAgent, token: c.token,
path: map[string]string{"cardID": c.card.ID}}
response := &TestAPIResponse{data: &cardDetail}
if err = TestAPIRequest(GetCardDetail, params, response); err != nil {
return
}
c.card.Data.CardDetail = &cardDetail
return
}
func (c *TestContactData) updateContactCardProfile() (err error) {
var cardProfile CardProfile
params := &TestAPIParams{query: "/contact/cards/{cardID}/profile", tokenType: APPTokenAgent, token: c.token,
path: map[string]string{"cardID": c.card.ID}}
response := &TestAPIResponse{data: &cardProfile}
if err = TestAPIRequest(GetCardProfile, params, response); err != nil {
return
}
c.card.Data.CardProfile = &cardProfile
return
}
//NewTestApp allocate a new TestApp structure
func NewTestApp() *TestApp {
return &TestApp{
groups: make(map[string]*Group),
articles: make(map[string]*Article),
channels: make(map[string]*testChannel),
contacts: make(map[string]*TestContactData),
}
}
//TestApp holds an instance of test app use case
type TestApp struct {
name string
revision Revision
profile Profile
groups map[string]*Group
articles map[string]*Article
channels map[string]*testChannel
contacts map[string]*TestContactData
token string
mutex sync.Mutex
condition *testCondition
}
func (a *TestApp) updateProfile() (err error) {
params := &TestAPIParams{query: "/profile", tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &a.profile}
err = TestAPIRequest(GetProfile, params, response)
return
}
func (a *TestApp) updateGroups() (err error) {
var groups []Group
if a.revision.Group == 0 {
params := &TestAPIParams{query: "/groups", tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &groups}
if err = TestAPIRequest(GetGroups, params, response); err != nil {
return
}
} else {
revision := strconv.FormatInt(a.revision.Group, 10)
params := &TestAPIParams{query: "/groups?revision=" + revision, tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &groups}
if err = TestAPIRequest(GetGroups, params, response); err != nil {
return
}
}
for _, group := range groups {
if group.Data == nil {
delete(a.groups, group.ID)
} else {
a.groups[group.ID] = &group
}
}
return
}
func (a *TestApp) updateArticles() (err error) {
var articles []Article
if a.revision.Article == 0 {
params := &TestAPIParams{query: "/articles", tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &articles}
if err = TestAPIRequest(GetArticles, params, response); err != nil {
return
}
} else {
revision := strconv.FormatInt(a.revision.Article, 10)
params := &TestAPIParams{query: "/articles?articleRevision=" + revision, tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &articles}
if err = TestAPIRequest(GetArticles, params, response); err != nil {
return
}
}
for _, article := range articles {
if article.Data == nil {
delete(a.articles, article.ID)
} else {
a.articles[article.ID] = &article
}
}
return
}
func (a *TestApp) updateChannels() (err error) {
var channels []Channel
if a.revision.Channel == 0 {
params := &TestAPIParams{query: "/channels", tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &channels}
if err = TestAPIRequest(GetChannels, params, response); err != nil {
return
}
} else {
revision := strconv.FormatInt(a.revision.Channel, 10)
params := &TestAPIParams{query: "/channels?channelRevision=" + revision, tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &channels}
if err = TestAPIRequest(GetChannels, params, response); err != nil {
return
}
}
for _, channel := range channels {
if channel.Data == nil {
delete(a.channels, channel.ID)
} else {
storeChannel, set := a.channels[channel.ID]
if set {
if channel.Revision != storeChannel.channel.Revision {
if err = a.updateChannel(storeChannel, &channel); err != nil {
return
}
storeChannel.channel.Revision = channel.Revision
}
} else {
storeChannel := &testChannel{channel: Channel{ID: channel.ID, Data: &ChannelData{}}}
a.channels[channel.ID] = storeChannel
if err = a.updateChannel(storeChannel, &channel); err != nil {
return
}
storeChannel.channel.Revision = channel.Revision
}
}
}
return
}
func (a *TestApp) updateChannel(storeChannel *testChannel, channel *Channel) (err error) {
if storeChannel.channel.Revision != channel.Revision {
if storeChannel.channel.Data.TopicRevision != channel.Data.TopicRevision {
if err = a.updateChannelTopics(storeChannel); err != nil {
return
}
storeChannel.channel.Data.TopicRevision = channel.Data.TopicRevision
}
if channel.Data.ChannelDetail != nil {
storeChannel.channel.Data.ChannelDetail = channel.Data.ChannelDetail
storeChannel.channel.Data.DetailRevision = channel.Data.DetailRevision
} else if storeChannel.channel.Data.DetailRevision != channel.Data.DetailRevision {
params := &TestAPIParams{query: "/channel/{channelID}", path: map[string]string{"channelID": channel.ID},
tokenType: APPTokenAgent, token: a.token}
detail := &ChannelDetail{}
response := &TestAPIResponse{data: &detail}
if err = TestAPIRequest(GetChannelDetail, params, response); err != nil {
return
}
if channel.Data == nil {
err = errors.New("channel removed during update")
return
}
storeChannel.channel.Data.ChannelDetail = detail
storeChannel.channel.Data.DetailRevision = channel.Data.DetailRevision
}
}
return
}
func (a *TestApp) updateChannelTopics(storeChannel *testChannel) (err error) {
var topics []Topic
if storeChannel.channel.Revision == 0 {
params := &TestAPIParams{query: "/channels/{channelID}/topics",
path: map[string]string{"channelID": storeChannel.channel.ID}, tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &topics}
if err = TestAPIRequest(GetChannelTopics, params, response); err != nil {
return
}
storeChannel.topics = make(map[string]*testTopic)
} else {
revision := strconv.FormatInt(storeChannel.channel.Revision, 10)
params := &TestAPIParams{query: "/channels/{channelID}/topics?revision=" + revision,
path: map[string]string{"channelID": storeChannel.channel.ID}, tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &topics}
if err = TestAPIRequest(GetChannelTopics, params, response); err != nil {
return
}
}
for _, topic := range topics {
if topic.Data == nil {
delete(storeChannel.topics, topic.ID)
} else {
storeTopic, set := storeChannel.topics[topic.ID]
if set {
if topic.Revision != storeTopic.topic.Revision {
if err = a.updateChannelTopic(storeChannel, storeTopic, &topic); err != nil {
return
}
storeTopic.topic.Revision = topic.Revision
}
} else {
storeTopic := &testTopic{topic: Topic{ID: topic.ID, Data: &TopicData{}}}
storeChannel.topics[topic.ID] = storeTopic
if err = a.updateChannelTopic(storeChannel, storeTopic, &topic); err != nil {
return
}
storeTopic.topic.Revision = topic.Revision
}
}
}
return
}
func (a *TestApp) updateChannelTopic(storeChannel *testChannel, storeTopic *testTopic, topic *Topic) (err error) {
if storeTopic.topic.Revision != topic.Revision {
if storeTopic.topic.Data.TagRevision != topic.Data.TagRevision {
if err = a.updateChannelTopicTags(storeChannel, storeTopic); err != nil {
return
}
storeTopic.topic.Data.TagRevision = topic.Data.TagRevision
}
if topic.Data.TopicDetail != nil {
storeTopic.topic.Data.TopicDetail = topic.Data.TopicDetail
storeTopic.topic.Data.DetailRevision = topic.Data.DetailRevision
} else if storeTopic.topic.Data.DetailRevision != topic.Data.DetailRevision {
params := &TestAPIParams{query: "/channels/{channelID}/topics/{topicID}",
path: map[string]string{"channelID": storeChannel.channel.ID, "topicID": topic.ID},
tokenType: APPTokenAgent, token: a.token}
topic := Topic{}
response := &TestAPIResponse{data: &topic}
if err = TestAPIRequest(GetChannelTopic, params, response); err != nil {
return
}
if topic.Data == nil {
err = errors.New("topic removed during update")
return
}
storeTopic.topic.Data.TopicDetail = topic.Data.TopicDetail
storeTopic.topic.Data.DetailRevision = topic.Data.DetailRevision
}
}
return
}
func (a *TestApp) updateChannelTopicTags(storeChannel *testChannel, storeTopic *testTopic) (err error) {
var tags []Tag
if storeTopic.topic.Revision == 0 {
params := &TestAPIParams{query: "/channels/{channelID}/topics/{topicID}/tags",
path: map[string]string{"channelID": storeChannel.channel.ID, "topicID": storeTopic.topic.ID},
tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &tags}
if err = TestAPIRequest(GetChannelTopicTags, params, response); err != nil {
return
}
storeTopic.tags = make(map[string]*Tag)
} else {
revision := strconv.FormatInt(storeTopic.topic.Revision, 10)
params := &TestAPIParams{query: "/channels/{channelID}/topics/{topicID}/tags?revision=" + revision,
path: map[string]string{"channelID": storeChannel.channel.ID, "topicID": storeTopic.topic.ID},
tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &tags}
if err = TestAPIRequest(GetChannelTopicTags, params, response); err != nil {
return
}
}
for _, tag := range tags {
if tag.Data == nil {
delete(storeTopic.tags, tag.ID)
} else {
storeTopic.tags[tag.ID] = &tag
}
}
return
}
func (a *TestApp) updateCards() (err error) {
var cards []Card
if a.revision.Card == 0 {
params := &TestAPIParams{query: "/cards", tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &cards}
if err = TestAPIRequest(GetCards, params, response); err != nil {
return
}
for _, card := range cards {
if card.Data == nil {
delete(a.contacts, card.ID)
} else {
// set new card
contactData := &TestContactData{card: card, articles: make(map[string]*Article), channels: make(map[string]*testChannel),
cardDetailRevision: card.Data.DetailRevision, cardProfileRevision: card.Data.ProfileRevision,
profileRevision: card.Data.ProfileRevision, token: a.token}
a.contacts[card.ID] = contactData
if err = contactData.updateContact(); err != nil {
contactData.offsync = true
PrintMsg(err)
}
}
}
} else {
revision := strconv.FormatInt(a.revision.Card, 10)
params := &TestAPIParams{query: "/cards?revision=" + revision, tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &cards}
if err = TestAPIRequest(GetCards, params, response); err != nil {
return
}
for _, card := range cards {
if card.Data == nil {
delete(a.contacts, card.ID)
} else {
contactData, set := a.contacts[card.ID]
if !set {
// download new card
params := &TestAPIParams{query: "/cards/{cardID}", path: map[string]string{"cardID": card.ID},
tokenType: APPTokenAgent, token: a.token}
response := &TestAPIResponse{data: &card}
if err = TestAPIRequest(GetCard, params, response); err != nil {
return
}
contactData := &TestContactData{card: card, articles: make(map[string]*Article), channels: make(map[string]*testChannel),
cardDetailRevision: card.Data.DetailRevision, cardProfileRevision: card.Data.ProfileRevision,
profileRevision: card.Data.ProfileRevision, token: a.token}
a.contacts[card.ID] = contactData
if err = contactData.updateContact(); err != nil {
contactData.offsync = true
PrintMsg(err)
}
} else {
// update existing card revisions
contactData.card.Data.NotifiedProfile = card.Data.NotifiedProfile
contactData.card.Data.NotifiedArticle = card.Data.NotifiedArticle
contactData.card.Data.NotifiedChannel = card.Data.NotifiedChannel
contactData.card.Data.NotifiedView = card.Data.NotifiedView
contactData.card.Data.DetailRevision = card.Data.DetailRevision
contactData.card.Data.ProfileRevision = card.Data.ProfileRevision
if err = contactData.updateContact(); err != nil {
contactData.offsync = true
PrintMsg(err)
}
}
}
}
}
return
}
func (a *TestApp) updateApp(rev *Revision) {
a.mutex.Lock()
defer a.mutex.Unlock()
if rev.Profile != a.revision.Profile {
if err := a.updateProfile(); err != nil {
PrintMsg(err)
} else {
a.revision.Profile = rev.Profile
}
}
if rev.Group != a.revision.Group {
if err := a.updateGroups(); err != nil {
PrintMsg(err)
} else {
a.revision.Group = rev.Group
}
}
if rev.Article != a.revision.Article {
if err := a.updateArticles(); err != nil {
PrintMsg(err)
} else {
a.revision.Article = rev.Article
}
}
if rev.Card != a.revision.Card {
if err := a.updateCards(); err != nil {
PrintMsg(err)
} else {
a.revision.Card = rev.Card
}
}
if rev.Channel != a.revision.Channel {
if err := a.updateChannels(); err != nil {
PrintMsg(err)
} else {
a.revision.Channel = rev.Channel
}
}
if a.condition != nil {
if a.condition.check(a) {
select {
case a.condition.channel <- true:
default:
}
}
}
}
//Connect provides a test handler for the websocket connection
func (a *TestApp) Connect(token string) error {
var revision Revision
var data []byte
var dataType int
a.token = token
// connect websocket
ws, err := StatusConnection(token, &revision)
if err != nil {
return err
}
a.updateApp(&revision)
// reset any timeout
ws.SetReadDeadline(time.Time{})
// read revision update
for {
if dataType, data, err = ws.ReadMessage(); err != nil {
return errors.New("failed to read status connection")
}
if dataType != websocket.TextMessage {
return errors.New("invalid status data type")
}
rev := &Revision{}
if err = json.Unmarshal(data, rev); err != nil {
return errors.New("invalid status data")
}
a.updateApp(rev)
}
}
func (a *TestApp) setCondition(test *testCondition) {
a.mutex.Lock()
if test.check(a) {
test.channel <- true
} else {
a.condition = test
}
a.mutex.Unlock()
}
func (a *TestApp) clearCondition() {
a.mutex.Lock()
a.condition = nil
a.mutex.Unlock()
}
//WaitFor provides a helper waiting for a condition to be met
func (a *TestApp) WaitFor(check func(*TestApp) bool) error {
var done = make(chan bool, 1)
var wake = make(chan bool, 1)
a.setCondition(&testCondition{channel: done, check: check})
go func() {
time.Sleep(testTimeout * time.Second)
wake <- true
}()
select {
case <-done:
a.clearCondition()
return nil
case <-wake:
a.clearCondition()
return errors.New("timeout waiting for condition")
}
}
/*** endpoint test function ***/
//TestAPIParams holds the config for an endpoint test
type TestAPIParams struct {
restType string
path map[string]string
query string
body interface{}
tokenType string
token string
authorization string
credentials string
}
//TestAPIResponse holds the endpoint test response
type TestAPIResponse struct {
code int
data interface{}
header map[string][]string
}
//TestAPIRequest tests and endpoint with provided params
func TestAPIRequest(endpoint func(http.ResponseWriter, *http.Request), params *TestAPIParams, resp *TestAPIResponse) (err error) {
var r *http.Request
var w *httptest.ResponseRecorder
rest := params.restType
if rest == "" {
rest = "GET"
}
if params.tokenType == APPTokenAgent {
if !strings.Contains(params.query, "?") {
params.query += "?"
} else {
params.query += "&"
}
params.query += "agent=" + params.token
} else if params.tokenType == APPTokenContact {
if !strings.Contains(params.query, "?") {
params.query += "?"
} else {
params.query += "&"
}
params.query += "contact=" + params.token
}
if r, w, err = NewRequest(rest, params.query, params.body); err != nil {
return
}
r = mux.SetURLVars(r, params.path)
if params.tokenType != "" {
r.Header.Add("TokenType", params.tokenType)
}
if params.token != "" {
SetBearerAuth(r, params.token)
}
if params.authorization != "" {
SetBasicAuth(r, params.authorization)
}
if params.credentials != "" {
SetCredentials(r, params.credentials)
}
endpoint(w, r)
res := w.Result()
if res.StatusCode != 200 && res.StatusCode != 410 {
err = errors.New("response failed")
return
}
if resp != nil {
resp.header = res.Header
if resp.data != nil {
dec := json.NewDecoder(res.Body)
if err = dec.Decode(resp.data); err != nil {
return
}
}
}
return
}