Unit and integration tests for Telegram

This commit is contained in:
Jan-Lukas Else 2021-06-14 21:34:29 +02:00
parent 9c9a217c07
commit c9af4e7efa
7 changed files with 292 additions and 27 deletions

2
app.go
View File

@ -36,7 +36,7 @@ type goBlog struct {
pPostHooks []postHookFunc
pUpdateHooks []postHookFunc
pDeleteHooks []postHookFunc
// HTTP
// HTTP Routers
d *dynamicHandler
privateMode bool
privateModeHandler []func(http.Handler) http.Handler

View File

@ -4,6 +4,10 @@ import (
"testing"
)
func (a *goBlog) setInMemoryDatabase() {
a.db, _ = a.openDatabase(":memory:", false)
}
func Test_database(t *testing.T) {
t.Run("Basic Database Test", func(t *testing.T) {
app := &goBlog{}

View File

@ -5,7 +5,11 @@ import (
"time"
)
var appHttpClient = &http.Client{
type httpClient interface {
Do(req *http.Request) (*http.Response, error)
}
var appHttpClient httpClient = &http.Client{
Timeout: 5 * time.Minute,
Transport: &http.Transport{
DisableKeepAlives: true,

62
httpClient_test.go Normal file
View File

@ -0,0 +1,62 @@
package main
import (
"io"
"net/http"
"strings"
"sync"
)
type fakeHttpClient struct {
req *http.Request
res *http.Response
err error
enabled bool
// internal
alt httpClient
mx sync.Mutex
}
var fakeAppHttpClient *fakeHttpClient
func init() {
fakeAppHttpClient = &fakeHttpClient{
alt: appHttpClient,
}
appHttpClient = fakeAppHttpClient
}
func (c *fakeHttpClient) Do(req *http.Request) (*http.Response, error) {
if !c.enabled {
return c.alt.Do(req)
}
c.req = req
return c.res, c.err
}
func (c *fakeHttpClient) clean() {
c.req = nil
c.err = nil
c.res = nil
}
func (c *fakeHttpClient) setFakeResponse(statusCode int, body string, err error) {
c.clean()
c.err = err
c.res = &http.Response{
StatusCode: statusCode,
Body: io.NopCloser(strings.NewReader(body)),
}
}
func (c *fakeHttpClient) lock(enabled bool) {
c.mx.Lock()
c.clean()
c.enabled = enabled
}
func (c *fakeHttpClient) unlock() {
c.enabled = false
c.clean()
c.mx.Unlock()
}

View File

@ -30,11 +30,9 @@ func (a *goBlog) sendNotification(text string) {
log.Println("Failed to save notification:", err.Error())
}
if an := a.cfg.Notifications; an != nil {
if tg := an.Telegram; tg != nil && tg.Enabled {
err := sendTelegramMessage(n.Text, "", tg.BotToken, tg.ChatID)
if err != nil {
log.Println("Failed to send Telegram notification:", err.Error())
}
err := an.Telegram.send(n.Text, "")
if err != nil {
log.Println("Failed to send Telegram notification:", err.Error())
}
}
}

View File

@ -14,24 +14,27 @@ import (
const telegramBaseURL = "https://api.telegram.org/bot"
func (a *goBlog) initTelegram() {
enable := false
for _, b := range a.cfg.Blogs {
if tg := b.Telegram; tg != nil && tg.Enabled && tg.BotToken != "" && tg.ChatID != "" {
enable = true
}
}
if enable {
a.pPostHooks = append(a.pPostHooks, func(p *post) {
if p.isPublishedSectionPost() {
tgPost(a.cfg.Blogs[p.Blog].Telegram, p.title(), a.fullPostURL(p), a.shortPostURL(p))
a.pPostHooks = append(a.pPostHooks, func(p *post) {
if tg := a.cfg.Blogs[p.Blog].Telegram; tg.enabled() && p.isPublishedSectionPost() {
if html := tg.generateHTML(p.title(), a.fullPostURL(p), a.shortPostURL(p)); html != "" {
if err := tg.send(html, "HTML"); err != nil {
log.Printf("Failed to send post to Telegram: %v", err)
}
}
})
}
}
})
}
func tgPost(tg *configTelegram, title, fullURL, shortURL string) {
func (tg *configTelegram) enabled() bool {
if tg == nil || !tg.Enabled || tg.BotToken == "" || tg.ChatID == "" {
return
return false
}
return true
}
func (tg *configTelegram) generateHTML(title, fullURL, shortURL string) string {
if !tg.enabled() {
return ""
}
replacer := strings.NewReplacer("<", "&lt;", ">", "&gt;", "&", "&amp;")
var message bytes.Buffer
@ -48,19 +51,20 @@ func tgPost(tg *configTelegram, title, fullURL, shortURL string) {
message.WriteString(replacer.Replace(shortURL))
message.WriteString("</a>")
}
if err := sendTelegramMessage(message.String(), "HTML", tg.BotToken, tg.ChatID); err != nil {
log.Println(err.Error())
}
return message.String()
}
func sendTelegramMessage(message, mode, token, chat string) error {
func (tg *configTelegram) send(message, mode string) error {
if !tg.enabled() {
return nil
}
params := url.Values{}
params.Add("chat_id", chat)
params.Add("chat_id", tg.ChatID)
params.Add("text", message)
if mode != "" {
params.Add("parse_mode", mode)
}
tgURL, err := url.Parse(telegramBaseURL + token + "/sendMessage")
tgURL, err := url.Parse(telegramBaseURL + tg.BotToken + "/sendMessage")
if err != nil {
return errors.New("failed to create Telegram request")
}

193
telegram_test.go Normal file
View File

@ -0,0 +1,193 @@
package main
import (
"net/http"
"testing"
"time"
)
func Test_configTelegram_enabled(t *testing.T) {
if (&configTelegram{}).enabled() == true {
t.Error("Telegram shouldn't be enabled")
}
if (&configTelegram{
Enabled: true,
}).enabled() == true {
t.Error("Telegram shouldn't be enabled")
}
if (&configTelegram{
Enabled: true,
ChatID: "abc",
}).enabled() == true {
t.Error("Telegram shouldn't be enabled")
}
if (&configTelegram{
Enabled: true,
BotToken: "abc",
}).enabled() == true {
t.Error("Telegram shouldn't be enabled")
}
if (&configTelegram{
Enabled: true,
BotToken: "abc",
ChatID: "abc",
}).enabled() != true {
t.Error("Telegram should be enabled")
}
}
func Test_configTelegram_generateHTML(t *testing.T) {
tg := &configTelegram{
Enabled: true,
ChatID: "abc",
BotToken: "abc",
}
// Without Instant View
expected := "Title\n\n<a href=\"https://example.com/s/1\">https://example.com/s/1</a>"
if got := tg.generateHTML("Title", "https://example.com/test", "https://example.com/s/1"); got != expected {
t.Errorf("Wrong result, got: %v", got)
}
// With Instant View
tg.InstantViewHash = "abc"
expected = "Title\n\n<a href=\"https://t.me/iv?rhash=abc&url=https%3A%2F%2Fexample.com%2Ftest\">https://example.com/s/1</a>"
if got := tg.generateHTML("Title", "https://example.com/test", "https://example.com/s/1"); got != expected {
t.Errorf("Wrong result, got: %v", got)
}
}
func Test_configTelegram_send(t *testing.T) {
fakeAppHttpClient.lock(true)
defer fakeAppHttpClient.unlock()
tg := &configTelegram{
Enabled: true,
ChatID: "chatid",
BotToken: "bottoken",
}
fakeAppHttpClient.setFakeResponse(200, "", nil)
err := tg.send("Message", "HTML")
if err != nil {
t.Errorf("Error: %v", err)
}
if fakeAppHttpClient.req == nil {
t.Error("Empty request")
}
if fakeAppHttpClient.err != nil {
t.Error("Error in request")
}
if fakeAppHttpClient.req.Method != http.MethodPost {
t.Error("Wrong method")
}
if u := fakeAppHttpClient.req.URL.String(); u != "https://api.telegram.org/botbottoken/sendMessage?chat_id=chatid&parse_mode=HTML&text=Message" {
t.Errorf("Wrong request URL, got: %v", u)
}
}
func Test_goBlog_initTelegram(t *testing.T) {
app := &goBlog{
pPostHooks: []postHookFunc{},
}
app.initTelegram()
if len(app.pPostHooks) != 1 {
t.Error("Hook not registered")
}
}
func Test_telegram(t *testing.T) {
t.Run("Send post to Telegram", func(t *testing.T) {
fakeAppHttpClient.lock(true)
defer fakeAppHttpClient.unlock()
fakeAppHttpClient.setFakeResponse(200, "", nil)
app := &goBlog{
pPostHooks: []postHookFunc{},
cfg: &config{
Server: &configServer{
PublicAddress: "https://example.com",
},
Blogs: map[string]*configBlog{
"en": {
Telegram: &configTelegram{
Enabled: true,
ChatID: "chatid",
BotToken: "bottoken",
},
},
},
},
}
app.setInMemoryDatabase()
app.initTelegram()
p := &post{
Path: "/test",
Parameters: map[string][]string{
"title": {"Title"},
},
Published: time.Now().String(),
Section: "test",
Blog: "en",
Status: statusPublished,
}
app.pPostHooks[0](p)
if u := fakeAppHttpClient.req.URL.String(); u != "https://api.telegram.org/botbottoken/sendMessage?chat_id=chatid&parse_mode=HTML&text=Title%0A%0A%3Ca+href%3D%22https%3A%2F%2Fexample.com%2Fs%2F1%22%3Ehttps%3A%2F%2Fexample.com%2Fs%2F1%3C%2Fa%3E" {
t.Errorf("Wrong request URL, got: %v", u)
}
})
t.Run("Telegram disabled", func(t *testing.T) {
fakeAppHttpClient.lock(true)
defer fakeAppHttpClient.unlock()
fakeAppHttpClient.setFakeResponse(200, "", nil)
app := &goBlog{
pPostHooks: []postHookFunc{},
cfg: &config{
Server: &configServer{
PublicAddress: "https://example.com",
},
Blogs: map[string]*configBlog{
"en": {},
},
},
}
app.setInMemoryDatabase()
app.initTelegram()
p := &post{
Path: "/test",
Parameters: map[string][]string{
"title": {"Title"},
},
Published: time.Now().String(),
Section: "test",
Blog: "en",
Status: statusPublished,
}
app.pPostHooks[0](p)
if fakeAppHttpClient.req != nil {
t.Error("There should be no request")
}
})
}