diff --git a/example/rest/main.go b/example/rest/main.go new file mode 100644 index 0000000..88171d7 --- /dev/null +++ b/example/rest/main.go @@ -0,0 +1,113 @@ +package main + +import ( + "flag" + "fmt" + "log" + "net/url" + "os" + + "github.com/RocketChat/Rocket.Chat.Go.SDK/models" + "github.com/RocketChat/Rocket.Chat.Go.SDK/rest" +) + +func main() { + + hostPtr := flag.String("host", "", "Rocket.chat server host") + schemePtr := flag.String("scheme", "https", "http/https") + userPtr := flag.String("user", "", "Rocket.chat user") + passPtr := flag.String("pass", "", "Rocket.chat password") + + required := []string{"host", "user", "pass"} + flag.Parse() + + seen := make(map[string]bool) + flag.Visit(func(f *flag.Flag) { seen[f.Name] = true }) + for _, req := range required { + if !seen[req] { + fmt.Fprintf(os.Stderr, "Missing required argument -%s\n", req) + os.Exit(2) + } + } + + rockerServer := &url.URL{Host: *hostPtr, Scheme: *schemePtr} + debug := false + + credentials := &models.UserCredentials{Email: *userPtr, Password: *passPtr} + rc, err := rest.NewRestClient(rockerServer, debug) + if err != nil { + log.Fatal(err) + } + err = rc.Rest.Login(credentials) + if err != nil { + log.Fatal(err) + } + + myroom := &models.Channel{Name: "myroom"} + + err = rc.Rest.ChannelsCreate(myroom) + if err != nil { + log.Println(err) + } + + rcChannels, err := rc.Rest.GetPublicChannels() + if err != nil { + log.Println(err) + } + + for _, channel := range rcChannels.Channels { + fmt.Printf("channel\n\tName:\t%s\n\tID:\t%s\n", channel.Name, channel.ID) + + if channel.Name == "myroom" { + closeThisRoom := &models.Channel{ID: channel.ID} + err = rc.Rest.ChannelClose(closeThisRoom) + if err != nil { + log.Println(err) + } + } + } + + general := &models.Channel{ID: "GENERAL", Name: "general"} + + members, _ := rc.Rest.GetMembersList("GENERAL") + fmt.Println(members) + + messages, err := rc.Rest.GetMessages(general, &models.Pagination{Count: 5}) + if err != nil { + log.Println(err) + } + + for _, message := range messages { + fmt.Printf("%s %s\n", message.Timestamp, message.User.UserName) + fmt.Printf("%s\n", message.Msg) + fmt.Println("") + } + + msgOBJ := models.Attachment{ + Color: "#00ff00", + Text: "Yay for the gopher!", + ImageURL: "https://ih1.redbubble.net/image.377846240.0222/ap,550x550,12x16,1,transparent,t.png", + Title: "PostMessage Example for Go", + Fields: []models.AttachmentField{ + models.AttachmentField{Short: true, Title: "Get the package", Value: "[Link](https://github.com/RocketChat/Rocket.Chat.Go.SDK) Rocket.Chat.Go.SDK"}, + }, + } + + msgPOST := models.PostMessage{ + RoomID: "GENERAL", + Channel: "general", + Emoji: ":smirk:", + Text: "PostMessage API using GoLang works ok", + Attachments: []models.Attachment{ + msgOBJ, + }, + } + + message, err := rc.Rest.PostMessage(&msgPOST) + log.Println(message) + + if err != nil { + log.Println(err) + } +} + diff --git a/models/channel.go b/models/channel.go index c6579ec..e0705a5 100644 --- a/models/channel.go +++ b/models/channel.go @@ -2,6 +2,7 @@ package models import "time" +// Channel ... type Channel struct { ID string `json:"_id"` Name string `json:"name"` @@ -25,15 +26,33 @@ type Channel struct { // } `json:"customFields,omitempty"` } +// ChannelSubscription ... type ChannelSubscription struct { ID string `json:"_id"` Alert bool `json:"alert"` Name string `json:"name"` DisplayName string `json:"fname"` Open bool `json:"open"` - RoomId string `json:"rid"` + RoomID string `json:"rid"` Type string `json:"c"` User User `json:"u"` Roles []string `json:"roles"` Unread float64 `json:"unread"` } + +//MembersList members in a channel +type MembersList struct { + Members []Member `json:"members"` + Count int `json:"count"` + Offset int `json:"offset"` + Total int `json:"total"` + Success bool `json:"success"` +} + +// Member ... +type Member struct { + ID string `json:"_id"` + Username string `json:"username"` + Name string `json:"name"` + Status string `json:"status"` +} diff --git a/models/info.go b/models/info.go index fb99e7c..32e0d6b 100644 --- a/models/info.go +++ b/models/info.go @@ -2,6 +2,7 @@ package models import "time" +// Info ... type Info struct { Version string `json:"version"` @@ -22,12 +23,14 @@ type Info struct { } `json:"commit"` } +// Pagination ... type Pagination struct { Count int `json:"count"` Offset int `json:"offset"` Total int `json:"total"` } +// Directory ... type Directory struct { Result []struct { ID string `json:"_id"` @@ -43,11 +46,13 @@ type Directory struct { Pagination } +// Spotlight ... type Spotlight struct { Users []User `json:"users"` Rooms []Channel `json:"rooms"` } +// Statistics ... type Statistics struct { ID string `json:"_id"` UniqueID string `json:"uniqueId"` @@ -122,10 +127,12 @@ type Statistics struct { UpdatedAt time.Time `json:"_updatedAt"` } +// StatisticsInfo ... type StatisticsInfo struct { Statistics Statistics `json:"statistics"` } +// StatisticsList ... type StatisticsList struct { Statistics []Statistics `json:"statistics"` diff --git a/models/message.go b/models/message.go index 8be3e3b..840c4d7 100644 --- a/models/message.go +++ b/models/message.go @@ -2,6 +2,7 @@ package models import "time" +// Message ... type Message struct { ID string `json:"_id"` RoomID string `json:"rid"` diff --git a/models/permission.go b/models/permission.go index 052bad8..674087c 100644 --- a/models/permission.go +++ b/models/permission.go @@ -1,5 +1,6 @@ package models +// Permission ... type Permission struct { ID string `json:"_id"` UpdatedAt string `json:"_updatedAt.$date"` diff --git a/models/setting.go b/models/setting.go index aeacb38..c8e0ee7 100644 --- a/models/setting.go +++ b/models/setting.go @@ -1,5 +1,6 @@ package models +// Setting ... type Setting struct { ID string `json:"_id"` Blocked bool `json:"blocked"` @@ -16,6 +17,7 @@ type Setting struct { ValueAsset Asset `json:"asset"` } +// Asset ... type Asset struct { - DefaultUrl string `json:"defaultUrl"` + DefaultURL string `json:"defaultUrl"` } diff --git a/models/user.go b/models/user.go index 13b41f7..4e08909 100644 --- a/models/user.go +++ b/models/user.go @@ -1,5 +1,6 @@ package models +// User ... type User struct { ID string `json:"_id"` Name string `json:"name"` diff --git a/models/userCredentials.go b/models/userCredentials.go index 296e26f..257138a 100644 --- a/models/userCredentials.go +++ b/models/userCredentials.go @@ -1,5 +1,6 @@ package models +// UserCredentials model type UserCredentials struct { ID string `json:"id"` Token string `json:"token"` diff --git a/realtime/channels.go b/realtime/channels.go index 57669cd..c932f0e 100644 --- a/realtime/channels.go +++ b/realtime/channels.go @@ -7,7 +7,8 @@ import ( "github.com/RocketChat/Rocket.Chat.Go.SDK/models" ) -func (c *Client) GetChannelId(name string) (string, error) { +// GetChannelID ... +func (c *Client) GetChannelID(name string) (string, error) { rawResponse, err := c.ddp.Call("getRoomIdByNameOrId", name) if err != nil { return "", err @@ -99,8 +100,8 @@ func (c *Client) GetChannelSubscriptions() ([]models.ChannelSubscription, error) // GetChannelRoles returns room roles // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/get-room-roles -func (c *Client) GetChannelRoles(roomId string) error { - _, err := c.ddp.Call("getRoomRoles", roomId) +func (c *Client) GetChannelRoles(roomID string) error { + _, err := c.ddp.Call("getRoomRoles", roomID) if err != nil { return err } @@ -138,8 +139,8 @@ func (c *Client) CreateGroup(name string, users []string) error { // Takes roomId // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/joining-channels -func (c *Client) JoinChannel(roomId string) error { - _, err := c.ddp.Call("joinRoom", roomId) +func (c *Client) JoinChannel(roomID string) error { + _, err := c.ddp.Call("joinRoom", roomID) if err != nil { return err } @@ -151,8 +152,8 @@ func (c *Client) JoinChannel(roomId string) error { // Takes roomId // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/leaving-rooms -func (c *Client) LeaveChannel(roomId string) error { - _, err := c.ddp.Call("leaveRoom", roomId) +func (c *Client) LeaveChannel(roomID string) error { + _, err := c.ddp.Call("leaveRoom", roomID) if err != nil { return err } @@ -164,8 +165,8 @@ func (c *Client) LeaveChannel(roomId string) error { // Takes roomId // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/archive-rooms -func (c *Client) ArchiveChannel(roomId string) error { - _, err := c.ddp.Call("archiveRoom", roomId) +func (c *Client) ArchiveChannel(roomID string) error { + _, err := c.ddp.Call("archiveRoom", roomID) if err != nil { return err } @@ -177,8 +178,8 @@ func (c *Client) ArchiveChannel(roomId string) error { // Takes roomId // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/unarchive-rooms -func (c *Client) UnArchiveChannel(roomId string) error { - _, err := c.ddp.Call("unarchiveRoom", roomId) +func (c *Client) UnArchiveChannel(roomID string) error { + _, err := c.ddp.Call("unarchiveRoom", roomID) if err != nil { return err } @@ -190,8 +191,8 @@ func (c *Client) UnArchiveChannel(roomId string) error { // Takes roomId // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/delete-rooms -func (c *Client) DeleteChannel(roomId string) error { - _, err := c.ddp.Call("eraseRoom", roomId) +func (c *Client) DeleteChannel(roomID string) error { + _, err := c.ddp.Call("eraseRoom", roomID) if err != nil { return err } @@ -203,8 +204,8 @@ func (c *Client) DeleteChannel(roomId string) error { // takes roomId and topic // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/save-room-settings -func (c *Client) SetChannelTopic(roomId string, topic string) error { - _, err := c.ddp.Call("saveRoomSettings", roomId, "roomTopic", topic) +func (c *Client) SetChannelTopic(roomID string, topic string) error { + _, err := c.ddp.Call("saveRoomSettings", roomID, "roomTopic", topic) if err != nil { return err } @@ -216,8 +217,8 @@ func (c *Client) SetChannelTopic(roomId string, topic string) error { // takes roomId and roomType // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/save-room-settings -func (c *Client) SetChannelType(roomId string, roomType string) error { - _, err := c.ddp.Call("saveRoomSettings", roomId, "roomType", roomType) +func (c *Client) SetChannelType(roomID string, roomType string) error { + _, err := c.ddp.Call("saveRoomSettings", roomID, "roomType", roomType) if err != nil { return err } @@ -226,11 +227,11 @@ func (c *Client) SetChannelType(roomId string, roomType string) error { } // SetChannelJoinCode sets channel join code -// takes roomId and joinCode +// takes roomID and joinCode // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/save-room-settings -func (c *Client) SetChannelJoinCode(roomId string, joinCode string) error { - _, err := c.ddp.Call("saveRoomSettings", roomId, "joinCode", joinCode) +func (c *Client) SetChannelJoinCode(roomID string, joinCode string) error { + _, err := c.ddp.Call("saveRoomSettings", roomID, "joinCode", joinCode) if err != nil { return err } @@ -242,8 +243,8 @@ func (c *Client) SetChannelJoinCode(roomId string, joinCode string) error { // takes roomId and boolean // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/save-room-settings -func (c *Client) SetChannelReadOnly(roomId string, readOnly bool) error { - _, err := c.ddp.Call("saveRoomSettings", roomId, "readOnly", readOnly) +func (c *Client) SetChannelReadOnly(roomID string, readOnly bool) error { + _, err := c.ddp.Call("saveRoomSettings", roomID, "readOnly", readOnly) if err != nil { return err } @@ -255,8 +256,8 @@ func (c *Client) SetChannelReadOnly(roomId string, readOnly bool) error { // takes roomId and description // // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/save-room-settings -func (c *Client) SetChannelDescription(roomId string, description string) error { - _, err := c.ddp.Call("saveRoomSettings", roomId, "roomDescription", description) +func (c *Client) SetChannelDescription(roomID string, description string) error { + _, err := c.ddp.Call("saveRoomSettings", roomID, "roomDescription", description) if err != nil { return err } diff --git a/realtime/client.go b/realtime/client.go index 00705a7..ae89eb4 100644 --- a/realtime/client.go +++ b/realtime/client.go @@ -20,11 +20,11 @@ type Client struct { func NewClient(serverUrl *url.URL, debug bool) (*Client, error) { rand.Seed(time.Now().UTC().UnixNano()) - wsUrl := "ws" + wsURL := "ws" port := 80 if serverUrl.Scheme == "https" { - wsUrl = "wss" + wsURL = "wss" port = 443 } @@ -32,12 +32,12 @@ func NewClient(serverUrl *url.URL, debug bool) (*Client, error) { port, _ = strconv.Atoi(serverUrl.Port()) } - wsUrl = fmt.Sprintf("%s://%v:%v/websocket", wsUrl, serverUrl.Hostname(), port) + wsURL = fmt.Sprintf("%s://%v:%v/websocket", wsURL, serverUrl.Hostname(), port) - log.Println("About to connect to:", wsUrl, port, serverUrl.Scheme) + log.Println("About to connect to:", wsURL, port, serverUrl.Scheme) c := new(Client) - c.ddp = ddp.NewClient(wsUrl, serverUrl.String()) + c.ddp = ddp.NewClient(wsURL, serverUrl.String()) if debug { c.ddp.SetSocketLogActive(true) diff --git a/realtime/settings.go b/realtime/settings.go index 2eec288..0bd075c 100644 --- a/realtime/settings.go +++ b/realtime/settings.go @@ -41,7 +41,7 @@ func (c *Client) GetPublicSettings() ([]models.Setting, error) { setting.ValueInt = rawSetting.Path("value").Data().(float64) case "asset": setting.ValueAsset = models.Asset{ - DefaultUrl: stringOrZero(rawSetting.Path("value").Data().(map[string]interface{})["defaultUrl"]), + DefaultURL: stringOrZero(rawSetting.Path("value").Data().(map[string]interface{})["defaultUrl"]), } default: diff --git a/realtime/subscriptions.go b/realtime/subscriptions.go index 3b0c34c..8645d86 100644 --- a/realtime/subscriptions.go +++ b/realtime/subscriptions.go @@ -7,7 +7,7 @@ import ( "github.com/gopackage/ddp" ) -// Subscribes to stream-notify-logged +// Sub subscribes to stream-notify-logged // Returns a buffered channel // // https://rocket.chat/docs/developer-guides/realtime-api/subscriptions/stream-room-messages/ diff --git a/rest/Makefile b/rest/Makefile new file mode 100644 index 0000000..df8b6b7 --- /dev/null +++ b/rest/Makefile @@ -0,0 +1,48 @@ +ifeq ($(GOPATH),) + GOPATH := $(HOME)/go +endif + +#### VARIABLES #### +SHELL := /bin/bash + + +# Go parameters +GOCMD = go +GOCLEAN = $(GOCMD) clean +GOTEST = $(GOCMD) test +GOMETALINTER := $(BIN_DIR)/gometalinter +RICHGO := $(BIN_DIR)/richgo +CILINT := $(BIN_DIR)/golangci-lint +DEP := $(BIN_DIR)/dep +SRC = $(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -name '*test.go' ) + +#### RULES #### +#GNU meaning of all is to compile application and be the default. Prob shouldn't run +.PHONY: all +all: lint test + +.PHONY: test +test: $(RICHGO) + TZ="Australia/Brisbane" RICHGO_FORCE_COLOR=1 RICHGO_LOCAL=1 richgo test -v -cover + +$(RICHGO): + go get -u github.com/kyoh86/richgo + go install github.com/kyoh86/richgo + +$(GOMETALINTER): + go get -u github.com/alecthomas/gometalinter + gometalinter --install + +$(CILINT): + go get -u github.com/golangci/golangci-lint/cmd/golangci-lint + +.PHONY: lint +lint: $(CILINT) + golangci-lint run ./... + +$(DEP): + go get -u github.com/golang/dep/cmd/dep + +.PHONY: dep +dep: $(DEP) + dep ensure \ No newline at end of file diff --git a/rest/channels.go b/rest/channels.go index 6e52d55..765f081 100644 --- a/rest/channels.go +++ b/rest/channels.go @@ -8,17 +8,42 @@ import ( "github.com/RocketChat/Rocket.Chat.Go.SDK/models" ) +// ChannelsResponse used when returning channel lists type ChannelsResponse struct { Status models.Pagination Channels []models.Channel `json:"channels"` } +// ChannelResponse on a single channel type ChannelResponse struct { Status Channel models.Channel `json:"channel"` } +// MembersResponse on a single channel +type MembersResponse struct { + Status + models.Pagination + MembersList []models.Member `json:"members"` +} + +// ChannelArchive Archives a channel. +// +// https://rocket.chat/docs/developer-guides/rest-api/channels/archive +func (c *Client) ChannelArchive(channel *models.Channel) error { + var body = fmt.Sprintf(`{ "roomId": "%s"}`, channel.ID) + return c.Post("channels.archive", bytes.NewBufferString(body), new(ChannelResponse)) +} + +// ChannelUnarchive Unarchives a channel. +// +// https://rocket.chat/docs/developer-guides/rest-api/channels/unarchive +func (c *Client) ChannelUnarchive(channel *models.Channel) error { + var body = fmt.Sprintf(`{ "roomId": "%s"}`, channel.ID) + return c.Post("channels.unarchive", bytes.NewBufferString(body), new(ChannelResponse)) +} + // GetPublicChannels returns all channels that can be seen by the logged in user. // // https://rocket.chat/docs/developer-guides/rest-api/channels/list @@ -31,6 +56,23 @@ func (c *Client) GetPublicChannels() (*ChannelsResponse, error) { return response, nil } +// ChannelsCreate Creates a new public channel, +// optionally including specified users. The channel creator is always included. +// +// https://rocket.chat/docs/developer-guides/rest-api/channels/create +func (c *Client) ChannelsCreate(channel *models.Channel) error { + var body = fmt.Sprintf(`{ "name": "%s"}`, channel.Name) + return c.Post("channels.create", bytes.NewBufferString(body), new(ChannelResponse)) +} + +// ChannelClose Removes the channel from the user’s list of channels. +// +// https://rocket.chat/docs/developer-guides/rest-api/channels/create +func (c *Client) ChannelClose(channel *models.Channel) error { + var body = fmt.Sprintf(`{ "roomId": "%s"}`, channel.ID) + return c.Post("channels.close", bytes.NewBufferString(body), new(ChannelResponse)) +} + // GetJoinedChannels returns all channels that the user has joined. // // https://rocket.chat/docs/developer-guides/rest-api/channels/list-joined @@ -43,6 +85,14 @@ func (c *Client) GetJoinedChannels(params url.Values) (*ChannelsResponse, error) return response, nil } +// KickChannel Removes a user from the channel. +// +// https://rocket.chat/docs/developer-guides/rest-api/channels/kic +func (c *Client) KickChannel(channel *models.Channel) error { + var body = fmt.Sprintf(`{ "roomId": "%s", "userId": "%s"}`, channel.ID, channel.User.ID) + return c.Post("channels.kick", bytes.NewBufferString(body), new(ChannelResponse)) +} + // LeaveChannel leaves a channel. The id of the channel has to be not nil. // // https://rocket.chat/docs/developer-guides/rest-api/channels/leave @@ -51,6 +101,23 @@ func (c *Client) LeaveChannel(channel *models.Channel) error { return c.Post("channels.leave", bytes.NewBufferString(body), new(ChannelResponse)) } +// GetMembersList returns all channels that the user has joined. +// +// https://rocket.chat/docs/developer-guides/rest-api/channels/members/ +func (c *Client) GetMembersList(roomID string) (*MembersResponse, error) { + + params := url.Values{} + params.Add("roomId", roomID) + + response := new(MembersResponse) + + if err := c.Get("channels.members", params, response); err != nil { + return nil, err + } + + return response, nil +} + // GetChannelInfo get information about a channel. That might be useful to update the usernames. // // https://rocket.chat/docs/developer-guides/rest-api/channels/info @@ -59,6 +126,5 @@ func (c *Client) GetChannelInfo(channel *models.Channel) (*models.Channel, error if err := c.Get("channels.info", url.Values{"roomId": []string{channel.ID}}, response); err != nil { return nil, err } - return &response.Channel, nil } diff --git a/rest/channels_test.go b/rest/channels_test.go index c4f21da..be351cc 100644 --- a/rest/channels_test.go +++ b/rest/channels_test.go @@ -1,47 +1,734 @@ package rest import ( + "bytes" + "errors" + "io/ioutil" + "net/http" + "net/url" "testing" "github.com/RocketChat/Rocket.Chat.Go.SDK/models" "github.com/stretchr/testify/assert" ) -func TestRocket_GetPublicChannels(t *testing.T) { - rocket := getDefaultClient(t) +func TestRestService_ChannelArchivel(t *testing.T) { - resp, err := rocket.GetPublicChannels() - assert.Nil(t, err) - assert.NotZero(t, len(resp.Channels)) + type fields struct { + myDoer Doer + channel *models.Channel + } + tests := []struct { + name string + fields fields + wantErr error + }{ + { + name: "ChannelArchive OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "success": true + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + wantErr: nil, + }, + { + name: "ChannelArchive Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.ChannelArchive(tt.fields.channel) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + }) + } +} + +func TestRestService_ChannelUnarchive(t *testing.T) { + + type fields struct { + myDoer Doer + channel *models.Channel + } + tests := []struct { + name string + fields fields + wantErr error + }{ + { + name: "ChannelUnarchive OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "success": true + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + wantErr: nil, + }, + { + name: "ChannelUnarchive Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.ChannelUnarchive(tt.fields.channel) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + }) + } +} +func TestRestService_GetPublicChannels(t *testing.T) { + + type fields struct { + myDoer Doer + } + tests := []struct { + name string + fields fields + want ChannelsResponse + wantErr error + }{ + { + name: "GetPublicChannels OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "channels": [ + { + "_id": "ByehQjC44FwMeiLbX", + "name": "test-test", + "t": "c", + "usernames": [ + "testing1" + ], + "msgs": 0, + "u": { + "_id": "aobEdbYhXfu5hkeqG", + "username": "testing1" + }, + "ts": "2016-12-09T15:08:58.042Z", + "ro": false, + "sysMes": true, + "_updatedAt": "2016-12-09T15:22:40.656Z" + }, + { + "_id": "t7qapfhZjANMRAi5w", + "name": "testing", + "t": "c", + "usernames": [ + "testing2" + ], + "msgs": 0, + "u": { + "_id": "y65tAmHs93aDChMWu", + "username": "testing2" + }, + "ts": "2016-12-01T15:08:58.042Z", + "ro": false, + "sysMes": true, + "_updatedAt": "2016-12-09T15:22:40.656Z" + } + ], + "success": true + }`, + }, + }, + want: ChannelsResponse{ + Channels: []models.Channel{ + models.Channel{ID: "ByehQjC44FwMeiLbX", Name: "test-test"}, + models.Channel{ID: "t7qapfhZjANMRAi5w", Name: "testing"}, + }, + }, + wantErr: nil, + }, + { + name: "GetPublicChannels Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + }, + want: ChannelsResponse{ + Channels: []models.Channel{ + models.Channel{ID: "ByehQjC44FwMeiLbX", Name: "invite-me"}, + }, + }, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetPublicChannels() + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + if err == nil { + //ToDO : needs a better test ! + assert.NotNil(t, got) + assert.Equal(t, got.Channels[0].ID, tt.want.Channels[0].ID, "ID did not match") + assert.Equal(t, got.Channels[0].Name, tt.want.Channels[0].Name, "Name did not match") + } + }) + } +} + +func TestRestService_GetJoinedChannels(t *testing.T) { + + type fields struct { + myDoer Doer + params url.Values + } + tests := []struct { + name string + fields fields + want ChannelsResponse + wantErr error + }{ + { + name: "GetJoinedChannels OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "channels": [ + { + "_id": "ByehQjC44FwMeiLbX", + "name": "invite-me", + "t": "c", + "usernames": [ + "testing1" + ], + "msgs": 0, + "u": { + "_id": "aobEdbYhXfu5hkeqG", + "username": "testing1" + }, + "ts": "2016-12-09T15:08:58.042Z", + "ro": false, + "sysMes": true, + "_updatedAt": "2016-12-09T15:22:40.656Z" + } + ], + "offset": 0, + "count": 2, + "total": 2, + "success": true + }`, + }, + params: url.Values{}, + }, + want: ChannelsResponse{ + Channels: []models.Channel{ + models.Channel{ID: "ByehQjC44FwMeiLbX", Name: "invite-me"}, + }, + }, + wantErr: nil, + }, + { + name: "GetJoinedChannels Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + params: url.Values{}, + }, + want: ChannelsResponse{ + Channels: []models.Channel{ + models.Channel{ID: "ByehQjC44FwMeiLbX", Name: "invite-me"}, + }, + }, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetJoinedChannels(tt.fields.params) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + if err == nil { + //ToDO : needs a better test ! + assert.NotNil(t, got) + assert.Equal(t, got.Channels[0].ID, tt.want.Channels[0].ID, "ID did not match") + assert.Equal(t, got.Channels[0].Name, tt.want.Channels[0].Name, "Name did not match") + } + }) + } +} + +func TestRestService_LeaveChannel(t *testing.T) { + + type fields struct { + myDoer Doer + channel *models.Channel + } + tests := []struct { + name string + fields fields + want ChannelsResponse + wantErr error + }{ + { + name: "LeaveChannel OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "channel": { + "_id": "ByehQjC44FwMeiLbX", + "name": "invite-me", + "t": "c", + "usernames": [ + "testing2" + ], + "msgs": 0, + "u": { + "_id": "aobEdbYhXfu5hkeqG", + "username": "testing1" + }, + "ts": "2016-12-09T15:08:58.042Z", + "ro": false, + "sysMes": true, + "_updatedAt": "2016-12-09T15:22:40.656Z" + }, + "success": true + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + want: ChannelsResponse{ + Channels: []models.Channel{ + models.Channel{ID: "ByehQjC44FwMeiLbX", Name: "invite-me"}, + }, + }, + wantErr: nil, + }, + { + name: "LeaveChannel Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + want: ChannelsResponse{ + Channels: []models.Channel{ + models.Channel{ID: "ByehQjC44FwMeiLbX", Name: "invite-me"}, + }, + }, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.LeaveChannel(tt.fields.channel) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + }) + } +} + +type testDoer struct { + response string + responseCode int + http.Header +} + +func (nd testDoer) Do(*http.Request) (*http.Response, error) { + return &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte(nd.response))), + StatusCode: nd.responseCode, + Header: nd.Header, + }, nil +} + +func CreateTestRestClient(d Doer) *Client { + rockerServer := &url.URL{Host: "rocketchat.localhost", Scheme: "https"} + client := NewClient(rockerServer, false) + client.myDoer = d + return client } -func TestRocket_GetJoinedChannels(t *testing.T) { - rocket := getDefaultClient(t) +func TestRestService_GetMembersList(t *testing.T) { - resp, err := rocket.GetJoinedChannels(nil) - assert.Nil(t, err) - assert.NotZero(t, len(resp.Channels)) + type fields struct { + myDoer Doer + roomID string + } + tests := []struct { + name string + fields fields + want MembersResponse + wantErr error + }{ + { + name: "GetMembersList OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "members": [ + { + "_id": "Loz7qh9ChSqHMPymx", + "username": "customField_apiuser.test.1529436896005", + "name": "customField_apiuser.test.1529436896005", + "status": "offline" + }, + { + "_id": "Zc3Y3cRW7ZtS7Y8Hk", + "username": "customField_apiuser.test.1529436997563", + "name": "customField_apiuser.test.1529436997563", + "status": "offline" + } + ], + "count": 2, + "offset": 0, + "total": 35, + "success": true + }`, + }, + roomID: "GENERAL", + }, + want: MembersResponse{ + Status: Status{Status: "OK"}, + Pagination: models.Pagination{Count: 2, Offset: 0, Total: 35}, + MembersList: []models.Member{ + models.Member{ + ID: "Loz7qh9ChSqHMPymx", + Username: "customField_apiuser.test.1529436896005", + Name: "customField_apiuser.test.1529436896005", + Status: "offline"}, + models.Member{ + ID: "Zc3Y3cRW7ZtS7Y8Hk", + Username: "customField_apiuser.test.1529436997563", + Name: "customField_apiuser.test.1529436997563", + Status: "offline"}, + }, + }, + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetMembersList(tt.fields.roomID) + + assert.Equal(t, tt.wantErr, err, "Unexpected error") + assert.Equal(t, tt.want.Count, got.Count, "Member count dose not match") + assert.Equal(t, got.MembersList, tt.want.MembersList, "MembersList did not match") + + }) + } } -func TestRocket_LeaveChannel(t *testing.T) { - rocket := getDefaultClient(t) +func TestRestService_GetChannelInfo(t *testing.T) { + + type fields struct { + myDoer Doer + channel *models.Channel + } + tests := []struct { + name string + fields fields + want models.Channel + wantErr error + }{ + { + name: "GetChannelInfo OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "channel": { + "_id": "ByehQjC44FwMeiLbX", + "ts": "2016-11-30T21:23:04.737Z", + "t": "c", + "name": "testing", + "usernames": [ + "testing", + "testing1", + "testing2" + ], + "msgs": 1, + "default": true, + "_updatedAt": "2016-12-09T12:50:51.575Z", + "lm": "2016-12-09T12:50:51.555Z" + }, + "success": true + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + want: models.Channel{ + ID: "ByehQjC44FwMeiLbX", + Name: "testing", + Type: "c", + }, + wantErr: nil, + }, + { + name: "GetChannelInfo Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + want: models.Channel{}, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetChannelInfo(tt.fields.channel) - general := &models.Channel{ID: "GENERAL"} - err := rocket.LeaveChannel(general) - assert.Nil(t, err) + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + if err == nil { + assert.NotNil(t, got) + assert.Equal(t, got.ID, tt.want.ID, "ID did not match") + assert.Equal(t, got.Name, tt.want.Name, "Name did not match") + assert.Equal(t, got.Type, tt.want.Type, "Name did not match") + } + }) + } } -func TestRocket_GetChannelInfo(t *testing.T) { - rocket := getDefaultClient(t) +func TestRestService_KickChannel(t *testing.T) { + + type fields struct { + myDoer Doer + channel *models.Channel + } + tests := []struct { + name string + fields fields + wantErr error + }{ + { + name: "KickChannel OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "channel": { + "_id": "ByehQjC44FwMeiLbX", + "name": "invite-me", + "t": "c", + "usernames": [ + "testing1" + ], + "msgs": 0, + "u": { + "_id": "aobEdbYhXfu5hkeqG", + "username": "testing1" + }, + "ts": "2016-12-09T15:08:58.042Z", + "ro": false, + "sysMes": true, + "_updatedAt": "2016-12-09T15:22:40.656Z" + }, + "success": true + }`, + }, + channel: &models.Channel{ + ID: "GENERAL", + User: &models.User{ID: "nSYqWzZ4GsKTX4dyK"}, + }, + }, + wantErr: nil, + }, + { + name: "KickChannel Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + channel: &models.Channel{ + ID: "GENERAL", + User: &models.User{ID: "nSYqWzZ4GsKTX4dyK"}, + }, + }, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.KickChannel(tt.fields.channel) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + }) + } +} + +func TestRestService_ChannelsCreate(t *testing.T) { + + type fields struct { + myDoer Doer + channel *models.Channel + } + tests := []struct { + name string + fields fields + wantErr error + }{ + { + name: "ChannelsCreate OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "channel": { + "_id": "ByehQjC44FwMeiLbX", + "name": "channelname", + "t": "c", + "usernames": [ + "example" + ], + "msgs": 0, + "u": { + "_id": "aobEdbYhXfu5hkeqG", + "username": "example" + }, + "ts": "2016-05-30T13:42:25.304Z" + }, + "success": true + }`, + }, + channel: &models.Channel{Name: "channelname"}, + }, + wantErr: nil, + }, + { + name: "ChannelsCreate Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.ChannelsCreate(tt.fields.channel) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + }) + } +} + +func TestRestService_ChannelClose(t *testing.T) { + + type fields struct { + myDoer Doer + channel *models.Channel + } + tests := []struct { + name string + fields fields + wantErr error + }{ + { + name: "ChannelClose OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "success": true + }`, + }, + channel: &models.Channel{ID: "ByehQjC44FwMeiLbX"}, + }, + wantErr: nil, + }, + { + name: "ChannelClose Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "you must be logged in to do this" + }`, + }, + channel: &models.Channel{ID: "ByehQjC44FwMeiLbX"}, + }, + wantErr: errors.New("status: error, message: you must be logged in to do this"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.ChannelClose(tt.fields.channel) - general := &models.Channel{ID: "GENERAL"} - updatedChannelInfo, err := rocket.GetChannelInfo(general) - assert.Nil(t, err) - assert.NotNil(t, updatedChannelInfo) + assert.Equal(t, err, tt.wantErr, "Unexpected error") - assert.Equal(t, general.ID, updatedChannelInfo.ID) - assert.NotEmpty(t, updatedChannelInfo.Name) - assert.NotEmpty(t, updatedChannelInfo.Type) - assert.NotEmpty(t, updatedChannelInfo.UpdatedAt) - assert.NotEmpty(t, updatedChannelInfo.Timestamp) + }) + } } diff --git a/rest/client.go b/rest/client.go index fdf97fa..e320ac4 100644 --- a/rest/client.go +++ b/rest/client.go @@ -14,25 +14,43 @@ import ( ) var ( - ResponseErr = fmt.Errorf("got false response") + // ErrResponse for general responice errors + ErrResponse = fmt.Errorf("got false response") ) +// Response is everythuing is ok ? type Response interface { OK() error } +// Client ... type Client struct { Protocol string Host string Port string Version string + // http interface can be used when testing + myDoer Doer + + service + // Use this switch to see all network communication. Debug bool auth *authInfo } +// Doer to make testing easer ! +type Doer interface { + Do(*http.Request) (*http.Response, error) +} + +type service struct { + client *Client +} + +// Status ... type Status struct { Success bool `json:"success"` Error string `json:"error"` @@ -46,6 +64,7 @@ type authInfo struct { id string } +// OK ... func (s Status) OK() error { if s.Success { return nil @@ -62,7 +81,7 @@ func (s Status) OK() error { if len(s.Message) > 0 { return fmt.Errorf("status: %s, message: %s", s.Status, s.Message) } - return ResponseErr + return ErrResponse } // StatusResponse The base for the most of the json responses @@ -71,23 +90,33 @@ type StatusResponse struct { Channel string `json:"channel"` } -func NewClient(serverUrl *url.URL, debug bool) *Client { +// NewClient ... +func NewClient(serverURL *url.URL, debug bool) (c *Client) { protocol := "http" port := "80" - if serverUrl.Scheme == "https" { + if serverURL.Scheme == "https" { protocol = "https" port = "443" } - if len(serverUrl.Port()) > 0 { - port = serverUrl.Port() + if len(serverURL.Port()) > 0 { + port = serverURL.Port() } - return &Client{Host: serverUrl.Hostname(), Port: port, Protocol: protocol, Version: "v1", Debug: debug} + c.Host = serverURL.Hostname() + c.Port = port + c.Protocol = protocol + c.Version = "v1" + c.Debug = debug + + // set default http interface to use + c.myDoer = http.DefaultClient + + return } -func (c *Client) getUrl() string { +func (c *Client) getURL() string { if len(c.Version) == 0 { c.Version = "v1" } @@ -119,7 +148,7 @@ func (c *Client) doRequest(method, api string, params url.Values, body io.Reader } } - request, err := http.NewRequest(method, c.getUrl()+"/"+api, body) + request, err := http.NewRequest(method, c.getURL()+"/"+api, body) if err != nil { return err } @@ -141,7 +170,7 @@ func (c *Client) doRequest(method, api string, params url.Values, body io.Reader log.Println(request) } - resp, err := http.DefaultClient.Do(request) + resp, err := c.myDoer.Do(request) if err != nil { return err diff --git a/rest/client_test.go b/rest/client_test.go index 3b7add1..60654c3 100644 --- a/rest/client_test.go +++ b/rest/client_test.go @@ -1,6 +1,8 @@ package rest import ( + "errors" + "io" "net/url" "testing" @@ -11,23 +13,25 @@ import ( ) var ( - testUserName string - testUserEmail string - testPassword = "test" - rocketClient *Client + testUserName string // nolint + testUserEmail string // nolint + testPassword = "test" // nolint + testClient *Client // nolint ) -func getDefaultClient(t *testing.T) *Client { +// nolint - deadcode ! +func getDefaultClient(t *testing.T) (c *Client) { - if rocketClient == nil { + if testClient == nil { testUserEmail = common_testing.GetRandomEmail() testUserName = common_testing.GetRandomString() - rocketClient = getAuthenticatedClient(t, testUserName, testUserEmail, testPassword) + c = getAuthenticatedClient(t, testUserName, testUserEmail, testPassword) } - return rocketClient + return c } +// nolint is unused func getAuthenticatedClient(t *testing.T, name, email, password string) *Client { client := Client{Protocol: common_testing.Protocol, Host: common_testing.Host, Port: common_testing.Port} credentials := &models.UserCredentials{Name: name, Email: email, Password: password} @@ -43,6 +47,7 @@ func getAuthenticatedClient(t *testing.T, name, email, password string) *Client return &client } +// nolint - deadcode ! func findMessage(messages []models.Message, user string, msg string) *models.Message { var m *models.Message for i := range messages { @@ -55,6 +60,7 @@ func findMessage(messages []models.Message, user string, msg string) *models.Mes return nil } +// nolint - deadcode ! func getChannel(channels []models.Channel, name string) *models.Channel { for _, r := range channels { if r.Name == name { @@ -64,3 +70,322 @@ func getChannel(channels []models.Channel, name string) *models.Channel { return nil } + +func TestRestService_getURL(t *testing.T) { + type fields struct { + myDoer Doer + protocol string + host string + port string + version string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "Full", + fields: fields{ + myDoer: testDoer{}, + host: "rocketchat.localhost", + protocol: "https", + port: "443", + version: "v1", + }, + want: "https://rocketchat.localhost:443/api/v1", + }, + { + name: "host", + fields: fields{ + myDoer: testDoer{}, + host: "rocketchat.localhost", + }, + want: "://rocketchat.localhost:/api/v1", + }, + { + name: "protocol", + fields: fields{ + myDoer: testDoer{}, + protocol: "https", + }, + want: "https://:/api/v1", + }, + { + name: "port", + fields: fields{ + myDoer: testDoer{}, + port: "443", + }, + want: "://:443/api/v1", + }, + { + name: "version", + fields: fields{ + myDoer: testDoer{}, + version: "v1", + }, + want: "://:/api/v1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + rt.Host = tt.fields.host + rt.Protocol = tt.fields.protocol + rt.Port = tt.fields.port + rt.Version = tt.fields.version + got := rt.getURL() + + assert.Equal(t, got, tt.want, "Unexpected error") + }) + } +} + +func TestRestService_Get(t *testing.T) { + type fields struct { + myDoer Doer + } + type args struct { + api string + params url.Values + response Response + } + tests := []struct { + name string + fields fields + args args + wantErr error + }{ + { + name: "Ok", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{"success": true}`, + }, + }, + args: args{ + api: "", + params: url.Values{"query": []string{`#foobar`}}, + response: new(InfoResponse), + }, + wantErr: nil, + }, + { + name: "Err 200", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{"success": false}`, + }, + }, + args: args{ + api: "", + params: url.Values{"query": []string{`#foobar`}}, + response: new(InfoResponse), + }, + wantErr: errors.New("got false response"), + }, + { + name: "Err 500", + fields: fields{ + myDoer: testDoer{ + responseCode: 500, + response: ``, + }, + }, + args: args{ + api: "", + params: url.Values{"query": []string{`#foobar`}}, + response: new(InfoResponse), + }, + wantErr: errors.New("Request error: "), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.Get(tt.args.api, tt.args.params, tt.args.response) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + }) + } +} + +func TestRestService_Post(t *testing.T) { + type fields struct { + myDoer Doer + } + type args struct { + api string + body io.Reader + response Response + } + tests := []struct { + name string + fields fields + args args + wantErr error + }{ + { + name: "Ok", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{"success": true}`, + }, + }, + args: args{ + api: "", + body: nil, + response: new(InfoResponse), + }, + wantErr: nil, + }, + { + name: "Err 200", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{"success": false}`, + }, + }, + args: args{ + api: "", + body: nil, + response: new(InfoResponse), + }, + wantErr: errors.New("got false response"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.Post(tt.args.api, tt.args.body, tt.args.response) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + }) + } +} + +func TestRestService_PostForm(t *testing.T) { + type fields struct { + myDoer Doer + } + type args struct { + api string + params url.Values + response Response + } + tests := []struct { + name string + fields fields + args args + wantErr error + }{ + { + name: "Ok", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{"success": true}`, + }, + }, + args: args{ + api: "", + params: url.Values{"query": []string{`#foobar`}}, + response: new(InfoResponse), + }, + wantErr: nil, + }, + { + name: "Err 200", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{"success": false}`, + }, + }, + args: args{ + api: "", + params: url.Values{"query": []string{`#foobar`}}, + response: new(InfoResponse), + }, + wantErr: errors.New("got false response"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.PostForm(tt.args.api, tt.args.params, tt.args.response) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + }) + } +} + +func TestRestService_doRequest(t *testing.T) { + type fields struct { + myDoer Doer + } + type args struct { + method string + api string + params url.Values + body io.Reader + response Response + } + tests := []struct { + name string + fields fields + args args + wantErr error + }{ + { + name: "Ok", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{"success": true}`, + }, + }, + args: args{ + method: "GET", + api: "", + params: url.Values{"query": []string{`#foobar`}}, + body: nil, + response: new(InfoResponse), + }, + wantErr: nil, + }, + { + name: "Err 200", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{"success": false}`, + }, + }, + args: args{ + method: "GET", + api: "", + params: url.Values{"query": []string{`#foobar`}}, + body: nil, + response: new(InfoResponse), + }, + wantErr: errors.New("got false response"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.doRequest(tt.args.method, tt.args.api, tt.args.params, tt.args.body, tt.args.response) + assert.Equal(t, err, tt.wantErr, "Unexpected error") + }) + } +} diff --git a/rest/information.go b/rest/information.go index 4ab2b95..eefca5d 100644 --- a/rest/information.go +++ b/rest/information.go @@ -6,6 +6,7 @@ import ( "github.com/RocketChat/Rocket.Chat.Go.SDK/models" ) +// InfoResponse retired by GetServerInfo type InfoResponse struct { Status Info models.Info `json:"info"` @@ -24,6 +25,7 @@ func (c *Client) GetServerInfo() (*models.Info, error) { return &response.Info, nil } +// DirectoryResponse for GetDirectory type DirectoryResponse struct { Status models.Directory @@ -42,6 +44,7 @@ func (c *Client) GetDirectory(params url.Values) (*models.Directory, error) { return &response.Directory, nil } +// SpotlightResponse for GetSpotlight type SpotlightResponse struct { Status models.Spotlight @@ -60,17 +63,18 @@ func (c *Client) GetSpotlight(params url.Values) (*models.Spotlight, error) { return &response.Spotlight, nil } +// StatisticsResponse used with GetStatistics type StatisticsResponse struct { Status models.StatisticsInfo } -// GetStatistics -// Statistics about the Rocket.Chat server. +// GetStatistics statistics about the Rocket.Chat server. // // https://rocket.chat/docs/developer-guides/rest-api/miscellaneous/statistics func (c *Client) GetStatistics() (*models.StatisticsInfo, error) { response := new(StatisticsResponse) + if err := c.Get("statistics", nil, response); err != nil { return nil, err } @@ -78,16 +82,16 @@ func (c *Client) GetStatistics() (*models.StatisticsInfo, error) { return &response.StatisticsInfo, nil } +// StatisticsListResponse statistics about the Rocket.Chat server. type StatisticsListResponse struct { Status models.StatisticsList } -// GetStatisticsList -// Selectable statistics about the Rocket.Chat server. +// GetStatisticsList selectable statistics about the Rocket.Chat server. // It supports the Offset, Count and Sort Query Parameters along with just the Fields and Query Parameters. // -// https://rocket.chat/docs/developer-guides/rest-api/miscellaneous/statistics.list +// https://rocket.chat/docs/developer-guides/rest-api/miscellaneous/statistics-list func (c *Client) GetStatisticsList(params url.Values) (*models.StatisticsList, error) { response := new(StatisticsListResponse) if err := c.Get("statistics.list", params, response); err != nil { diff --git a/rest/information_test.go b/rest/information_test.go index c943dc0..6887e39 100644 --- a/rest/information_test.go +++ b/rest/information_test.go @@ -1,57 +1,642 @@ package rest import ( + "errors" "net/url" "testing" - "github.com/RocketChat/Rocket.Chat.Go.SDK/common_testing" + "github.com/RocketChat/Rocket.Chat.Go.SDK/models" "github.com/stretchr/testify/assert" ) func TestRocket_GetServerInfo(t *testing.T) { - rocket := Client{Protocol: common_testing.Protocol, Host: common_testing.Host, Port: common_testing.Port} - info, err := rocket.GetServerInfo() + type fields struct { + myDoer Doer + } + tests := []struct { + name string + fields fields + want models.Info + wantErr error + }{ + { + name: "Version match Ok", + fields: fields{ + testDoer{ + responseCode: 200, + response: `{ + "success": true, + "info": { + "version": "0.47.0-develop", + "build": { + "nodeVersion": "v4.6.2", + "arch": "x64", + "platform": "linux", + "cpus": 4 + }, + "commit": { + "hash": "5901cc7270e3587101631ee222def950d705c611", + "date": "Thu Dec 1 19:08:01 2016 -0200", + "author": "Gabriel Engel", + "subject": "Merge branch 'develop' into experimental", + "tag": "0.46.0", + "branch": "experimental" + } + } + }`, + }, + }, + want: models.Info{ + Version: "0.47.0-develop", + }, + wantErr: nil, + }, + { + name: "Version err", + fields: fields{ + testDoer{ + responseCode: 200, + response: `{ + "success": false + }`, + }, + }, + want: models.Info{ + Version: "0.47.0-develop", + }, + wantErr: errors.New("got false response"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetServerInfo() - assert.Nil(t, err) - assert.NotNil(t, info) - assert.NotEmpty(t, info.Version) + assert.Equal(t, err, tt.wantErr, "Unexpected error") + if err == nil { + assert.Equal(t, tt.want.Version, got.Version, "Version not matching") + } + + }) + } } func TestRocket_GetDirectory(t *testing.T) { - rocket := getDefaultClient(t) - directory, err := rocket.GetDirectory(url.Values{"query": []string{`{"text": "gene", "type": "channels"}`}}) + type fields struct { + myDoer Doer + params url.Values + } + tests := []struct { + name string + fields fields + want models.Directory + wantErr error + }{ + { + name: "channels OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "result": [ + { + "_id": "GENERAL", + "ts": "2018-08-23T01:39:00.881Z", + "name": "general", + "usersCount": 11, + "lastMessage": { + "alias": null, + "msg": "", + "attachments": [ + { + "title": "Gify", + "image_url": "https://media0.giphy.com/media/3ohc11UljvpPKWeNva/giphy.gif?cid=e1bb72ff5b7fa6964c576d2f6b464d03", + "color": "#225159" + } + ], + "parseUrls": false, + "bot": { + "i": "h3m3p69QjBtgDgABp" + }, + "groupable": false, + "ts": "2018-08-24T06:32:55.154Z", + "u": { + "_id": "z5fLnYsiYZzREohkE", + "username": "bradb", + "name": null + }, + "rid": "GENERAL", + "mentions": [], + "channels": [], + "_updatedAt": "2018-08-24T06:32:55.156Z", + "_id": "Pt7RsaNSDAE7tJH6t", + "sandstormSessionId": null + } + } + ], + "count": 1, + "offset": 0, + "total": 1, + "success": true + }`, + }, + params: url.Values{"query": []string{`{"text": "gene", "type": "channels"}`}}, + }, + want: models.Directory{ + Pagination: models.Pagination{Count: 1, Offset: 0, Total: 1}, + }, + wantErr: nil, + }, + { + name: "users OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "result": [ + { + "_id": "rocket.cat", + "createdAt": "2018-08-23T01:39:00.958Z", + "name": "Rocket.Cat", + "username": "rocket.cat" + }, + { + "_id": "7foMpeuHzfW5Npoqg", + "createdAt": "2018-08-23T01:53:05.715Z", + "emails": [ + { + "address": "rocketchat@localhost", + "verified": false + } + ], + "name": "Rocket Admin", + "username": "rocketadmin" + } + ], + "count": 2, + "offset": 0, + "total": 2, + "success": true + }`, + }, + params: url.Values{"query": []string{`{"text": "rocket", "type": "users"}`}}, + }, + want: models.Directory{ + Pagination: models.Pagination{Count: 2, Offset: 0, Total: 2}, + }, + wantErr: nil, + }, + { + name: "users err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "result": [ + { + "_id": "rocket.cat", + "createdAt": "2018-08-23T01:39:00.958Z", + "name": "Rocket.Cat", + "username": "rocket.cat" + }, + { + "_id": "7foMpeuHzfW5Npoqg", + "createdAt": "2018-08-23T01:53:05.715Z", + "emails": [ + { + "address": "rocketchat@localhost", + "verified": false + } + ], + "name": "Rocket Admin", + "username": "rocketadmin" + } + ], + "count": 2, + "offset": 0, + "total": 2, + "success": false + }`, + }, + params: url.Values{"query": []string{`{"text": "rocket", "type": "users"}`}}, + }, + want: models.Directory{}, + wantErr: errors.New("got false response"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetDirectory(tt.fields.params) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") - assert.Nil(t, err) - assert.NotNil(t, directory) + if err == nil { + assert.Equal(t, got.Pagination.Count, tt.want.Pagination.Count, "Incorrect Pagination Count") + assert.Equal(t, got.Pagination.Offset, tt.want.Pagination.Offset, "Incorrect Pagination Offset") + assert.Equal(t, got.Pagination.Total, tt.want.Pagination.Total, "Incorrect Pagination Total") + assert.NotNil(t, got) + //ToDO : needs a better test ! + // assert.Equal(t, got, tt.want, "Unexpected error") + } + }) + } } func TestRocket_GetSpotlight(t *testing.T) { - rocket := getDefaultClient(t) - spotlight, err := rocket.GetSpotlight(url.Values{"query": []string{`#foobar`}}) + type fields struct { + myDoer Doer + params url.Values + } + tests := []struct { + name string + fields fields + want models.Spotlight + wantErr error + }{ + { + name: "GetSpotlight OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "users": [ + { + "_id": "rocket.cat", + "name": "Rocket.Cat", + "username": "rocket.cat", + "status": "online" + } + ], + "rooms": [], + "success": true + }`, + }, + params: url.Values{"query": []string{`#foobar`}}, + }, + want: models.Spotlight{ + Users: []models.User{ + models.User{ + ID: "rocket.cat", + Name: "Rocket.Cat", + UserName: "rocket.cat", + Status: "online", + Token: "", + TokenExpires: 0}, + }, + Rooms: []models.Channel{}, + }, + wantErr: nil, + }, + { + name: "GetSpotlight err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "users": [ + { + "_id": "rocket.cat", + "name": "Rocket.Cat", + "username": "rocket.cat", + "status": "online" + } + ], + "rooms": [], + "success": false + }`, + }, + params: url.Values{"query": []string{`#foobar`}}, + }, + want: models.Spotlight{}, + wantErr: errors.New("got false response"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetSpotlight(tt.fields.params) - assert.Nil(t, err) - assert.NotNil(t, spotlight) + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + if err == nil { + assert.NotNil(t, got) + assert.Equal(t, got.Users[0].ID, tt.want.Users[0].ID, "ID did not match") + assert.Equal(t, got.Users[0].Name, tt.want.Users[0].Name, "Name did not match") + assert.Equal(t, got.Users[0].UserName, tt.want.Users[0].UserName, "UserName did not match") + assert.Equal(t, got.Users[0].Status, tt.want.Users[0].Status, "Name did not match") + } + }) + } } func TestRocket_GetStatistics(t *testing.T) { - rocket := Client{Protocol: common_testing.Protocol, Host: common_testing.Host, Port: common_testing.Port} - // TODO admin user - rocket.auth = &authInfo{id: "4SicoW2wDjcAaRh4M", token: "4nI24JkcHTsqTtOUeJYbbrhum5T_Y6IdjAwyj72qDBu"} - statistics, err := rocket.GetStatistics() - assert.Nil(t, err) - assert.NotNil(t, statistics) + type fields struct { + myDoer Doer + } + tests := []struct { + name string + fields fields + want models.StatisticsInfo + wantErr error + }{ + { + name: "Statistics OK", + fields: fields{ + testDoer{ + responseCode: 200, + response: `{ + "statistics": { + "_id":"wufRdmSrjmSMhBdTN", + "uniqueId":"wD4EP3M7FeFzJZgk9", + "installedAt":"2018-02-18T19:40:45.369Z", + "version":"0.61.0-develop", + "totalUsers":88, + "activeUsers":88, + "nonActiveUsers":0, + "onlineUsers":0, + "awayUsers":1, + "offlineUsers":87, + "totalRooms":81, + "totalChannels":41, + "totalPrivateGroups":37, + "totalDirect":3, + "totlalLivechat":0, + "totalMessages":2408, + "totalChannelMessages":730, + "totalPrivateGroupMessages":1869, + "totalDirectMessages":25, + "totalLivechatMessages":0, + "lastLogin":"2018-02-24T12:44:45.045Z", + "lastMessageSentAt":"2018-02-23T18:14:03.490Z", + "lastSeenSubscription":"2018-02-23T17:58:54.779Z", + "os": { + "type":"Linux", + "platform":"linux", + "arch":"x64", + "release":"4.13.0-32-generic", + "uptime":76242, + "loadavg": [ + 0.0576171875,0.04638671875,0.00439453125 + ], + "totalmem":5787901952, + "freemem":1151168512, + "cpus": [ + { + "model":"Intel(R) Xeon(R) CPU E5620 @ 2.40GHz", + "speed":2405, + "times": { + "user":6437000, + "nice":586500, + "sys":1432200, + "idle":750117500, + "irq":0 + } + }, + { + "model":"Intel(R) Xeon(R) CPU E5620 @ 2.40GHz", + "speed":2405, + "times": { + "user":7319700, + "nice":268800, + "sys":1823600, + "idle":747642700, + "irq":0 + } + }, + { + "model":"Intel(R) Xeon(R) CPU E5620 @ 2.40GHz", + "speed":2405, + "times": { + "user":7484600, + "nice":1003500, + "sys":1446000, + "idle":748873400, + "irq":0 + } + }, + { + "model":"Intel(R) Xeon(R) CPU E5620 @ 2.40GHz", + "speed":2405, + "times": { + "user":8378200, + "nice":548500, + "sys":1443200, + "idle":747053300, + "irq":0 + } + } + ] + }, + "process": { + "nodeVersion":"v8.9.4", + "pid":11736, + "uptime":16265.506 + }, + "deploy": { + "method":"tar", + "platform":"selfinstall" + }, + "migration": { + "_id":"control", + "version":106, + "locked":false, + "lockedAt":"2018-02-23T18:13:13.948Z", + "buildAt":"2018-02-18T17:22:51.212Z" + }, + "instanceCount":1, + "createdAt":"2018-02-24T13:13:00.236Z", + "_updatedAt":"2018-02-24T13:13:00.236Z" + }, + "success":true + }`, + }, + }, + want: models.StatisticsInfo{ + Statistics: models.Statistics{ + Version: "0.61.0-develop", + TotalUsers: 88, + }, + }, + wantErr: nil, + }, + { + name: "Statistics Err", + fields: fields{ + testDoer{ + responseCode: 500, + response: `{ + "success":false, + "error":"Not allowed [error-not-allowed]", + "errorType":"error-not-allowed" + }`, + }, + }, + want: models.StatisticsInfo{ + Statistics: models.Statistics{}, + }, + wantErr: errors.New("Not allowed [error-not-allowed]"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetStatistics() + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + if err == nil { + assert.Equal(t, tt.want.Statistics.Version, got.Statistics.Version, "Version not matching") + assert.Equal(t, tt.want.Statistics.TotalUsers, got.Statistics.TotalUsers, "TotalUsers not matching") + } + }) + } } +// func TestRocket_GetStatisticsList(t *testing.T) { +// rocket := Client{Protocol: common_testing.Protocol, Host: common_testing.Host, Port: common_testing.Port} +// // TODO admin user +// rocket.auth = &authInfo{id: "4SicoW2wDjcAaRh4M", token: "4nI24JkcHTsqTtOUeJYbbrhum5T_Y6IdjAwyj72qDBu"} + +// statistics, err := rocket.GetStatisticsList(url.Values{"query": []string{`{"_id" : "zT26ye8RAM7MaEN7S"}`}}) +// assert.Nil(t, err) +// assert.NotNil(t, statistics) +// } + func TestRocket_GetStatisticsList(t *testing.T) { - rocket := Client{Protocol: common_testing.Protocol, Host: common_testing.Host, Port: common_testing.Port} - // TODO admin user - rocket.auth = &authInfo{id: "4SicoW2wDjcAaRh4M", token: "4nI24JkcHTsqTtOUeJYbbrhum5T_Y6IdjAwyj72qDBu"} - statistics, err := rocket.GetStatisticsList(url.Values{"query": []string{`{"_id" : "zT26ye8RAM7MaEN7S"}`}}) - assert.Nil(t, err) - assert.NotNil(t, statistics) + type fields struct { + myDoer Doer + params url.Values + } + tests := []struct { + name string + fields fields + want models.StatisticsList + wantErr error + }{ + { + name: "GetStatisticsList OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "statistics": [ + { + "_id":"v3D4mvobwfznKozH8", + "uniqueId":"wD4EP3M7FeFzJZgk9", + "installedAt":"2018-02-18T19:40:45.369Z", + "version":"0.61.0-develop", + "totalUsers":88, + "activeUsers":88, + "nonActiveUsers":0, + "onlineUsers":0, + "awayUsers":1, + "offlineUsers":87, + "totalRooms":81, + "totalChannels":41, + "totalPrivateGroups":37, + "totalDirect":3, + "totlalLivechat":0, + "totalMessages":2408, + "totalChannelMessages":730, + "totalPrivateGroupMessages":1869, + "totalDirectMessages":25, + "totalLivechatMessages":0, + "lastLogin":"2018-02-24T12:44:45.045Z", + "lastMessageSentAt":"2018-02-23T18:14:03.490Z", + "lastSeenSubscription":"2018-02-23T17:58:54.779Z", + "instanceCount":1, + "createdAt":"2018-02-24T15:13:00.312Z", + "_updatedAt":"2018-02-24T15:13:00.312Z" + } + ], + "count":1, + "offset":0, + "total":1, + "success":true + }`, + }, + params: url.Values{"query": []string{`{"_id" : "zT26ye8RAM7MaEN7S"}`}}, + }, + want: models.StatisticsList{ + Statistics: []models.Statistics{ + models.Statistics{ + ID: "v3D4mvobwfznKozH8", + UniqueID: "wD4EP3M7FeFzJZgk9", + ActiveUsers: 88, + TotalRooms: 81, + }, + }, + Pagination: models.Pagination{Count: 2, Offset: 0, Total: 2}, + }, + wantErr: nil, + }, + { + name: "GetStatisticsList err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "statistics": [ + { + "_id":"v3D4mvobwfznKozH8", + "uniqueId":"wD4EP3M7FeFzJZgk9", + "installedAt":"2018-02-18T19:40:45.369Z", + "version":"0.61.0-develop", + "totalUsers":88, + "activeUsers":88, + "nonActiveUsers":0, + "onlineUsers":0, + "awayUsers":1, + "offlineUsers":87, + "totalRooms":81, + "totalChannels":41, + "totalPrivateGroups":37, + "totalDirect":3, + "totlalLivechat":0, + "totalMessages":2408, + "totalChannelMessages":730, + "totalPrivateGroupMessages":1869, + "totalDirectMessages":25, + "totalLivechatMessages":0, + "lastLogin":"2018-02-24T12:44:45.045Z", + "lastMessageSentAt":"2018-02-23T18:14:03.490Z", + "lastSeenSubscription":"2018-02-23T17:58:54.779Z", + "instanceCount":1, + "createdAt":"2018-02-24T15:13:00.312Z", + "_updatedAt":"2018-02-24T15:13:00.312Z" + } + ], + "count":1, + "offset":0, + "total":1, + "success":false + }`, + }, + params: url.Values{"query": []string{`{"_id" : "zT26ye8RAM7MaEN7S"}`}}, + }, + want: models.StatisticsList{}, + wantErr: errors.New("got false response"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetStatisticsList(tt.fields.params) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + if err == nil { + assert.NotNil(t, got) + assert.Equal(t, got.Statistics[0].ID, tt.want.Statistics[0].ID, "ID did not match") + assert.Equal(t, got.Statistics[0].UniqueID, tt.want.Statistics[0].UniqueID, "UniqueID did not match") + assert.Equal(t, got.Statistics[0].ActiveUsers, tt.want.Statistics[0].ActiveUsers, "ActiveUsers did not match") + assert.Equal(t, got.Statistics[0].TotalRooms, tt.want.Statistics[0].TotalRooms, "TotalRooms did not match") + } + }) + } } diff --git a/rest/messages.go b/rest/messages.go index 0525a68..63d74d3 100644 --- a/rest/messages.go +++ b/rest/messages.go @@ -11,17 +11,19 @@ import ( "github.com/RocketChat/Rocket.Chat.Go.SDK/models" ) +// MessagesResponse hold messages type MessagesResponse struct { Status Messages []models.Message `json:"messages"` } +// MessageResponse a message type MessageResponse struct { Status Message models.Message `json:"message"` } -// Sends a message to a channel. The name of the channel has to be not nil. +// Send a message to a channel. The name of the channel has to be not nil. // The message will be html escaped. // // https://rocket.chat/docs/developer-guides/rest-api/chat/postmessage @@ -45,7 +47,7 @@ func (c *Client) PostMessage(msg *models.PostMessage) (*MessageResponse, error) return response, err } -// Get messages from a channel. The channel id has to be not nil. Optionally a +// GetMessages from a channel. The channel id has to be not nil. Optionally a // count can be specified to limit the size of the returned messages. // // https://rocket.chat/docs/developer-guides/rest-api/channels/history diff --git a/rest/messages_test.go b/rest/messages_test.go index d4c7899..0419478 100644 --- a/rest/messages_test.go +++ b/rest/messages_test.go @@ -1,22 +1,286 @@ package rest import ( + "errors" "testing" "github.com/RocketChat/Rocket.Chat.Go.SDK/models" "github.com/stretchr/testify/assert" ) -func TestRocket_SendAndReceive(t *testing.T) { - rocket := getDefaultClient(t) - general := &models.Channel{ID: "GENERAL", Name: "general"} +func TestRocket_Send(t *testing.T) { - err := rocket.Send(general, "Test") - assert.Nil(t, err) + type fields struct { + myDoer Doer + channel *models.Channel + msg string + } + tests := []struct { + name string + fields fields + wantErr error + }{ + { + name: "Send OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "ts": 1481748965123, + "channel": "general", + "message": { + "alias": "", + "msg": "This is a test!", + "parseUrls": true, + "groupable": false, + "ts": "2016-12-14T20:56:05.117Z", + "u": { + "_id": "y65tAmHs93aDChMWu", + "username": "graywolf336" + }, + "rid": "GENERAL", + "_updatedAt": "2016-12-14T20:56:05.119Z", + "_id": "jC9chsFddTvsbFQG7" + }, + "success": true + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + msg: "This is a test!", + }, + wantErr: nil, + }, + { + name: "Send Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "got false response" + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + }, + wantErr: errors.New("got false response"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.Send(tt.fields.channel, tt.fields.msg) - messages, err := rocket.GetMessages(general, &models.Pagination{Count: 10}) - assert.Nil(t, err) + assert.Equal(t, err, tt.wantErr, "Unexpected error") - message := findMessage(messages, testUserName, "Test") - assert.NotNil(t, message) + }) + } +} + +func TestRocket_PostMessage(t *testing.T) { + + type fields struct { + myDoer Doer + msg *models.PostMessage + } + tests := []struct { + name string + fields fields + want *MessageResponse + wantErr error + }{ + { + name: "PostMessage OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "ts": 1481748965123, + "channel": "general", + "message": { + "alias": "", + "msg": "This is a test!", + "parseUrls": true, + "groupable": false, + "ts": "2016-12-14T20:56:05.117Z", + "u": { + "_id": "y65tAmHs93aDChMWu", + "username": "graywolf336" + }, + "rid": "GENERAL", + "_updatedAt": "2016-12-14T20:56:05.119Z", + "_id": "jC9chsFddTvsbFQG7" + }, + "success": true + }`, + }, + msg: &models.PostMessage{ + RoomID: "", + Channel: "", + Text: "", + }, + }, + want: &MessageResponse{ + Status: Status{Success: true, Status: "", Message: ""}, + Message: models.Message{RoomID: "GENERAL", Msg: "This is a test!"}, + }, + wantErr: nil, + }, + { + name: "PostMessage Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "got false response" + }`, + }, + msg: &models.PostMessage{}, + }, + want: &MessageResponse{}, + wantErr: errors.New("got false response"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.PostMessage(tt.fields.msg) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + if err == nil { + assert.NotNil(t, got) + assert.Equal(t, got.Status.Message, tt.want.Status.Message, "Status Message did not match") + assert.Equal(t, got.Status.Status, tt.want.Status.Status, "Status Status did not match") + assert.Equal(t, got.Message.Msg, tt.want.Message.Msg, "Message Msg did not match") + assert.Equal(t, got.Message.RoomID, tt.want.Message.RoomID, "Message RoomID did not match") + + } + + }) + } +} + +func TestRocket_GetMessages(t *testing.T) { + + type fields struct { + myDoer Doer + channel *models.Channel + page *models.Pagination + } + tests := []struct { + name string + fields fields + want []models.Message + wantErr error + }{ + { + name: "GetMessages OK", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "messages": [ + { + "_id": "AkzpHAvZpdnuchw2a", + "rid": "ByehQjC44FwMeiLbX", + "msg": "hi", + "ts": "2016-12-09T12:50:51.555Z", + "u": { + "_id": "y65tAmHs93aDChMWu", + "username": "testing" + }, + "_updatedAt": "2016-12-09T12:50:51.562Z" + }, + { + "_id": "vkLMxcctR4MuTxreF", + "t": "uj", + "rid": "ByehQjC44FwMeiLbX", + "ts": "2016-12-08T15:41:37.730Z", + "msg": "testing2", + "u": { + "_id": "bRtgdhzM6PD9F8pSx", + "username": "testing2" + }, + "groupable": false, + "_updatedAt": "2016-12-08T16:03:25.235Z" + }, + { + "_id": "bfRW658nEyEBg75rc", + "t": "uj", + "rid": "ByehQjC44FwMeiLbX", + "ts": "2016-12-07T15:47:49.099Z", + "msg": "testing", + "u": { + "_id": "nSYqWzZ4GsKTX4dyK", + "username": "testing1" + }, + "groupable": false, + "_updatedAt": "2016-12-07T15:47:49.099Z" + }, + { + "_id": "pbuFiGadhRZTKouhB", + "t": "uj", + "rid": "ByehQjC44FwMeiLbX", + "ts": "2016-12-06T17:57:38.635Z", + "msg": "testing", + "u": { + "_id": "y65tAmHs93aDChMWu", + "username": "testing" + }, + "groupable": false, + "_updatedAt": "2016-12-06T17:57:38.635Z" + } + ], + "success": true + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + page: &models.Pagination{Count: 1, Offset: 0, Total: 1}, + }, + want: []models.Message{ + models.Message{ID: "AkzpHAvZpdnuchw2a", RoomID: "ByehQjC44FwMeiLbX", Msg: "hi"}, + models.Message{ID: "vkLMxcctR4MuTxreF", RoomID: "ByehQjC44FwMeiLbX", Msg: "testing2"}, + models.Message{ID: "bfRW658nEyEBg75rc", RoomID: "ByehQjC44FwMeiLbX", Msg: "testing"}, + models.Message{ID: "pbuFiGadhRZTKouhB", RoomID: "ByehQjC44FwMeiLbX", Msg: "testing"}, + }, + wantErr: nil, + }, + { + name: "GetMessages Err", + fields: fields{ + myDoer: testDoer{ + responseCode: 200, + response: `{ + "status": "error", + "message": "got false response" + }`, + }, + channel: &models.Channel{ID: "GENERAL"}, + page: &models.Pagination{Count: 1, Offset: 0, Total: 1}, + }, + want: []models.Message{}, + wantErr: errors.New("status: error, message: got false response"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + got, err := rt.GetMessages(tt.fields.channel, tt.fields.page) + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + if err == nil { + assert.NotNil(t, got) + + for i := 0; i < len(got); i++ { + assert.Equal(t, got[i].ID, tt.want[i].ID, "ID did not match") + assert.Equal(t, got[i].RoomID, tt.want[i].RoomID, "RoomID did not match") + assert.Equal(t, got[i].Msg, tt.want[i].Msg, "Msg did not match") + } + + } + + }) + } } diff --git a/rest/users.go b/rest/users.go index 5604d6d..b770e2e 100644 --- a/rest/users.go +++ b/rest/users.go @@ -2,7 +2,7 @@ package rest import ( "bytes" - "net/url" + "encoding/json" "github.com/RocketChat/Rocket.Chat.Go.SDK/models" ) @@ -26,22 +26,29 @@ type logonResponse struct { // // https://rocket.chat/docs/developer-guides/rest-api/authentication/login func (c *Client) Login(credentials *models.UserCredentials) error { - if c.auth != nil { + if c.client.auth != nil { return nil } if credentials.ID != "" && credentials.Token != "" { - c.auth = &authInfo{id: credentials.ID, token: credentials.Token} + c.client.auth = &authInfo{id: credentials.ID, token: credentials.Token} return nil } response := new(logonResponse) - data := url.Values{"user": {credentials.Email}, "password": {credentials.Password}} - if err := c.Post("login", bytes.NewBufferString(data.Encode()), response); err != nil { + + type userlogin struct { + UserName string `json:"username"` + Password string `json:"password"` + } + + data, _ := json.Marshal(userlogin{UserName: credentials.Email, Password: credentials.Password}) + + if err := c.Post("login", bytes.NewBuffer(data), response); err != nil { return err } - c.auth = &authInfo{id: response.Data.UserID, token: response.Data.Token} + c.client.auth = &authInfo{id: response.Data.UserID, token: response.Data.Token} credentials.ID, credentials.Token = response.Data.UserID, response.Data.Token return nil } @@ -51,7 +58,7 @@ func (c *Client) Login(credentials *models.UserCredentials) error { // https://rocket.chat/docs/developer-guides/rest-api/authentication/logout func (c *Client) Logout() (string, error) { - if c.auth == nil { + if c.client.auth == nil { return "Was not logged in", nil } diff --git a/rest/users_test.go b/rest/users_test.go index c93fe59..e50909b 100644 --- a/rest/users_test.go +++ b/rest/users_test.go @@ -1,18 +1,188 @@ package rest import ( + "errors" "testing" - "github.com/RocketChat/Rocket.Chat.Go.SDK/common_testing" + "github.com/RocketChat/Rocket.Chat.Go.SDK/models" "github.com/stretchr/testify/assert" ) -func TestRocket_LoginLogout(t *testing.T) { - client := getAuthenticatedClient(t, common_testing.GetRandomString(), common_testing.GetRandomEmail(), common_testing.GetRandomString()) - _, logoutErr := client.Logout() - assert.Nil(t, logoutErr) +func TestRestService_Login(t *testing.T) { + type fields struct { + myDoer Doer + } + type args struct { + credentials *models.UserCredentials + } + tests := []struct { + name string + fields fields + args args + wantErr error + }{ + { + name: "OK", + fields: fields{ + testDoer{ + responseCode: 200, + response: `{ + "status": "success", + "data": { + "authToken": "9HqLlyZOugoStsXCUfD_0YdwnNnunAJF8V47U3QHXSq", + "userId": "aobEdbYhXfu5hkeqG", + "me": { + "_id": "aYjNnig8BEAWeQzMh", + "name": "Rocket Cat", + "emails": [ + { + "address": "rocket.cat@rocket.chat", + "verified": false + } + ], + "status": "offline", + "statusConnection": "offline", + "username": "rocket.cat", + "utcOffset": -3, + "active": true, + "roles": [ + "admin" + ], + "settings": { + "preferences": {} + } + } + } + }`, + }, + }, + args: args{ + credentials: &models.UserCredentials{Email: "fred", Password: "smith"}, + }, + wantErr: nil, + }, + { + name: "Token", + fields: fields{ + testDoer{ + responseCode: 200, + response: `{ + "status": "success", + "data": { + "authToken": "9HqLlyZOugoStsXCUfD_0YdwnNnunAJF8V47U3QHXSq", + "userId": "aobEdbYhXfu5hkeqG", + "me": { + "_id": "aYjNnig8BEAWeQzMh", + "name": "Rocket Cat", + "emails": [ + { + "address": "rocket.cat@rocket.chat", + "verified": false + } + ], + "status": "offline", + "statusConnection": "offline", + "username": "rocket.cat", + "utcOffset": -3, + "active": true, + "roles": [ + "admin" + ], + "settings": { + "preferences": {} + } + } + } + }`, + }, + }, + args: args{ + credentials: &models.UserCredentials{ID: "aobEdbYhXfu5hkeqG", Token: "9HqLlyZOugoStsXCUfD_0YdwnNnunAJF8V47U3QHXSq"}, + }, + wantErr: nil, + }, + { + name: "Err", + fields: fields{ + testDoer{ + responseCode: 200, + response: `{ + "success": false + }`, + }, + }, + args: args{ + credentials: &models.UserCredentials{Email: "", Password: ""}, + }, + wantErr: errors.New("got false response"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + err := rt.Login(tt.args.credentials) - // channels, err := client.GetJoinedChannels() - // assert.Nil(t, channels) - // assert.NotNil(t, err) + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + }) + } +} + +func TestRestService_Logout(t *testing.T) { + type fields struct { + myDoer Doer + } + tests := []struct { + name string + fields fields + authed bool + want string + wantErr error + }{ + { + name: "Logged in", + fields: fields{ + testDoer{ + responseCode: 200, + response: `{ + "status": "success", + "data": { + "message": "You've been logged out!" + } + }`, + }, + }, + authed: true, + want: "You've been logged out!", + wantErr: nil, + }, + { + name: "Was not logged in", + fields: fields{ + testDoer{ + responseCode: 200, + response: ``, + }, + }, + authed: false, + want: "Was not logged in", + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rt := CreateTestRestClient(tt.fields.myDoer) + if tt.authed { + rt.auth = &authInfo{id: "HAS A TOKEN"} + } + got, err := rt.Logout() + + assert.Equal(t, err, tt.wantErr, "Unexpected error") + + if err == nil { + assert.Equal(t, got, tt.want, "ID did not match") + } + + }) + } }