feat(sources)!: split source contracts into PollSource/StreamSource and add mode-aware source config
- Introduce explicit source interfaces: sources.PollSource and sources.StreamSource, with shared sources.Input (Name() only). - Remove mandatory Kind() from the base source contract to support sources that emit multiple kinds. - Add config.SourceMode (poll, stream, or omitted/auto) and SourceConfig.Kinds (plural expected kinds), while keeping legacy SourceConfig.Kind for compatibility. - Enforce mode semantics in config validation (poll requires every, stream forbids every) and detect mode/driver mismatches in sources.Registry. - Update docs and tests for the new source model and config behavior.
This commit is contained in:
84
sources/registry_test.go
Normal file
84
sources/registry_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package sources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/ejr/feedkit/config"
|
||||
"gitea.maximumdirect.net/ejr/feedkit/event"
|
||||
)
|
||||
|
||||
type testPollSource struct{ name string }
|
||||
|
||||
func (s testPollSource) Name() string { return s.name }
|
||||
func (s testPollSource) Poll(context.Context) ([]event.Event, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type testStreamSource struct{ name string }
|
||||
|
||||
func (s testStreamSource) Name() string { return s.name }
|
||||
func (s testStreamSource) Run(context.Context, chan<- event.Event) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRegistryBuildInputModeConflicts(t *testing.T) {
|
||||
r := NewRegistry()
|
||||
r.RegisterPoll("poll_driver", func(cfg config.SourceConfig) (PollSource, error) {
|
||||
return testPollSource{name: cfg.Name}, nil
|
||||
})
|
||||
r.RegisterStream("stream_driver", func(cfg config.SourceConfig) (StreamSource, error) {
|
||||
return testStreamSource{name: cfg.Name}, nil
|
||||
})
|
||||
|
||||
_, err := r.BuildInput(config.SourceConfig{
|
||||
Name: "s1",
|
||||
Driver: "stream_driver",
|
||||
Mode: config.SourceModePoll,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatalf("expected mode conflict error, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "mode=poll") {
|
||||
t.Fatalf("expected poll conflict error, got: %v", err)
|
||||
}
|
||||
|
||||
_, err = r.BuildInput(config.SourceConfig{
|
||||
Name: "s2",
|
||||
Driver: "poll_driver",
|
||||
Mode: config.SourceModeStream,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatalf("expected mode conflict error, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "mode=stream") {
|
||||
t.Fatalf("expected stream conflict error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryBuildInputAutoByDriverType(t *testing.T) {
|
||||
r := NewRegistry()
|
||||
r.RegisterPoll("poll_driver", func(cfg config.SourceConfig) (PollSource, error) {
|
||||
return testPollSource{name: cfg.Name}, nil
|
||||
})
|
||||
r.RegisterStream("stream_driver", func(cfg config.SourceConfig) (StreamSource, error) {
|
||||
return testStreamSource{name: cfg.Name}, nil
|
||||
})
|
||||
|
||||
src, err := r.BuildInput(config.SourceConfig{Name: "p", Driver: "poll_driver"})
|
||||
if err != nil {
|
||||
t.Fatalf("BuildInput poll auto failed: %v", err)
|
||||
}
|
||||
if _, ok := src.(PollSource); !ok {
|
||||
t.Fatalf("expected PollSource, got %T", src)
|
||||
}
|
||||
|
||||
src, err = r.BuildInput(config.SourceConfig{Name: "s", Driver: "stream_driver"})
|
||||
if err != nil {
|
||||
t.Fatalf("BuildInput stream auto failed: %v", err)
|
||||
}
|
||||
if _, ok := src.(StreamSource); !ok {
|
||||
t.Fatalf("expected StreamSource, got %T", src)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user