A build ask its seat's worker gave up on could only be dropped, though the controller already holds the publish on that seat's accepts and the stream API to remove the original. Asks to other seats stay refused: delivering them needs a grant ADR 0264 withholds, in the asker's name ADR 0259 protects.
103 lines
3.8 KiB
Go
103 lines
3.8 KiB
Go
package link
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/nats-io/nats.go"
|
|
"github.com/nats-io/nats.go/jetstream"
|
|
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
)
|
|
|
|
// What a seat's worker gave up on, when the ask is one the controller itself makes (novox/hq issue 334).
|
|
//
|
|
// The controller already publishes on the accept subjects of the seats it asks (broker's
|
|
// seatsTheControllerAsks) and reaches the stream API, so delivering its own ask again needs no grant it
|
|
// does not hold: the original is removed from the work queue by its sequence, and the kept copy is
|
|
// published on the ask's own subject, where the seat's one worker takes it. An ask to any other seat is
|
|
// still refused, and stays kept: delivering it would need a publish the controller is not granted
|
|
// (ADR 0264's consequences), in the asker's name (ADR 0259 §3).
|
|
|
|
// theBuildWorker is the build seat's worker as a holder pulls from it.
|
|
func theBuildWorker(t *testing.T, js *broker.JetStream) jetstream.Consumer {
|
|
t.Helper()
|
|
api, err := jetstream.New(js.Conn())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
stream := "SEAT_NODE_BUILD_AGENT"
|
|
worker, err := api.Consumer(t.Context(), stream, stream+"_worker")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return worker
|
|
}
|
|
|
|
func TestAnAskTheControllerMadeIsDeliveredAgainToTheSeatsWorker(t *testing.T) {
|
|
js := aBusWithTheBuildRole(t)
|
|
keeping(t, js)
|
|
worker := theBuildWorker(t, js)
|
|
|
|
subject := BuildWorkOf(TheBuildMachine)
|
|
ask := &nats.Msg{Subject: subject, Data: []byte(`{"module":"x"}`), Header: nats.Header{}}
|
|
ask.Header.Set(nats.MsgIdHdr, "build-1")
|
|
if _, err := js.Context().PublishMsg(ask); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d := givenUp(t, js, worker)
|
|
if d.Stream != "SEAT_NODE_BUILD_AGENT" || d.Subject != subject || d.Lost != "" {
|
|
t.Fatalf("kept as %+v", d)
|
|
}
|
|
if _, err := js.Context().GetMsg(d.Stream, d.Sequence); err != nil {
|
|
t.Fatalf("the original is not in the work queue before it is delivered again: %v", err)
|
|
}
|
|
|
|
_, to, err := DeliverAgain(js.Context(), d.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if to != subject {
|
|
t.Fatalf("delivered again on %s, not the ask's own subject %s", to, subject)
|
|
}
|
|
if _, err := js.Context().GetMsg(d.Stream, d.Sequence); !errors.Is(err, nats.ErrMsgNotFound) {
|
|
t.Fatalf("the original is still in the work queue beside its copy: %v", err)
|
|
}
|
|
again := next(t, worker)
|
|
if again == nil {
|
|
t.Fatal("the seat's worker was not handed the ask again")
|
|
}
|
|
if string(again.Data()) != `{"module":"x"}` || again.Headers().Get(AgainHeader) == "" {
|
|
t.Fatalf("handed again as %s %v", again.Data(), again.Headers())
|
|
}
|
|
_ = again.Ack()
|
|
if m := next(t, worker); m != nil {
|
|
t.Fatalf("the worker was handed it twice: %s", m.Subject())
|
|
}
|
|
if _, err := DeadLetterNamed(js.Context(), d.ID); !errors.Is(err, ErrNoDeadLetter) {
|
|
t.Fatalf("still kept after it was delivered again: %v", err)
|
|
}
|
|
if _, _, err := DeliverAgain(js.Context(), d.ID); !errors.Is(err, ErrNoDeadLetter) {
|
|
t.Fatalf("a second delivery answered %v", err)
|
|
}
|
|
}
|
|
|
|
// An ask to a seat the controller does not ask is refused, says why, and nothing is done.
|
|
func TestAnAskTheControllerDidNotMakeIsStillOnlyDropped(t *testing.T) {
|
|
js := aBus(t)
|
|
for _, d := range []DeadLetter{
|
|
{ID: 2, Stream: "SEAT_TELEGRAM_SENDER", Consumer: "SEAT_TELEGRAM_SENDER_worker",
|
|
Subject: "mesh.seat.telegram-sender.accept.send"},
|
|
// The subject of a seat the controller asks, on a stream that is not that seat's queue.
|
|
{ID: 3, Stream: "SEAT_TELEGRAM_SENDER", Consumer: "SEAT_TELEGRAM_SENDER_worker",
|
|
Subject: "mesh.seat.node-build-agent.accept.build"},
|
|
} {
|
|
if to, err := AgainTo(js.Context(), d); err == nil {
|
|
t.Errorf("%s on %s was given %s to be delivered again on", d.Subject, d.Stream, to)
|
|
} else if !strings.Contains(err.Error(), "Drop it") {
|
|
t.Errorf("refused without saying what to do: %v", err)
|
|
}
|
|
}
|
|
}
|