mesh-config drops an ended assignment as a removed one (issue 1098)
This commit is contained in:
@@ -551,3 +551,43 @@ func TestTheVerbsArgumentsAreReadStrictly(t *testing.T) {
|
||||
t.Errorf("read %+v (%v)", call, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 1098: a value of the assignments bucket with `ended` set, or with a `state`, is not an assignment: it
|
||||
// resolves nothing and takes the module's resolved values away, as a removed key does.
|
||||
func TestAnEndedAssignmentIsNotAnAssignment(t *testing.T) {
|
||||
c, m := aMesh(t)
|
||||
m.assign(t, "ace", "dunst")
|
||||
if r, err := c.Reconcile(); err != nil || len(r.Moved) != 4 {
|
||||
t.Fatalf("the assignment moved %+v (%v)", r.Moved, err)
|
||||
}
|
||||
for _, ended := range []string{`"ended":"2026-10-18T01:00:00Z"`, `"state":"pending"`} {
|
||||
m.mirror(t, AssignmentsRead, "ace.dunst", `{"node":"ace","module":"dunst","assigned":"2026-10-14T00:00:00Z",`+ended+`}`)
|
||||
r, err := c.Reconcile()
|
||||
if err != nil || len(r.Moved) != 4 || !r.Moved[0].Gone {
|
||||
t.Errorf("%s moved %+v (%v)", ended, r.Moved, err)
|
||||
}
|
||||
if e, _ := m.Get(ResolvedState, ResolvedKey("ace", "dunst", "font-size")); e != nil {
|
||||
t.Errorf("%s: the module keeps its resolved values", ended)
|
||||
}
|
||||
m.assign(t, "ace", "dunst")
|
||||
if r, _ = c.Reconcile(); len(r.Moved) != 4 {
|
||||
t.Fatalf("the assignment standing again moved %+v", r.Moved)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 1098: the fields the controller adds to an assignment change nothing, under the same key.
|
||||
func TestAnAssignmentCarriesBuildCommitAndRolloutWithoutChangingItsKey(t *testing.T) {
|
||||
c, m := aMesh(t)
|
||||
m.mirror(t, AssignmentsRead, "ace.dunst", `{"node":"ace","module":"dunst","assigned":"2026-10-14T00:00:00Z",`+
|
||||
`"build":"b-1","artifact":{"name":"dunst","version":"1.2"},"commit":"abc123","rollout":"r-9",`+
|
||||
`"since":"2026-10-18T00:00:00Z","ended":"","state":"","future":{"x":1}}`)
|
||||
r, err := c.Reconcile()
|
||||
if err != nil || len(r.Moved) != 4 {
|
||||
t.Fatalf("an assignment with the new fields moved %+v (%v)", r.Moved, err)
|
||||
}
|
||||
expect(t, m, "ace", "10", SourceDefault)
|
||||
if r, _ = c.Reconcile(); len(r.Moved) != 0 {
|
||||
t.Errorf("a quiet pass moved %+v", r.Moved)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,10 +121,24 @@ type Published struct {
|
||||
Commit string `json:"commit"`
|
||||
}
|
||||
|
||||
// Assignment is one key of the assignments mirror: a module on a node.
|
||||
// Assignment is one key of the assignments bucket: a module on a node. The value also carries the build, commit and
|
||||
// rollout that put it there and more; those are read where they are reported, and an unknown field never fails a
|
||||
// parse. **Ended** and **State** are set on a value that is not a standing assignment (novox/hq ADR 0408 clause 4):
|
||||
// it reads exactly as a removed key (issue 1098).
|
||||
type Assignment struct {
|
||||
Node string `json:"node"`
|
||||
Module string `json:"module"`
|
||||
Node string `json:"node"`
|
||||
Module string `json:"module"`
|
||||
Ended json.RawMessage `json:"ended,omitempty"`
|
||||
State json.RawMessage `json:"state,omitempty"`
|
||||
}
|
||||
|
||||
// Standing is whether the value is a standing assignment: neither ended nor in a state.
|
||||
func (a Assignment) Standing() bool { return !fieldSet(a.Ended) && !fieldSet(a.State) }
|
||||
|
||||
// fieldSet is whether a field of an assignment's value carries something: not absent, null or empty.
|
||||
func fieldSet(f json.RawMessage) bool {
|
||||
s := strings.TrimSpace(string(f))
|
||||
return s != "" && s != "null" && s != `""`
|
||||
}
|
||||
|
||||
// rule is the validation a value is held to, from a module's declaration or a predefined key.
|
||||
|
||||
@@ -19,6 +19,9 @@ func (c *Config) sources() (Sources, error) {
|
||||
if err := json.Unmarshal(raw, &a); err != nil || a.Node == "" || a.Module == "" {
|
||||
return fmt.Errorf("the assignment %s is not one: %s", key, raw)
|
||||
}
|
||||
if !a.Standing() {
|
||||
return nil // ended or pending: read as a removed key (issue 1098)
|
||||
}
|
||||
s.Assignments = append(s.Assignments, a)
|
||||
return nil
|
||||
}); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user