2023-01-28 13:29:39 +00:00
|
|
|
package bot
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"net"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
iptest "git.faercol.me/faercol/public-ip-tracker/tracker/ip/test"
|
|
|
|
"github.com/ahugues/go-telegram-api/structs"
|
2023-01-29 17:50:43 +00:00
|
|
|
"github.com/google/uuid"
|
2023-01-28 13:29:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const expectedChatID = 42
|
|
|
|
|
|
|
|
// Need to mock the telegram bot, because no mock is provided by my own lib, what a shame.
|
|
|
|
type mockTGBot struct {
|
|
|
|
SendMessageProp error
|
2023-02-04 18:07:04 +00:00
|
|
|
SendMessageFunc func(context.Context, int64, string, structs.FormattingOption) error
|
2023-01-28 13:29:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Do nothing here, it's not used by this bot
|
|
|
|
func (mb *mockTGBot) GetMe(ctx context.Context) (structs.User, error) {
|
|
|
|
return structs.User{}, nil
|
|
|
|
}
|
|
|
|
|
2023-02-04 18:07:04 +00:00
|
|
|
func (mb *mockTGBot) SendMessage(ctx context.Context, chatID int64, content string, option structs.FormattingOption) error {
|
2023-01-28 13:29:39 +00:00
|
|
|
if mb.SendMessageFunc == nil {
|
|
|
|
return mb.SendMessageProp
|
|
|
|
}
|
2023-02-04 18:07:04 +00:00
|
|
|
return mb.SendMessageFunc(ctx, chatID, content, option)
|
2023-01-28 13:29:39 +00:00
|
|
|
}
|
|
|
|
|
2023-01-29 17:50:43 +00:00
|
|
|
// Need to mock the notifier here too, but will do later on, I need to improve my lib in the future
|
|
|
|
type mockTGNotifier struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mn *mockTGNotifier) Run(ctx context.Context) {}
|
|
|
|
func (mn *mockTGNotifier) Subscribe(eventTypes []structs.UpdateType) (uuid.UUID, <-chan structs.Update) {
|
|
|
|
return uuid.New(), make(chan structs.Update)
|
|
|
|
}
|
|
|
|
func (mn *mockTGNotifier) Unsubscribe(id uuid.UUID) {}
|
|
|
|
func (mn *mockTGNotifier) ErrChan() <-chan error { return nil }
|
|
|
|
|
2023-01-28 13:29:39 +00:00
|
|
|
func TestInit(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
called := false
|
|
|
|
|
2023-02-04 18:07:04 +00:00
|
|
|
expectedMsg := "\\[Host `test`\\] Sat, 28 Jan 2023 14:17:12 UTC\nPublic IP tracker initialized\\. Current IP is 198\\.51\\.100\\.42"
|
|
|
|
|
2023-01-28 13:29:39 +00:00
|
|
|
tgBot := mockTGBot{
|
2023-02-04 18:07:04 +00:00
|
|
|
SendMessageFunc: func(ctx context.Context, chatID int64, content string, option structs.FormattingOption) error {
|
|
|
|
if option != structs.FormattingMarkdownV2 {
|
|
|
|
t.Errorf("Unexpected formatting option %v", option)
|
|
|
|
}
|
2023-01-28 13:29:39 +00:00
|
|
|
if chatID != expectedChatID {
|
|
|
|
t.Errorf("Unexpected chatID %d", chatID)
|
|
|
|
}
|
2023-02-04 18:07:04 +00:00
|
|
|
if content != expectedMsg {
|
2023-01-28 13:29:39 +00:00
|
|
|
t.Errorf("Unexpected message %s", content)
|
|
|
|
}
|
|
|
|
called = true
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
ipGetter := iptest.TestIPGetter{
|
|
|
|
PublicIPProp: net.ParseIP("198.51.100.42"),
|
|
|
|
}
|
|
|
|
|
|
|
|
bot := Notifier{
|
|
|
|
ctx: ctx,
|
|
|
|
cancel: cancel,
|
|
|
|
tgBot: &tgBot,
|
|
|
|
tgChatID: expectedChatID,
|
|
|
|
timeGetter: func() time.Time { return time.Date(2023, 1, 28, 14, 17, 12, 0, time.UTC) },
|
|
|
|
ipGetter: &ipGetter,
|
|
|
|
frequency: 1 * time.Minute,
|
2023-01-29 17:50:43 +00:00
|
|
|
tgWatcher: &mockTGNotifier{},
|
2023-02-04 18:07:04 +00:00
|
|
|
hostname: "test",
|
2023-01-28 13:29:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := bot.SendInitMessage(); err != nil {
|
|
|
|
t.Fatalf("Unexpected error %s", err.Error())
|
|
|
|
}
|
|
|
|
if !called {
|
|
|
|
t.Error("Telegram bot not called")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdateIP(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
called := false
|
|
|
|
|
2023-02-04 18:07:04 +00:00
|
|
|
expectedMsg := "\\[Host `test`\\] Sat, 28 Jan 2023 14:17:12 UTC\nPublic IP has changed, new IP is 198\\.51\\.100\\.42"
|
|
|
|
|
2023-01-28 13:29:39 +00:00
|
|
|
tgBot := mockTGBot{
|
2023-02-04 18:07:04 +00:00
|
|
|
SendMessageFunc: func(ctx context.Context, chatID int64, content string, option structs.FormattingOption) error {
|
|
|
|
if option != structs.FormattingMarkdownV2 {
|
|
|
|
t.Errorf("Unexpected formatting option %v", option)
|
|
|
|
}
|
2023-01-28 13:29:39 +00:00
|
|
|
if chatID != expectedChatID {
|
|
|
|
t.Errorf("Unexpected chatID %d", chatID)
|
|
|
|
}
|
2023-02-04 18:07:04 +00:00
|
|
|
if content != expectedMsg {
|
2023-01-28 13:29:39 +00:00
|
|
|
t.Errorf("Unexpected message %s", content)
|
|
|
|
}
|
|
|
|
called = true
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
ipGetter := iptest.TestIPGetter{
|
|
|
|
PublicIPProp: net.ParseIP("198.51.100.42"),
|
|
|
|
}
|
|
|
|
|
|
|
|
bot := Notifier{
|
|
|
|
ctx: ctx,
|
|
|
|
cancel: cancel,
|
|
|
|
tgBot: &tgBot,
|
|
|
|
tgChatID: expectedChatID,
|
|
|
|
timeGetter: func() time.Time { return time.Date(2023, 1, 28, 14, 17, 12, 0, time.UTC) },
|
|
|
|
currentIP: net.ParseIP("198.51.100.12"),
|
|
|
|
exitChan: make(chan struct{}, 1),
|
|
|
|
errChan: make(chan error, 5),
|
|
|
|
ipGetter: &ipGetter,
|
2023-01-29 17:50:43 +00:00
|
|
|
tgWatcher: &mockTGNotifier{},
|
2023-01-28 13:29:39 +00:00
|
|
|
frequency: 500 * time.Millisecond,
|
2023-02-04 18:07:04 +00:00
|
|
|
hostname: "test",
|
2023-01-28 13:29:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
go bot.Run()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-bot.Exit():
|
|
|
|
t.Error("Unexpected exit")
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
cancel()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-bot.Exit():
|
|
|
|
break
|
|
|
|
case <-time.After(2 * time.Second):
|
|
|
|
t.Error("Unexpected timeout")
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case err := <-bot.ErrChan():
|
|
|
|
t.Errorf("Unexpected error %s", err.Error())
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if !called {
|
|
|
|
t.Error("Telegram bot not called")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdateIPNoChange(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
|
|
|
tgBot := mockTGBot{
|
|
|
|
SendMessageProp: errors.New("should not be called"),
|
|
|
|
}
|
|
|
|
|
|
|
|
ipGetter := iptest.TestIPGetter{
|
|
|
|
PublicIPProp: net.ParseIP("198.51.100.42"),
|
|
|
|
}
|
|
|
|
|
|
|
|
bot := Notifier{
|
|
|
|
ctx: ctx,
|
|
|
|
cancel: cancel,
|
|
|
|
tgBot: &tgBot,
|
|
|
|
tgChatID: expectedChatID,
|
|
|
|
timeGetter: func() time.Time { return time.Date(2023, 1, 28, 14, 17, 12, 0, time.UTC) },
|
|
|
|
currentIP: net.ParseIP("198.51.100.42"),
|
|
|
|
exitChan: make(chan struct{}, 1),
|
|
|
|
errChan: make(chan error, 5),
|
|
|
|
ipGetter: &ipGetter,
|
2023-01-29 17:50:43 +00:00
|
|
|
tgWatcher: &mockTGNotifier{},
|
2023-01-28 13:29:39 +00:00
|
|
|
frequency: 100 * time.Millisecond,
|
|
|
|
}
|
|
|
|
|
|
|
|
go bot.Run()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-bot.Exit():
|
|
|
|
t.Error("Unexpected exit")
|
|
|
|
case <-time.After(500 * time.Millisecond):
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
cancel()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-bot.Exit():
|
|
|
|
break
|
|
|
|
case <-time.After(2 * time.Second):
|
|
|
|
t.Error("Unexpected timeout")
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case err := <-bot.ErrChan():
|
|
|
|
t.Errorf("Unexpected error %s", err.Error())
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|