v0.235.0: a delivered fix must also refresh the stored definition
gates / gates (push) Successful in 14s
gates / gates (push) Successful in 14s
Found by the LIVE validation on demo-hp, not by review. Scenario A passed - a non-image catalog change reached the pinned app on the real 15-minute cycle - and that is exactly what exposed the gap: the stored applied-compose.yml is written when the PIN is written, so the fix landed in the live compose file and not in the store. The first time the catalog then moved a version, the freeze would have rendered the pre-fix definition and reverted every fix delivered since - silently undoing the half of the operator's ruling that says fixes keep flowing. The equal-images branch now refreshes the store as it delivers. The images cannot move in that branch by construction, so no version moves and no intent is rewritten. RenderPlan gains StackDir so the syncer can write it. TestFixRefreshesTheStoredDefinition asserts both halves: the fix reaches the store, and it survives the freeze that follows.
This commit is contained in:
@@ -265,3 +265,52 @@ func TestRenderTable_EmptyStoredDefinitionIsTreatedAsAbsent(t *testing.T) {
|
||||
t.Fatal("an empty compose file was written over a live app")
|
||||
}
|
||||
}
|
||||
|
||||
// TestFixRefreshesTheStoredDefinition — found by the LIVE validation of v0.235.0, not by review.
|
||||
//
|
||||
// The stored definition is written when the pin is written. A fix delivered afterwards lands in the
|
||||
// live compose file but NOT in the stored one — so the first time the catalog moves a version, the
|
||||
// freeze reverts every fix delivered since, silently undoing the half of the ruling that says fixes
|
||||
// keep flowing. The equal-images branch therefore refreshes the store as it delivers.
|
||||
//
|
||||
// The IMAGES cannot move here by construction: this branch only runs when the catalog's images equal
|
||||
// the pin. No version moves and no intent is rewritten.
|
||||
func TestFixRefreshesTheStoredDefinition(t *testing.T) {
|
||||
s, stackDir, _ := renderFixture(t, tplOldFixed) // same version, fixed healthcheck
|
||||
live := filepath.Join(stackDir, "docker-compose.yml")
|
||||
write(t, live, tplOld)
|
||||
write(t, stacks.AppliedComposePath(stackDir), tplOld)
|
||||
s.SetRenderPlanFn(func(string) stacks.RenderPlan {
|
||||
return stacks.RenderPlan{Deployed: true, StackDir: stackDir,
|
||||
Pinned: map[string]string{"web": "nextcloud:31.0.14-apache"},
|
||||
AppliedPath: stacks.AppliedComposePath(stackDir)}
|
||||
})
|
||||
|
||||
if _, _, err := s.copyTemplates(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stored, err := stacks.LoadAppliedDefinition(stackDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(stored), "status.php") {
|
||||
t.Fatalf("the delivered fix must also become part of what the app is pinned TO:\n%s", stored)
|
||||
}
|
||||
if !strings.Contains(string(stored), "31.0.14-apache") {
|
||||
t.Fatalf("refreshing the store must NOT move the version:\n%s", stored)
|
||||
}
|
||||
|
||||
// And now the catalog moves: the freeze must keep the fix, not revert to the pre-fix definition.
|
||||
catDir := filepath.Join(filepath.Dir(filepath.Dir(stackDir)), "data", "catalog-cache", "templates", "nextcloud")
|
||||
write(t, filepath.Join(catDir, "docker-compose.yml"), tplNew)
|
||||
if _, _, err := s.copyTemplates(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := readFile(t, live)
|
||||
if strings.Contains(got, "34.0.1") {
|
||||
t.Fatalf("the version must be frozen:\n%s", got)
|
||||
}
|
||||
if !strings.Contains(got, "status.php") {
|
||||
t.Fatalf("the freeze must keep the fix that was delivered while the versions matched:\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user