mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 18:03:43 +00:00
fix: bind matcher source to playlist
This commit is contained in:
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/cosmic-clash/cosmic-clash/server/domain"
|
||||
)
|
||||
|
||||
type CandidateSource func(context.Context, time.Time, int) ([]domain.Candidate, error)
|
||||
type CandidateSource func(context.Context, time.Time, domain.Playlist, int) ([]domain.Candidate, error)
|
||||
|
||||
type ProposalCreator interface {
|
||||
CreateProposal(context.Context, domain.Proposal, map[string]string, time.Time) error
|
||||
@@ -68,7 +68,7 @@ func (w Worker) RunOnce(ctx context.Context) (bool, error) {
|
||||
return false, fmt.Errorf("invalid matcher size")
|
||||
}
|
||||
now := w.Now()
|
||||
candidates, err := w.Source(ctx, now, w.Size)
|
||||
candidates, err := w.Source(ctx, now, w.Playlist, w.Size)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -77,6 +77,9 @@ func (w Worker) RunOnce(ctx context.Context) (bool, error) {
|
||||
}
|
||||
queue := domain.NewQueue()
|
||||
for _, candidate := range candidates {
|
||||
if candidate.Playlist != w.Playlist {
|
||||
return false, fmt.Errorf("candidate playlist does not match worker")
|
||||
}
|
||||
if _, err := queue.Create(candidate.PlayerID, candidate.TicketID, "matcher-"+candidate.TicketID, candidate, now); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@ func workerFor(source CandidateSource, creator ProposalCreator) Worker {
|
||||
|
||||
func TestRunOnceDelegatesFinalClaimAndBindsTickets(t *testing.T) {
|
||||
creator := &creatorSpy{}
|
||||
worker := workerFor(func(context.Context, time.Time, int) ([]domain.Candidate, error) { return candidates(), nil }, creator)
|
||||
worker := workerFor(func(context.Context, time.Time, domain.Playlist, int) ([]domain.Candidate, error) {
|
||||
return candidates(), nil
|
||||
}, creator)
|
||||
formed, err := worker.RunOnce(context.Background())
|
||||
if err != nil || !formed || creator.calls != 1 {
|
||||
t.Fatalf("formed=%v err=%v calls=%d", formed, err, creator.calls)
|
||||
@@ -52,13 +54,15 @@ func TestRunOnceDelegatesFinalClaimAndBindsTickets(t *testing.T) {
|
||||
|
||||
func TestRunOnceFailsClosedOnSourceOrDurableClaimFailure(t *testing.T) {
|
||||
creator := &creatorSpy{err: errors.New("serialization conflict")}
|
||||
worker := workerFor(func(context.Context, time.Time, int) ([]domain.Candidate, error) {
|
||||
worker := workerFor(func(context.Context, time.Time, domain.Playlist, int) ([]domain.Candidate, error) {
|
||||
return nil, errors.New("redis unavailable")
|
||||
}, creator)
|
||||
if _, err := worker.RunOnce(context.Background()); err == nil {
|
||||
t.Fatal("source failure was swallowed")
|
||||
}
|
||||
worker.Source = func(context.Context, time.Time, int) ([]domain.Candidate, error) { return candidates(), nil }
|
||||
worker.Source = func(context.Context, time.Time, domain.Playlist, int) ([]domain.Candidate, error) {
|
||||
return candidates(), nil
|
||||
}
|
||||
if _, err := worker.RunOnce(context.Background()); err == nil {
|
||||
t.Fatal("durable claim failure was swallowed")
|
||||
}
|
||||
@@ -69,9 +73,34 @@ func TestRunOnceFailsClosedOnSourceOrDurableClaimFailure(t *testing.T) {
|
||||
|
||||
func TestRunOnceDoesNotClaimAnIncompleteBatch(t *testing.T) {
|
||||
creator := &creatorSpy{}
|
||||
worker := workerFor(func(context.Context, time.Time, int) ([]domain.Candidate, error) { return candidates()[:3], nil }, creator)
|
||||
worker := workerFor(func(context.Context, time.Time, domain.Playlist, int) ([]domain.Candidate, error) {
|
||||
return candidates()[:3], nil
|
||||
}, creator)
|
||||
formed, err := worker.RunOnce(context.Background())
|
||||
if err != nil || formed || creator.calls != 0 {
|
||||
t.Fatalf("formed=%v err=%v calls=%d", formed, err, creator.calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunOnceRejectsMixedPlaylistAndDuplicateIdentityBatches(t *testing.T) {
|
||||
creator := &creatorSpy{}
|
||||
worker := workerFor(func(_ context.Context, _ time.Time, _ domain.Playlist, _ int) ([]domain.Candidate, error) {
|
||||
batch := candidates()
|
||||
batch[1].Playlist = domain.Ranked
|
||||
return batch, nil
|
||||
}, creator)
|
||||
if _, err := worker.RunOnce(context.Background()); err == nil {
|
||||
t.Fatal("mixed playlist was accepted")
|
||||
}
|
||||
worker.Source = func(_ context.Context, _ time.Time, _ domain.Playlist, _ int) ([]domain.Candidate, error) {
|
||||
batch := candidates()
|
||||
batch[1].PlayerID = batch[0].PlayerID
|
||||
return batch, nil
|
||||
}
|
||||
if _, err := worker.RunOnce(context.Background()); err == nil {
|
||||
t.Fatal("duplicate identity was accepted")
|
||||
}
|
||||
if creator.calls != 0 {
|
||||
t.Fatalf("creator calls=%d", creator.calls)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user