build-hours takes one window and names no node, node names enter digests and checks by their clauses, and a leftover particulars file is refused
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
// Command noplacement refuses what the repository path of placement left behind (novox/hq ADR 0567 §1, §8, §10).
|
||||
// Command noplacement refuses what the repository path of placement left behind (novox/hq ADR 0567 §10, §12).
|
||||
//
|
||||
// Placement, which module runs on which node, is bus state held by the seat mesh-placement; no file of the
|
||||
// catalogue says it, and no manifest reads it from the delivery indexer, which no longer keeps it. It refuses:
|
||||
//
|
||||
// 1. a `placement` directory (or file) at the root of the catalogue;
|
||||
//
|
||||
// 2. a manifest naming a state, stream, event or bucket of the indexer's placement (`mesh-delivery-indexer.placement…`
|
||||
// 2. a `particulars` file at the root (the mesh's node names come from the checker's run, §16);
|
||||
//
|
||||
// 3. a manifest naming a state, stream, event or bucket of the indexer's placement (`mesh-delivery-indexer.placement…`
|
||||
// or `mesh-delivery-indexer_placement…`) in any string value, such as `reads`.
|
||||
//
|
||||
// go run . <catalogue root>
|
||||
@@ -29,7 +31,10 @@ var Prefixes = []string{"mesh-delivery-indexer.placement", "mesh-delivery-indexe
|
||||
func Findings(root string) ([]string, error) {
|
||||
var out []string
|
||||
if _, err := os.Lstat(filepath.Join(root, "placement")); err == nil {
|
||||
out = append(out, "placement: the repository holds no placement; it is bus state of the seat mesh-placement (novox/hq ADR 0567 §1)")
|
||||
out = append(out, "placement: the repository holds no placement; it is bus state of the seat mesh-placement (novox/hq ADR 0567 §10)")
|
||||
}
|
||||
if _, err := os.Lstat(filepath.Join(root, "particulars")); err == nil {
|
||||
out = append(out, "particulars: the repository lists no node names; the checker hands them to the check (novox/hq ADR 0567 §16)")
|
||||
}
|
||||
manifests, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
|
||||
if err != nil {
|
||||
@@ -47,7 +52,7 @@ func Findings(root string) ([]string, error) {
|
||||
}
|
||||
module := filepath.Base(filepath.Dir(file))
|
||||
for _, s := range named(doc, nil) {
|
||||
out = append(out, fmt.Sprintf("%s: names %q, which the indexer no longer keeps; placement is the seat mesh-placement's (novox/hq ADR 0567 §8)", module, s))
|
||||
out = append(out, fmt.Sprintf("%s: names %q, which the indexer no longer keeps; placement is the seat mesh-placement's (novox/hq ADR 0567 §12)", module, s))
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
|
||||
@@ -15,6 +15,7 @@ func TestFindingsRefuseWhatThePlacementPathLeft(t *testing.T) {
|
||||
}{
|
||||
{"clean", map[string]string{"modules/a/module.json": `{"module":"a","reads":["mesh-controller.assignments"]}`}, ""},
|
||||
{"a placement directory", map[string]string{"placement/ace.json": `{}`}, "placement: the repository holds no placement"},
|
||||
{"a particulars file", map[string]string{"particulars": "ace\n"}, "particulars: the repository lists no node names"},
|
||||
{"a read of the indexer's placement", map[string]string{"modules/a/module.json": `{"module":"a","reads":["mesh-delivery-indexer.placement"]}`}, `a: names "mesh-delivery-indexer.placement"`},
|
||||
{"a read of its candidates", map[string]string{"modules/b/module.json": `{"module":"b","reads":["mesh-delivery-indexer.placement-candidates"]}`}, "placement-candidates"},
|
||||
{"its event", map[string]string{"modules/c/module.json": `{"module":"c","on":[{"event":"mesh-delivery-indexer.placement-changed"}]}`}, "placement-changed"},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// fixture of a covered module names a node of this one.
|
||||
//
|
||||
// The names are the mesh's own, not the repository's: the checker hands them in the environment value
|
||||
// MESH_NODE_NAMES, comma-separated, from the node records it reads (novox/hq ADR 0567 §11). A run with none fails
|
||||
// MESH_NODE_NAMES, comma-separated, from the node records it reads (novox/hq ADR 0567 §16). A run with none fails
|
||||
// loudly, since it would pass on anything. The modules covered are in `covered` at checks/particulars/covered, one a line. A name is matched
|
||||
// whole and in any case; a hyphen, an underscore or a CamelCase boundary parts one, so a longer word holding a name is another word.
|
||||
// The forge is not a node name: its host (git.novox.be) and the organisation path (novox/<repo>) are blanked
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -126,7 +127,8 @@ func TestManifestClaimsTheGoBuildSeatAndReadsItsCapacity(t *testing.T) {
|
||||
raw, _ := os.ReadFile(moduleDir + "/module.json")
|
||||
var doc struct {
|
||||
Config map[string]struct {
|
||||
Default json.RawMessage `json:"default"`
|
||||
Default json.RawMessage `json:"default"`
|
||||
Pattern, Description string
|
||||
} `json:"config"`
|
||||
}
|
||||
_ = json.Unmarshal(raw, &doc)
|
||||
@@ -144,6 +146,16 @@ func TestManifestClaimsTheGoBuildSeatAndReadsItsCapacity(t *testing.T) {
|
||||
if w, fault := buildstep.NodeBuildHours(moduleDir+"/files/settings.json", "g14", t.Errorf)(); w != nil || fault != "" {
|
||||
t.Errorf("the settings template holds build hours %v (%s)", w, fault)
|
||||
}
|
||||
// ADR 0567 §15: build-hours names no node (one window, or empty for any hour) and capacity defaults to 0.
|
||||
window := regexp.MustCompile("^(?:" + doc.Config[buildstep.BuildHoursSetting].Pattern + ")$")
|
||||
for value, ok := range map[string]bool{"": true, "18:00-06:00": true, "g14=18:00-06:00": false, "18:00": false} {
|
||||
if window.MatchString(value) != ok {
|
||||
t.Errorf("build-hours pattern on %q: accepted %v, want %v", value, !ok, ok)
|
||||
}
|
||||
}
|
||||
if strings.Contains(doc.Config[buildstep.BuildHoursSetting].Description, "=") {
|
||||
t.Errorf("the build-hours description names a node pair")
|
||||
}
|
||||
var capacity float64
|
||||
_ = json.Unmarshal(doc.Config[buildstep.CapacitySetting].Default, &capacity)
|
||||
if capacity != 0 {
|
||||
|
||||
@@ -38,7 +38,7 @@ const DigestVersion = "6"
|
||||
const besideVariable = "MESH_CHECK_BESIDE"
|
||||
|
||||
// namesVariable is the same for the mesh's node names: a package whose tests reach a file naming it depends on the node
|
||||
// list the ask carries, so its digest holds the sorted names and a new node misses a kept verdict (ADR 0567 §12).
|
||||
// list the ask carries, so its digest holds the sorted names and a new node misses a kept verdict (ADR 0567 §15).
|
||||
const namesVariable = "MESH_NODE_NAMES"
|
||||
|
||||
// ReadsOutsideMarker is the name of a file in a package's directory that says its tests read files outside it (a
|
||||
|
||||
@@ -189,7 +189,7 @@ func TestAModuleOutsideTheTreeCountsByVersionAndChecksum(t *testing.T) {
|
||||
if d3 := digest(); d3 == d1 {
|
||||
t.Errorf("a new version left the digest as it was")
|
||||
}
|
||||
// A different node list misses the cache only for a package whose tests read MESH_NODE_NAMES (ADR 0567 §12).
|
||||
// A different node list misses the cache only for a package whose tests read MESH_NODE_NAMES (ADR 0567 §15).
|
||||
names = []string{"node-names a"}
|
||||
d4 := digest()
|
||||
names = []string{"node-names a", "node-names b"}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"build-hours": {
|
||||
"type": "string",
|
||||
"description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.",
|
||||
"pattern": "|[a-z0-9_-]+=([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9](,[a-z0-9_-]+=([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9])*",
|
||||
"pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]",
|
||||
"default": ""
|
||||
},
|
||||
"cores-per-step": {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -121,6 +123,30 @@ func TestManifestKeepsItsStatesClaimsItsBuildSeatAndDeclaresItsHealthTool(t *tes
|
||||
if strings.TrimSpace(string(tpl)) != "${seat:mesh-artifact-store:reach}" {
|
||||
t.Errorf("registry template = %q", tpl)
|
||||
}
|
||||
raw, _ = os.ReadFile(filepath.Join(moduleDir, "module.json"))
|
||||
var doc struct {
|
||||
Config map[string]struct {
|
||||
Default json.RawMessage `json:"default"`
|
||||
Pattern, Description string
|
||||
} `json:"config"`
|
||||
}
|
||||
_ = json.Unmarshal(raw, &doc)
|
||||
var capacity float64 = -1
|
||||
_ = json.Unmarshal(doc.Config["capacity"].Default, &capacity)
|
||||
if capacity != 0 {
|
||||
t.Errorf("the capacity's default = %g, want 0", capacity)
|
||||
}
|
||||
// ADR 0567 §15: build-hours names no node (one window, or empty for any hour) and capacity defaults to 0.
|
||||
window := regexp.MustCompile("^(?:" + doc.Config["build-hours"].Pattern + ")$")
|
||||
for value, ok := range map[string]bool{"": true, "18:00-06:00": true, "g14=18:00-06:00": false, "18:00": false} {
|
||||
if window.MatchString(value) != ok {
|
||||
t.Errorf("build-hours pattern on %q: accepted %v, want %v", value, !ok, ok)
|
||||
}
|
||||
}
|
||||
if strings.Contains(doc.Config["build-hours"].Description, "=") {
|
||||
t.Errorf("the build-hours description names a node pair")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Every tool the manifest names is served, and every tool served is named.
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"build-hours": {
|
||||
"type": "string",
|
||||
"description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.",
|
||||
"pattern": "|[a-z0-9_-]+=([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9](,[a-z0-9_-]+=([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9])*",
|
||||
"pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]",
|
||||
"default": ""
|
||||
},
|
||||
"cores-per-step": {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -84,7 +85,8 @@ func TestManifestTakesTheBuildCapacity(t *testing.T) {
|
||||
raw, _ := os.ReadFile(moduleDir + "/module.json")
|
||||
var doc struct {
|
||||
Config map[string]struct {
|
||||
Default json.RawMessage `json:"default"`
|
||||
Default json.RawMessage `json:"default"`
|
||||
Pattern, Description string
|
||||
} `json:"config"`
|
||||
}
|
||||
_ = json.Unmarshal(raw, &doc)
|
||||
@@ -102,6 +104,16 @@ func TestManifestTakesTheBuildCapacity(t *testing.T) {
|
||||
if w, fault := buildstep.NodeBuildHours(moduleDir+"/files/settings.json", "g14", t.Errorf)(); w != nil || fault != "" {
|
||||
t.Errorf("the settings template holds build hours %v (%s)", w, fault)
|
||||
}
|
||||
// ADR 0567 §15: build-hours names no node (one window, or empty for any hour) and capacity defaults to 0.
|
||||
window := regexp.MustCompile("^(?:" + doc.Config[buildstep.BuildHoursSetting].Pattern + ")$")
|
||||
for value, ok := range map[string]bool{"": true, "18:00-06:00": true, "g14=18:00-06:00": false, "18:00": false} {
|
||||
if window.MatchString(value) != ok {
|
||||
t.Errorf("build-hours pattern on %q: accepted %v, want %v", value, !ok, ok)
|
||||
}
|
||||
}
|
||||
if strings.Contains(doc.Config[buildstep.BuildHoursSetting].Description, "=") {
|
||||
t.Errorf("the build-hours description names a node pair")
|
||||
}
|
||||
var capacity float64
|
||||
_ = json.Unmarshal(doc.Config[buildstep.CapacitySetting].Default, &capacity)
|
||||
if capacity != 0 {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"build-hours": {
|
||||
"type": "string",
|
||||
"description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.",
|
||||
"pattern": "|[a-z0-9_-]+=([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9](,[a-z0-9_-]+=([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9])*",
|
||||
"pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]",
|
||||
"default": ""
|
||||
},
|
||||
"cores-per-step": {
|
||||
|
||||
Reference in New Issue
Block a user