From 84cf4ae56d7988883b790ea195587a119c18c7d1 Mon Sep 17 00:00:00 2001 From: DmitryZagorulko Date: Fri, 25 May 2018 15:56:31 +0300 Subject: [PATCH] add tests, improve receiving updates from telegram --- config.go | 14 ++--- routing.go | 148 ++++++++++++++++++++++++++---------------------- routing_test.go | 133 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 197 insertions(+), 98 deletions(-) diff --git a/config.go b/config.go index cb5aae8..8190ae0 100644 --- a/config.go +++ b/config.go @@ -10,11 +10,10 @@ import ( // TransportConfig struct type TransportConfig struct { - LogLevel logging.Level `yaml:"log_level"` - Database DatabaseConfig `yaml:"database"` - SentryDSN string `yaml:"sentry_dsn"` - HTTPServer HTTPServerConfig `yaml:"http_server"` - TelegramConfig TelegramConfig `yaml:"telegram"` + LogLevel logging.Level `yaml:"log_level"` + Database DatabaseConfig `yaml:"database"` + SentryDSN string `yaml:"sentry_dsn"` + HTTPServer HTTPServerConfig `yaml:"http_server"` } // DatabaseConfig struct @@ -33,11 +32,6 @@ type HTTPServerConfig struct { Listen string `yaml:"listen"` } -// TelegramConfig struct -type TelegramConfig struct { - Debug bool `yaml:"debug"` -} - // LoadConfig read configuration file func LoadConfig(path string) *TransportConfig { var err error diff --git a/routing.go b/routing.go index 960049a..bacaacd 100644 --- a/routing.go +++ b/routing.go @@ -109,6 +109,7 @@ func connectHandler(w http.ResponseWriter, r *http.Request) { } func addBotHandler(w http.ResponseWriter, r *http.Request) { + setLocale(r.Header.Get("Accept-Language")) body, err := ioutil.ReadAll(r.Body) if err != nil { raven.CaptureErrorAndWait(err, nil) @@ -312,6 +313,8 @@ func settingsHandler(w http.ResponseWriter, r *http.Request, uid string) { } func saveHandler(w http.ResponseWriter, r *http.Request) { + setLocale(r.Header.Get("Accept-Language")) + body, err := ioutil.ReadAll(r.Body) if err != nil { raven.CaptureErrorAndWait(err, nil) @@ -385,7 +388,7 @@ func createHandler(w http.ResponseWriter, r *http.Request) { cr, status, errr := client.APICredentials() if errr.RuntimeErr != nil { - raven.CaptureErrorAndWait(err, nil) + raven.CaptureErrorAndWait(errr.RuntimeErr, nil) http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "not_found_account"}), http.StatusInternalServerError) logger.Error(c.APIURL, status, errr.RuntimeErr, cr) return @@ -429,7 +432,7 @@ func createHandler(w http.ResponseWriter, r *http.Request) { data, status, errr := client.IntegrationModuleEdit(integration) if errr.RuntimeErr != nil { - raven.CaptureErrorAndWait(err, nil) + raven.CaptureErrorAndWait(errr.RuntimeErr, nil) http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_creating_integration"}), http.StatusInternalServerError) logger.Error(c.APIURL, status, errr.RuntimeErr, data) return @@ -554,85 +557,96 @@ func validate(c Connection) error { } func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string) { - b := getBotByToken(token) - if b.ID == 0 { - logger.Error(token, "missing") - return - } - - if !b.Active { - logger.Error(token, "deactivated") - return - } - - bot, err := GetBotInfo(token) - if err != nil { - logger.Error(token, err) - } - - bot.Debug = false - + ok := make(chan bool) bytes, err := ioutil.ReadAll(r.Body) if err != nil { raven.CaptureErrorAndWait(err, nil) + logger.Error(token, err) return } - var update tgbotapi.Update - - err = json.Unmarshal(bytes, &update) - if err != nil { - raven.CaptureErrorAndWait(err, nil) - return - } - - c := getConnection(b.ClientID) - if c.MGURL == "" || c.MGToken == "" { - logger.Error(token, "MGURL or MGToken is empty") - return - } - - var client = v1.New(c.MGURL, c.MGToken) - - if update.Message != nil { - snd := v1.SendData{ - Message: v1.SendMessage{ - Message: v1.Message{ - ExternalID: strconv.Itoa(update.Message.MessageID), - Type: "text", - Text: update.Message.Text, - }, - SentAt: time.Now(), - }, - User: v1.User{ - ExternalID: strconv.Itoa(update.Message.From.ID), - Nickname: update.Message.From.UserName, - Firstname: update.Message.From.FirstName, - }, - Channel: b.Channel, + go func() { + b := getBotByToken(token) + if b.ID == 0 { + logger.Error(token, "missing") + return } - data, status, err := client.Messages(snd) + if !b.Active { + logger.Error(token, "deactivated") + return + } + + var update tgbotapi.Update + + err = json.Unmarshal(bytes, &update) if err != nil { - logger.Error(token, err.Error(), status, data) + raven.CaptureErrorAndWait(err, nil) + logger.Error(token, err) + return } - } - if update.EditedMessage != nil { - snd := v1.UpdateData{ - Message: v1.UpdateMessage{ - Message: v1.Message{ - ExternalID: strconv.Itoa(update.EditedMessage.MessageID), - Type: "text", - Text: update.EditedMessage.Text, + c := getConnection(b.ClientID) + if c.MGURL == "" || c.MGToken == "" { + logger.Error(token, "MGURL or MGToken is empty") + return + } + + var client = v1.New(c.MGURL, c.MGToken) + + if update.Message != nil { + snd := v1.SendData{ + Message: v1.SendMessage{ + Message: v1.Message{ + ExternalID: strconv.Itoa(update.Message.MessageID), + Type: "text", + Text: update.Message.Text, + }, + SentAt: time.Now(), }, - }, - Channel: b.Channel, + User: v1.User{ + ExternalID: strconv.Itoa(update.Message.From.ID), + Nickname: update.Message.From.UserName, + Firstname: update.Message.From.FirstName, + }, + Channel: b.Channel, + } + + data, status, err := client.Messages(snd) + if err != nil { + logger.Error(token, err.Error(), status, data) + ok <- false + return + } } - data, status, err := client.UpdateMessages(snd) - if err != nil { - logger.Error(token, err.Error(), status, data) + if update.EditedMessage != nil { + snd := v1.UpdateData{ + Message: v1.UpdateMessage{ + Message: v1.Message{ + ExternalID: strconv.Itoa(update.EditedMessage.MessageID), + Type: "text", + Text: update.EditedMessage.Text, + }, + }, + Channel: b.Channel, + } + + data, status, err := client.UpdateMessages(snd) + if err != nil { + logger.Error(token, err.Error(), status, data) + ok <- false + return + } } + + ok <- true + }() + + if <-ok { + w.WriteHeader(http.StatusOK) + w.Write([]byte("SendMessage")) + } else { + w.WriteHeader(http.StatusBadRequest) } } diff --git a/routing_test.go b/routing_test.go index ed2e7ef..bbff5ec 100644 --- a/routing_test.go +++ b/routing_test.go @@ -3,16 +3,24 @@ package main import ( "net/http" "net/http/httptest" + "strings" "testing" - "strings" - - "encoding/json" - "github.com/h2non/gock" - "github.com/retailcrm/mg-transport-api-client-go/v1" ) +func init() { + c := Connection{ + ClientID: "123123", + APIKEY: "test", + APIURL: "https://test.retailcrm.ru", + MGURL: "https://test.retailcrm.pro", + MGToken: "test-token", + Active: true, + } + + c.createConnection() +} func TestRouting_connectHandler(t *testing.T) { req, err := http.NewRequest("GET", "/", nil) if err != nil { @@ -34,40 +42,123 @@ func TestRouting_addBotHandler(t *testing.T) { defer gock.Off() gock.New("https://api.telegram.org"). - Post("/botbot123:test/getMe"). + Post("/bot123123:Qwerty/getMe"). Reply(200). BodyString(`{"ok":true,"result":{"id":123,"is_bot":true,"first_name":"Test","username":"TestBot"}}`) - ch := v1.Channel{ - Type: "telegram", - Events: []string{ - "message_sent", - "message_updated", - "message_deleted", - "message_read", - }, - } - str, _ := json.Marshal(ch) + gock.New("https://api.telegram.org"). + Post("/bot123123:Qwerty/setWebhook"). + MatchType("url"). + BodyString("url=https%3A%2F%2Ftest.com%2Ftelegram%2F123123%3AQwerty"). + Reply(201). + BodyString(`{"ok":true}`) - gock.New("https://mg-test.com"). + gock.New("https://api.telegram.org"). + Post("/bot123123:Qwerty/getWebhookInfo"). + Reply(200). + BodyString(`{"ok":true,"result":{"url":"https://test.com/telegram/123123:Qwerty","has_custom_certificate":false,"pending_update_count":0}}`) + + gock.New("https://test.retailcrm.pro"). Post("/api/v1/transport/channels"). - JSON(str). + BodyString(`{"ID":0,"Type":"telegram","Events":["message_sent","message_updated","message_deleted","message_read"]}`). MatchHeader("Content-Type", "application/json"). MatchHeader("X-Transport-Token", "test-token"). - Reply(200). + Reply(201). BodyString(`{"id": 1}`) - req, err := http.NewRequest("POST", "/add-bot/", strings.NewReader(`{"token": "bot123:test", "clientId": "test"}`)) + req, err := http.NewRequest("POST", "/add-bot/", strings.NewReader(`{"token": "123123:Qwerty", "clientId": "123123"}`)) if err != nil { t.Fatal(err) } rr := httptest.NewRecorder() handler := http.HandlerFunc(addBotHandler) - handler.ServeHTTP(rr, req) + if rr.Code != http.StatusCreated { t.Errorf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusCreated) } } + +func TestRouting_activityBotHandler(t *testing.T) { + defer gock.Off() + + gock.New("https://test.retailcrm.pro"). + Post("/api/v1/transport/channels"). + BodyString(`{"ID":1,"Type":"telegram","Events":["message_sent","message_updated","message_deleted","message_read"]}`). + MatchHeader("Content-Type", "application/json"). + MatchHeader("X-Transport-Token", "123123"). + Reply(200). + BodyString(`{"id": 1}`) + + req, err := http.NewRequest("POST", "/activity-bot/", strings.NewReader(`{"token": "123123:Qwerty", "active": false, "clientId": "123123"}`)) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(activityBotHandler) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", + rr.Code, http.StatusOK) + } +} + +func TestRouting_settingsHandler(t *testing.T) { + req, err := http.NewRequest("GET", "/settings/123123", nil) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(makeHandler(settingsHandler)) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", + rr.Code, http.StatusOK) + } +} + +func TestRouting_saveHandler(t *testing.T) { + req, err := http.NewRequest("POST", "/save/", + strings.NewReader( + `{"clientId": "123123", + "api_url": "https://test.retailcrm.ru", + "api_key": "test"}`, + )) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(saveHandler) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", + rr.Code, http.StatusOK) + } +} + +func TestRouting_activityHandler(t *testing.T) { + req, err := http.NewRequest("POST", "/actions/activity", + strings.NewReader( + `{"clientId": "123123","activity": {"active": true}}`, + )) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(activityHandler) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", + rr.Code, http.StatusOK) + } +}