chore(stock): log dividend event checks

This commit is contained in:
2026-07-21 18:50:48 +07:00
parent 39955669a8
commit c9fa4ac6dd
2 changed files with 64 additions and 2 deletions
@@ -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)
@@ -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