A deleting head's answer compares the controller's compositions with what runs, and is refused only without returning; fold the shadow's tests into TestInput (issue 1126, review of the shadow, round 1)
This commit is contained in:
@@ -17,7 +17,7 @@ import (
|
|||||||
// Issue 1126 (the seed's shadow, round 2): a node's answer names every module it cannot compose, not the first only;
|
// Issue 1126 (the seed's shadow, round 2): a node's answer names every module it cannot compose, not the first only;
|
||||||
// and a module folded into its own composition that names a build of the old form (de-spiegel on novox, nats, photos,
|
// and a module folded into its own composition that names a build of the old form (de-spiegel on novox, nats, photos,
|
||||||
// systemd-resolved: their haves name a build-... id and no fingerprint) is left to the node, carried as it runs.
|
// systemd-resolved: their haves name a build-... id and no fingerprint) is left to the node, carried as it runs.
|
||||||
func TestTheAnswerNamesEveryRefusalAndLeavesAnOldBuildToTheNode(t *testing.T) {
|
func answerNamesEveryRefusalAndLeavesAnOldBuildToTheNode(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
image := "alpine@sha256:" + strings.Repeat("a", 64)
|
image := "alpine@sha256:" + strings.Repeat("a", 64)
|
||||||
manifest := func(module string) []byte {
|
manifest := func(module string) []byte {
|
||||||
@@ -138,7 +138,7 @@ func TestTheAnswerNamesEveryRefusalAndLeavesAnOldBuildToTheNode(t *testing.T) {
|
|||||||
|
|
||||||
// A node that reaches no artifact store says what its composition holds of one (issue 1126: ace and g14 answered
|
// A node that reaches no artifact store says what its composition holds of one (issue 1126: ace and g14 answered
|
||||||
// "reaches no artifact store", and nothing said why).
|
// "reaches no artifact store", and nothing said why).
|
||||||
func TestNoStoreReachedSaysWhy(t *testing.T) {
|
func noStoreReachedSaysWhy(t *testing.T) {
|
||||||
in := compose.Input{Catalogue: map[string]catalogue.Manifest{
|
in := compose.Input{Catalogue: map[string]catalogue.Manifest{
|
||||||
"distribution": {Module: "distribution", Serves: map[string]map[string]any{catalogue.ArtifactStoreProvision: {"port": 5000}}}},
|
"distribution": {Module: "distribution", Serves: map[string]map[string]any{catalogue.ArtifactStoreProvision: {"port": 5000}}}},
|
||||||
Nodes: []compose.Node{{Name: "g14", Assigned: []string{"adwaita"}}, {Name: "novox", Assigned: []string{"distribution"}}}}
|
Nodes: []compose.Node{{Name: "g14", Assigned: []string{"adwaita"}}, {Name: "novox", Assigned: []string{"distribution"}}}}
|
||||||
@@ -119,6 +119,10 @@ func publicKey(t *testing.T) string {
|
|||||||
// controller's store fills for compose's own two-machine mesh (compose's aMesh: anchor the hub, laptop), and that Input
|
// controller's store fills for compose's own two-machine mesh (compose's aMesh: anchor the hub, laptop), and that Input
|
||||||
// composes; a node reads only its own config values; what cannot be composed is refused, naming it.
|
// composes; a node reads only its own config values; what cannot be composed is refused, naming it.
|
||||||
func TestInput(t *testing.T) {
|
func TestInput(t *testing.T) {
|
||||||
|
// Issue 1126, the seed's shadow: every refusal named, an old-form module left to the node, and no store reached
|
||||||
|
// saying why (answer_rows_test.go).
|
||||||
|
t.Run("every refusal, and an old build left to the node", answerNamesEveryRefusalAndLeavesAnOldBuildToTheNode)
|
||||||
|
t.Run("no store reached says why", noStoreReachedSaysWhy)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
xterm, err := os.ReadFile("../../catalogue/testdata/catalogue-835bf22b-xterm.module.json")
|
xterm, err := os.ReadFile("../../catalogue/testdata/catalogue-835bf22b-xterm.module.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -134,8 +134,9 @@ type CandidateAnswer struct {
|
|||||||
Refused string `json:"refused,omitempty"`
|
Refused string `json:"refused,omitempty"`
|
||||||
// Returns is, for a head that deletes the node's placement file, what the node does then: it returns to the
|
// Returns is, for a head that deletes the node's placement file, what the node does then: it returns to the
|
||||||
// controller's compositions (ReturnsToController), as a node the catalogue does not place composes none of its own
|
// controller's compositions (ReturnsToController), as a node the catalogue does not place composes none of its own
|
||||||
// (issue 1126: the seed's revert). The verdict is then same, and nothing else is named: the node composes nothing
|
// (issue 1126: the seed's revert). Same, Differs, Added and Removed then compare the controller's compositions at
|
||||||
// with the candidate, and judges nothing of what the controller composes.
|
// the node's wants with what it runs, and the verdict is theirs; a want the controller holds no composition for is
|
||||||
|
// refused (Refused, without Returns).
|
||||||
Returns string `json:"returns,omitempty"`
|
Returns string `json:"returns,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,8 +196,9 @@ func (a CandidateAnswer) check() error {
|
|||||||
if a.Refused != "" && len(a.Same)+len(a.Differs)+len(a.Added)+len(a.Removed)+len(a.Refusals) > 0 {
|
if a.Refused != "" && len(a.Same)+len(a.Differs)+len(a.Added)+len(a.Removed)+len(a.Refusals) > 0 {
|
||||||
return fmt.Errorf("delivery: a candidate the node could not compose names modules")
|
return fmt.Errorf("delivery: a candidate the node could not compose names modules")
|
||||||
}
|
}
|
||||||
if a.Returns != "" && (a.Refused != "" || len(a.Same)+len(a.Differs)+len(a.Added)+len(a.Removed)+len(a.Refusals) > 0) {
|
if a.Returns != "" && (a.Refused != "" || len(a.Refusals) > 0) {
|
||||||
return fmt.Errorf("delivery: a candidate the node returns to the controller's compositions on names what it composed")
|
return fmt.Errorf("delivery: a candidate the node returns to the controller's compositions on is compared, never refused: " +
|
||||||
|
"a composition the controller holds none of is refused without returning")
|
||||||
}
|
}
|
||||||
for _, d := range a.Differs {
|
for _, d := range a.Differs {
|
||||||
if d.Module == "" || d.Why == "" {
|
if d.Module == "" || d.Why == "" {
|
||||||
|
|||||||
@@ -231,7 +231,9 @@ func TestPlacement(t *testing.T) {
|
|||||||
"a value": {Head: "h1", Verdict: CandidateRefused, Same: []string{"node"}, Refusals: []ModuleRefused{{Module: "db", Why: "stands in for db/password"}}},
|
"a value": {Head: "h1", Verdict: CandidateRefused, Same: []string{"node"}, Refusals: []ModuleRefused{{Module: "db", Why: "stands in for db/password"}}},
|
||||||
// A head that deletes the node's placement file: the node returns to the controller's compositions (issue 1126,
|
// A head that deletes the node's placement file: the node returns to the controller's compositions (issue 1126,
|
||||||
// the seed's revert, mesh-catalog #526).
|
// the seed's revert, mesh-catalog #526).
|
||||||
"returns": {Head: "h1", Verdict: CandidateSame, Returns: ReturnsToController},
|
"returns": {Head: "h1", Verdict: CandidateSame, Returns: ReturnsToController, Same: []string{"app", "node"}},
|
||||||
|
"returns, the controller's differs": {Head: "h1", Verdict: CandidateDiffers, Returns: ReturnsToController, Same: []string{"node"},
|
||||||
|
Differs: []ModuleDiffers{{Module: "app", Resource: "file:/etc/app", Why: "the resource differs"}}, Removed: []string{"old"}},
|
||||||
}
|
}
|
||||||
n := HaveNode{Composed: "sha256:" + strings.Repeat("a", 64), Sealed: []string{"box"}, Candidates: answers,
|
n := HaveNode{Composed: "sha256:" + strings.Repeat("a", 64), Sealed: []string{"box"}, Candidates: answers,
|
||||||
Composes: ComposesOwn, ComposesWhy: "the catalogue places it (placement.n1)"}
|
Composes: ComposesOwn, ComposesWhy: "the catalogue places it (placement.n1)"}
|
||||||
@@ -297,7 +299,7 @@ func TestPlacement(t *testing.T) {
|
|||||||
"same with an added": {Head: "h", Verdict: CandidateSame, Added: []ModuleAdded{{Module: "a"}}},
|
"same with an added": {Head: "h", Verdict: CandidateSame, Added: []ModuleAdded{{Module: "a"}}},
|
||||||
"differs refusing": {Head: "h", Verdict: CandidateDiffers, Removed: []string{"a"}, Refusals: []ModuleRefused{{Module: "b", Why: "x"}}},
|
"differs refusing": {Head: "h", Verdict: CandidateDiffers, Removed: []string{"a"}, Refusals: []ModuleRefused{{Module: "b", Why: "x"}}},
|
||||||
"refused and modules": {Head: "h", Verdict: CandidateRefused, Refused: "x", Same: []string{"a"}},
|
"refused and modules": {Head: "h", Verdict: CandidateRefused, Refused: "x", Same: []string{"a"}},
|
||||||
"returns and removes": {Head: "h", Verdict: CandidateDiffers, Returns: ReturnsToController, Removed: []string{"a"}},
|
"returns refusing": {Head: "h", Verdict: CandidateRefused, Returns: ReturnsToController, Refusals: []ModuleRefused{{Module: "b", Why: "x"}}},
|
||||||
"returns refused": {Head: "h", Verdict: CandidateRefused, Returns: ReturnsToController, Refused: "x"},
|
"returns refused": {Head: "h", Verdict: CandidateRefused, Returns: ReturnsToController, Refused: "x"},
|
||||||
} {
|
} {
|
||||||
if _, err := EncodeHaveNode(HaveNode{Candidates: map[string]CandidateAnswer{"g": a}}); err == nil {
|
if _, err := EncodeHaveNode(HaveNode{Candidates: map[string]CandidateAnswer{"g": a}}); err == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user