mirror of
https://github.com/retailcrm/mg-bot-api-client-go.git
synced 2024-11-21 20:36:05 +03:00
674 lines
14 KiB
Go
674 lines
14 KiB
Go
package v1
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"log"
|
||
"math/rand"
|
||
"net/http"
|
||
"os"
|
||
"strconv"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/h2non/gock"
|
||
"github.com/joho/godotenv"
|
||
"github.com/stretchr/testify/assert"
|
||
)
|
||
|
||
const (
|
||
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||
letterIdxBits = 6 // 6 bits to represent a letter index
|
||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||
)
|
||
|
||
var src = rand.NewSource(time.Now().UnixNano())
|
||
|
||
func TestMain(m *testing.M) {
|
||
if os.Getenv("DEVELOPER_NODE") == "1" {
|
||
err := godotenv.Load("../.env")
|
||
if err != nil {
|
||
log.Fatal("Error loading .env file")
|
||
}
|
||
}
|
||
|
||
os.Exit(m.Run())
|
||
}
|
||
|
||
var (
|
||
mgURL = "https://api.example.com"
|
||
mgToken = "test_token"
|
||
debug, _ = strconv.ParseBool(os.Getenv("DEBUG"))
|
||
)
|
||
|
||
func client() *MgClient {
|
||
c := New(mgURL, mgToken)
|
||
|
||
if debug != false {
|
||
c.Debug = true
|
||
}
|
||
|
||
return c
|
||
}
|
||
|
||
func TestMgClient_Bots(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/bots").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1, "name": "Test Bot", "created_at": "2018-01-01T00:00:00.000000Z", "is_active": true, "is_self": true}]`)
|
||
|
||
req := BotsRequest{Active: 1}
|
||
|
||
data, status, err := c.Bots(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data)
|
||
|
||
for _, bot := range data {
|
||
assert.NotEmpty(t, bot.CreatedAt)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_Channels(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/channels").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1, "type":"test_type", "name": "Test Bot", "created_at": "2018-01-01T00:00:00.000000Z", "is_active": true}]`)
|
||
|
||
req := ChannelsRequest{Active: 1}
|
||
|
||
data, status, err := c.Channels(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data)
|
||
|
||
for _, channel := range data {
|
||
assert.NotEmpty(t, channel.Type)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_Users(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/users").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1, "external_id":"1", "username": "Test", "first_name":"Test", "last_name":"Test", "created_at": "2018-01-01T00:00:00.000000Z", "is_active": true, "is_online": true}]`)
|
||
|
||
req := UsersRequest{Active: 1}
|
||
|
||
data, status, err := c.Users(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data)
|
||
|
||
for _, user := range data {
|
||
assert.NotEmpty(t, user.FirstName)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_Customers(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/customers").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1,"channel_id": 1, "created_at": "2018-01-01T00:00:00.000000Z"}]`)
|
||
|
||
req := CustomersRequest{}
|
||
|
||
data, status, err := c.Customers(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data)
|
||
|
||
for _, customer := range data {
|
||
assert.NotEmpty(t, customer.ChannelId)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_Chats(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/chats").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1,"customer": {"id": 1, "name": "Test"}, "created_at": "2018-01-01T00:00:00.000000Z"}]`)
|
||
|
||
req := ChatsRequest{ChannelType: ChannelTypeTelegram}
|
||
|
||
data, status, err := c.Chats(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data)
|
||
|
||
for _, chat := range data {
|
||
assert.NotEmpty(t, chat.Customer.Name)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_Members(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/members").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1,"user_id": 1, "chat_id": 1, "created_at": "2018-01-01T00:00:00.000000Z"}]`)
|
||
|
||
req := MembersRequest{State: ChatMemberStateLeaved}
|
||
|
||
data, status, err := c.Members(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
|
||
for _, member := range data {
|
||
assert.NotEmpty(t, member.ChatID)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_Dialogs(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/dialogs").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1, "chat_id": 1, "created_at": "2018-01-01T00:00:00.000000Z"}]`)
|
||
|
||
req := DialogsRequest{Active: 0}
|
||
|
||
data, status, err := c.Dialogs(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data)
|
||
|
||
for _, dialog := range data {
|
||
assert.NotEmpty(t, dialog.ChatID)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_DialogAssign(t *testing.T) {
|
||
c := client()
|
||
|
||
d := 1
|
||
u := 1
|
||
req := DialogAssignRequest{DialogID: uint64(d), UserID: uint64(u)}
|
||
r, _ := json.Marshal(req)
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Patch("/api/bot/v1/dialogs/1/assign").
|
||
JSON(r).
|
||
Reply(400).
|
||
BodyString(`{"errors": ["dialog is not the latest in the chat"]}`)
|
||
|
||
_, status, err := c.DialogAssign(req)
|
||
|
||
assert.Error(t, err)
|
||
assert.Equal(t, http.StatusBadRequest, status)
|
||
}
|
||
|
||
func TestMgClient_DialogClose(t *testing.T) {
|
||
c := client()
|
||
i := 1
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Delete("/api/bot/v1/dialogs/1/close").
|
||
Reply(400).
|
||
BodyString(`{"errors": ["dialog #1 not found"]}`)
|
||
|
||
_, status, err := c.DialogClose(uint64(i))
|
||
|
||
assert.Error(t, err)
|
||
assert.Equal(t, http.StatusBadRequest, status)
|
||
}
|
||
|
||
func TestMgClient_Messages(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/messages").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1, "time": "2018-01-01T00:00:00+03:00", "type": "text", "scope": "public", "chat_id": 1, "is_read": false, "is_edit": false, "status": "received", "created_at": "2018-01-01T00:00:00.000000Z"}]`)
|
||
|
||
req := MessagesRequest{ChannelType: ChannelTypeTelegram, Scope: MessageScopePublic}
|
||
|
||
data, status, err := c.Messages(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data)
|
||
|
||
for _, message := range data {
|
||
assert.NotEmpty(t, message.ID)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_MessageSendText(t *testing.T) {
|
||
c := client()
|
||
|
||
i := uint64(1)
|
||
message := MessageSendRequest{
|
||
Type: MsgTypeText,
|
||
Scope: "public",
|
||
Content: "test",
|
||
ChatID: i,
|
||
}
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Post("/api/bot/v1/messages").
|
||
JSON(message).
|
||
Reply(200).
|
||
BodyString(`{"message_id": 1, "time": "2018-01-01T00:00:00+03:00"}`)
|
||
|
||
data, status, err := c.MessageSend(message)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data.MessageID)
|
||
}
|
||
|
||
func TestMgClient_MessageSendTextWithSuggestions(t *testing.T) {
|
||
c := client()
|
||
|
||
i := uint64(1)
|
||
message := MessageSendRequest{
|
||
Type: MsgTypeText,
|
||
Scope: "public",
|
||
Content: "test message with suggestions",
|
||
ChatID: i,
|
||
TransportAttachments: &TransportAttachments{
|
||
Suggestions: []Suggestion{
|
||
{
|
||
Type: SuggestionTypeText,
|
||
Title: "text suggestion",
|
||
},
|
||
{Type: SuggestionTypeEmail},
|
||
{Type: SuggestionTypePhone},
|
||
},
|
||
},
|
||
}
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Post("/api/bot/v1/messages").
|
||
JSON(message).
|
||
Reply(200).
|
||
BodyString(`{"message_id": 1, "time": "2018-01-01T00:00:00+03:00"}`)
|
||
|
||
data, status, err := c.MessageSend(message)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data.MessageID)
|
||
}
|
||
|
||
func TestMgClient_MessageSendProduct(t *testing.T) {
|
||
c := client()
|
||
|
||
message := MessageSendRequest{
|
||
Type: MsgTypeProduct,
|
||
ChatID: 5,
|
||
Scope: "public",
|
||
Product: &MessageProduct{
|
||
ID: 1,
|
||
Name: "Some Product",
|
||
Article: "Art-111",
|
||
Url: "https://example.com",
|
||
Img: "http://example.com/pic.jpg",
|
||
Cost: &MessageOrderCost{
|
||
Value: 29900,
|
||
Currency: "rub",
|
||
},
|
||
Quantity: &MessageOrderQuantity{
|
||
Value: 1,
|
||
},
|
||
},
|
||
}
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Post("/api/bot/v1/messages").
|
||
JSON(message).
|
||
Reply(200).
|
||
BodyString(`{"message_id": 1, "time": "2018-01-01T00:00:00+03:00"}`)
|
||
|
||
msg, _, err := c.MessageSend(message)
|
||
|
||
if err != nil {
|
||
t.Errorf("%v", err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
t.Logf("%v", msg)
|
||
}
|
||
|
||
func TestMgClient_MessageSendOrder(t *testing.T) {
|
||
c := client()
|
||
|
||
message := MessageSendRequest{
|
||
Type: MsgTypeOrder,
|
||
ChatID: 5,
|
||
Scope: "public",
|
||
Order: &MessageOrder{
|
||
Number: RandStringBytesMaskImprSrc(7),
|
||
Cost: &MessageOrderCost{
|
||
Value: 29900,
|
||
Currency: MsgCurrencyRub,
|
||
},
|
||
Status: &MessageOrderStatus{
|
||
Code: MsgOrderStatusCodeNew,
|
||
Name: "Новый",
|
||
},
|
||
Delivery: &MessageOrderDelivery{
|
||
Name: "Курьерская доставка",
|
||
Address: "г. Москва, Проспект Мира, 9",
|
||
Price: &MessageOrderCost{
|
||
Value: 1100,
|
||
Currency: MsgCurrencyRub,
|
||
},
|
||
},
|
||
Items: []MessageOrderItem{
|
||
{
|
||
Name: "iPhone 6",
|
||
Url: "https://example.com/product.html",
|
||
Img: "https://example.com/picture.png",
|
||
Price: &MessageOrderCost{
|
||
Value: 29900,
|
||
Currency: MsgCurrencyRub,
|
||
},
|
||
Quantity: &MessageOrderQuantity{
|
||
Value: 1,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Post("/api/bot/v1/messages").
|
||
JSON(message).
|
||
Reply(200).
|
||
BodyString(`{"message_id": 1, "time": "2018-01-01T00:00:00+03:00"}`)
|
||
|
||
msg, _, err := c.MessageSend(message)
|
||
|
||
if err != nil {
|
||
t.Errorf("%v", err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
t.Logf("%v", msg)
|
||
}
|
||
|
||
func TestMgClient_RandomStringGenerator(t *testing.T) {
|
||
rnd := RandStringBytesMaskImprSrc(7)
|
||
assert.NotEmpty(t, rnd)
|
||
t.Logf("%v", rnd)
|
||
}
|
||
|
||
func TestMgClient_MessageEdit(t *testing.T) {
|
||
c := client()
|
||
|
||
message := MessageEditRequest{
|
||
ID: uint64(1),
|
||
Content: "test",
|
||
}
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Patch("/api/bot/v1/messages/1").
|
||
JSON(message).
|
||
Reply(200).
|
||
BodyString(`{"message_id": 1, "time": "2018-01-01T00:00:00+03:00"}`)
|
||
|
||
e, status, err := c.MessageEdit(message)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
t.Logf("Message edit: %v", e)
|
||
}
|
||
|
||
func TestMgClient_MessageDelete(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Delete("/api/bot/v1/messages/1").
|
||
Reply(200).
|
||
BodyString(`{}`)
|
||
|
||
d, status, err := c.MessageDelete(1)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
t.Logf("Message delete: %v", d)
|
||
}
|
||
|
||
func TestMgClient_Info(t *testing.T) {
|
||
c := client()
|
||
req := InfoRequest{Name: "AWESOME", Avatar: "https://test.com/awesome_bot_avatar"}
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Patch("/api/bot/v1/my/info").
|
||
JSON(req).
|
||
Reply(200).
|
||
BodyString(`{}`)
|
||
|
||
_, status, err := c.Info(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
}
|
||
|
||
func TestMgClient_Commands(t *testing.T) {
|
||
c := client()
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Get("/api/bot/v1/my/commands").
|
||
Reply(200).
|
||
BodyString(`[{"id": 1, "name": "command_name", "description": "Command description", "created_at": "2018-01-01T00:00:00.000000Z"}]`)
|
||
|
||
req := CommandsRequest{}
|
||
|
||
data, status, err := c.Commands(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, data)
|
||
|
||
for _, command := range data {
|
||
assert.NotEmpty(t, command.Description)
|
||
}
|
||
}
|
||
|
||
func TestMgClient_CommandEditDelete(t *testing.T) {
|
||
c := client()
|
||
req := CommandEditRequest{
|
||
Name: "test_command",
|
||
Description: "Test command",
|
||
}
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Put("/api/bot/v1/my/commands/test_command").
|
||
JSON(req).
|
||
Reply(200).
|
||
BodyString(`{"id": 1, "name": "test_command", "description": "Test description"}`)
|
||
|
||
n, status, err := c.CommandEdit(req)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, n.ID)
|
||
|
||
gock.New(mgURL).
|
||
Delete("/api/bot/v1/my/commands/test_command").
|
||
Reply(200).
|
||
BodyString(`{}`)
|
||
|
||
d, status, err := c.CommandDelete(n.Name)
|
||
if err != nil {
|
||
t.Errorf("%d %v", status, err)
|
||
}
|
||
|
||
assert.NoError(t, err)
|
||
t.Logf("%v", d)
|
||
}
|
||
|
||
func TestMgClient_WsMeta(t *testing.T) {
|
||
c := client()
|
||
events := []string{"user_updated", "user_join_chat"}
|
||
url, headers, err := c.WsMeta(events)
|
||
|
||
if err != nil {
|
||
t.Errorf("%v", err)
|
||
}
|
||
|
||
resUrl := fmt.Sprintf("%s%s%s%s", strings.Replace(c.URL, "https", "wss", 1), prefix, "/ws?events=", strings.Join(events[:], ","))
|
||
resToken := c.Token
|
||
|
||
assert.Equal(t, resUrl, url)
|
||
assert.Equal(t, resToken, headers["X-Bot-Token"][0])
|
||
}
|
||
|
||
func TestMgClient_UploadFile(t *testing.T) {
|
||
c := client()
|
||
|
||
resp, err := http.Get("https://via.placeholder.com/300")
|
||
if err != nil {
|
||
t.Errorf("%v", err)
|
||
}
|
||
|
||
defer resp.Body.Close()
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Post("/api/bot/v1/files/upload").
|
||
Reply(200).
|
||
BodyString(`{"created_at": "2018-01-01T00:00:00.000000Z", "hash": "hash", "id": "1"}`)
|
||
|
||
data, status, err := c.UploadFile(resp.Body)
|
||
|
||
if status != http.StatusOK {
|
||
t.Errorf("%v", err)
|
||
}
|
||
|
||
t.Logf("File %+v is upload", data)
|
||
}
|
||
|
||
func TestMgClient_UploadFileByUrl(t *testing.T) {
|
||
c := client()
|
||
file := UploadFileByUrlRequest{
|
||
Url: "https://via.placeholder.com/300",
|
||
}
|
||
|
||
defer gock.Off()
|
||
|
||
gock.New(mgURL).
|
||
Post("/api/bot/v1/files/upload_by_url").
|
||
JSON(file).
|
||
Reply(200).
|
||
BodyString(`{"created_at": "2018-01-01T00:00:00.000000Z", "hash": "hash", "id": "1"}`)
|
||
|
||
uploadFileResponse, st, err := c.UploadFileByURL(file)
|
||
|
||
if st != http.StatusOK {
|
||
t.Errorf("%v", err)
|
||
}
|
||
|
||
t.Logf("File %+v is upload", uploadFileResponse.ID)
|
||
|
||
assert.NoError(t, err)
|
||
}
|
||
|
||
func RandStringBytesMaskImprSrc(n int) string {
|
||
b := make([]byte, n)
|
||
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||
if remain == 0 {
|
||
cache, remain = src.Int63(), letterIdxMax
|
||
}
|
||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||
b[i] = letterBytes[idx]
|
||
i--
|
||
}
|
||
cache >>= letterIdxBits
|
||
remain--
|
||
}
|
||
|
||
return string(b)
|
||
}
|