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" ) 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) } 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, } 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, 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, 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 } }