public-ip-tracker/tracker/bot/bot_test.go

207 lines
4.6 KiB
Go
Raw Normal View History

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"
"github.com/google/uuid"
)
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
SendMessageFunc func(context.Context, int64, string) error
}
// Do nothing here, it's not used by this bot
func (mb *mockTGBot) GetMe(ctx context.Context) (structs.User, error) {
return structs.User{}, nil
}
func (mb *mockTGBot) SendMessage(ctx context.Context, chatID int64, content string) error {
if mb.SendMessageFunc == nil {
return mb.SendMessageProp
}
return mb.SendMessageFunc(ctx, chatID, content)
}
// 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 }
func TestInit(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(context.Background())
called := false
tgBot := mockTGBot{
SendMessageFunc: func(ctx context.Context, chatID int64, content string) error {
if chatID != expectedChatID {
t.Errorf("Unexpected chatID %d", chatID)
}
if content != "Public IP tracker initialized at 2023-01-28 14:17:12 +0000 UTC, public IP is 198.51.100.42" {
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,
tgWatcher: &mockTGNotifier{},
}
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
tgBot := mockTGBot{
SendMessageFunc: func(ctx context.Context, chatID int64, content string) error {
if chatID != expectedChatID {
t.Errorf("Unexpected chatID %d", chatID)
}
if content != "Public IP has been changed, is now 198.51.100.42" {
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,
tgWatcher: &mockTGNotifier{},
frequency: 500 * time.Millisecond,
}
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,
tgWatcher: &mockTGNotifier{},
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
}
}