(new): expand runtime APIs
(fix): harden concurrent lifecycle (tests): add regression coverage (doc): update v1.2 guidance
This commit is contained in:
+68
@@ -22,6 +22,14 @@ func (f pollingRoundTripFunc) RoundTrip(req *http.Request) (*http.Response, erro
|
||||
return f(req)
|
||||
}
|
||||
|
||||
type closeCountingWriter struct{ closes int }
|
||||
|
||||
func (w *closeCountingWriter) Close() error { w.closes++; return nil }
|
||||
func (w *closeCountingWriter) Write(p []byte) (int, error) { return len(p), nil }
|
||||
func (w *closeCountingWriter) Print(sneklog.LogLevel, string, []*sneklog.MethodTraceback, ...any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type pollingRetryObserver struct {
|
||||
recordingObserver
|
||||
cancel context.CancelFunc
|
||||
@@ -343,6 +351,66 @@ func TestLoggerConfigurationRejectsNilAndLateMutation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseRespectsLoggerOwnershipAndAliases(t *testing.T) {
|
||||
ownedWriter := new(closeCountingWriter)
|
||||
owned := sneklog.NewLogger().AddWriter(ownedWriter)
|
||||
bot := &Bot[NoData]{
|
||||
logger: owned, loggerOwned: true,
|
||||
requestLogger: owned, requestLoggerOwned: false,
|
||||
}
|
||||
if err := bot.Close(); err != nil {
|
||||
t.Fatalf("Close returned error: %v", err)
|
||||
}
|
||||
if ownedWriter.closes != 1 {
|
||||
t.Fatalf("owned aliased logger closed %d times, want 1", ownedWriter.closes)
|
||||
}
|
||||
|
||||
callerWriter := new(closeCountingWriter)
|
||||
callerLogger := sneklog.NewLogger().AddWriter(callerWriter)
|
||||
bot = &Bot[NoData]{logger: callerLogger, requestLogger: callerLogger, webhookLogger: callerLogger}
|
||||
if err := bot.Close(); err != nil {
|
||||
t.Fatalf("Close with caller logger returned error: %v", err)
|
||||
}
|
||||
if callerWriter.closes != 0 {
|
||||
t.Fatalf("caller-owned logger closed %d times", callerWriter.closes)
|
||||
}
|
||||
_ = callerLogger.Close()
|
||||
}
|
||||
|
||||
func TestRunWithContextReturnsPollingPanic(t *testing.T) {
|
||||
bot := &Bot[NoData]{
|
||||
logger: sneklog.NewLogger(), prefixes: []string{"/"},
|
||||
plugins: []Plugin[NoData]{{name: "demo"}}, updateQueue: make(chan *tgapi.Update, 1), maxWorkers: 1,
|
||||
}
|
||||
defer func() { _ = bot.logger.Close() }()
|
||||
|
||||
err := bot.RunWithContext(context.Background())
|
||||
if !errors.Is(err, ErrHandlerPanic) {
|
||||
t.Fatalf("RunWithContext error = %v, want ErrHandlerPanic", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewBotWithAPIUsesInjectedClient(t *testing.T) {
|
||||
client := &http.Client{Transport: pollingRoundTripFunc(func(*http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Header: http.Header{"Content-Type": []string{"application/json"}},
|
||||
Body: io.NopCloser(strings.NewReader(`{"ok":true,"result":{"id":7,"is_bot":true,"first_name":"Test","username":"test_bot"}}`)),
|
||||
}, nil
|
||||
})}
|
||||
api := tgapi.NewAPI(tgapi.NewAPIOpts("token").SetAPIURL("http://example.invalid").SetHTTPClient(client))
|
||||
bot, err := NewBotWithAPI[NoData](&BotOpts{Token: "token"}, api)
|
||||
if err != nil {
|
||||
t.Fatalf("NewBotWithAPI returned error: %v", err)
|
||||
}
|
||||
if bot.GetAPI() != api || bot.GetUploader() == nil {
|
||||
t.Fatal("injected API was not used consistently")
|
||||
}
|
||||
if err := bot.Close(); err != nil {
|
||||
t.Fatalf("Close returned error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAppDataLoggerWriterRejectsNilResult(t *testing.T) {
|
||||
bot := &Bot[NoData]{logger: sneklog.NewLogger(), hasAppData: true}
|
||||
defer func() { _ = bot.logger.Close() }()
|
||||
|
||||
Reference in New Issue
Block a user