diff --git a/internal/modules/stock/dividend_flow_test.go b/internal/modules/stock/dividend_flow_test.go index 29dba3a..322fff7 100644 --- a/internal/modules/stock/dividend_flow_test.go +++ b/internal/modules/stock/dividend_flow_test.go @@ -1,8 +1,11 @@ package stock import ( + "bytes" "context" + "encoding/json" "errors" + "log/slog" "net/http" "net/http/httptest" "strings" @@ -12,6 +15,7 @@ import ( "github.com/go-telegram/bot/models" + applog "github.com/tiennm99/miti99bot/internal/log" "github.com/tiennm99/miti99bot/internal/storage" "github.com/tiennm99/miti99bot/internal/testutil" ) @@ -39,6 +43,43 @@ func (f *fakeDividendProvider) FetchDividendEvents(_ context.Context, _ string, return append([]DividendEvent(nil), f.events...), f.err } +func TestPortfolioDividendCheckLogsNoEvents(t *testing.T) { + s, store, _, rb, now := newDividendFlowState(t, nil) + seedDividendFlowPortfolio(t, store, now, 100) + p, err := LoadPortfolio(context.Background(), store, 7, now.UnixMilli()) + if err != nil { + t.Fatal(err) + } + + var output bytes.Buffer + previous := applog.Default() + applog.SetDefault(slog.New(slog.NewJSONHandler(&output, nil))) + t.Cleanup(func() { applog.SetDefault(previous) }) + + if err := s.notifyDividendEvents( + context.Background(), + rb.Bot, + testutil.NewPrivateMessage(7, "/stock_portfolio").Message, + 7, + p, + now, + ); err != nil { + t.Fatal(err) + } + + var record map[string]any + if err := json.Unmarshal(bytes.TrimSpace(output.Bytes()), &record); err != nil { + t.Fatalf("decode dividend check log %q: %v", output.String(), err) + } + if record["msg"] != "stock_dividend_events_checked" || + record["user"] != float64(7) || + record["ticker"] != "TCB" || + record["events"] != float64(0) || + record["status"] != "success" { + t.Fatalf("unexpected dividend check log: %#v", record) + } +} + func newDividendFlowState(t *testing.T, events []DividendEvent) (*state, Store, PendingDividendStore, *testutil.RecordingBot, time.Time) { t.Helper() now := time.Date(2026, 6, 25, 12, 0, 0, 0, saigonLocation) diff --git a/internal/modules/stock/dividend_notifications.go b/internal/modules/stock/dividend_notifications.go index d416d1e..172b5ac 100644 --- a/internal/modules/stock/dividend_notifications.go +++ b/internal/modules/stock/dividend_notifications.go @@ -26,6 +26,7 @@ const ( type dividendCheckResult struct { symbol string openedAt int64 + after time.Time events []DividendEvent err error } @@ -69,7 +70,13 @@ func (s *state) notifyDividendEvents(ctx context.Context, b *bot.Bot, msg *model sem <- struct{}{} defer func() { <-sem }() events, err := s.dividends.FetchDividendEvents(fetchCtx, h.symbol, h.after, checkedThrough) - results[index] = dividendCheckResult{symbol: h.symbol, openedAt: p.Assets[h.symbol].OpenedAt, events: events, err: err} + results[index] = dividendCheckResult{ + symbol: h.symbol, + openedAt: p.Assets[h.symbol].OpenedAt, + after: h.after, + events: events, + err: err, + } }() } wg.Wait() @@ -78,10 +85,24 @@ func (s *state) notifyDividendEvents(ctx context.Context, b *bot.Bot, msg *model failed := make([]string, 0) for _, result := range results { if result.err != nil { - log.Error("stock_fetch_dividend_events", "ticker", result.symbol, "err", result.err) + log.Error("stock_dividend_events_checked", + "user", userID, + "ticker", result.symbol, + "from", result.after.UnixMilli(), + "through", checkedThrough.UnixMilli(), + "events", 0, + "status", "error", + "err", result.err) failed = append(failed, result.symbol) continue } + log.Info("stock_dividend_events_checked", + "user", userID, + "ticker", result.symbol, + "from", result.after.UnixMilli(), + "through", checkedThrough.UnixMilli(), + "events", len(result.events), + "status", "success") sort.Slice(result.events, func(i, j int) bool { if result.events[i].PublishedAt.Equal(result.events[j].PublishedAt) { return result.events[i].ProviderID < result.events[j].ProviderID