package sync import ( "path/filepath" "strings" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/stacks" ) // v0.269.0 (`09` §6.4 part 6) — the syncer writes the catalog's compose WITH the tested digests of the // ladder entry for exactly its refs, for an undeployed app and for a pinned app the catalog still matches; // and the stored definition is refreshed with the same bytes. // // COMPANION RED-PROOF (REPORT): make RenderWithLadderDigests return its input — the image line stays a bare // tag and this test fails at "no digest in the rendered compose". func TestDigest_SyncerRendersTheTestedDigest(t *testing.T) { s, stackDir, catDir := renderFixture(t, tplOld) write(t, filepath.Join(catDir, ".felhom.yml"), "display_name: Nextcloud\nupdate_ladder:\n"+ ` - {"from": {"web": "nextcloud:30.0.0-apache"}, "to": {"web": "nextcloud:31.0.14-apache"}, "digest": {"web": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "verdict": "proven", "tested_at": "2026-09-24T01:00:00Z"}`+"\n") for _, plan := range []func(string) stacks.RenderPlan{ func(string) stacks.RenderPlan { return stacks.RenderPlan{} }, // not deployed func(string) stacks.RenderPlan { p := pinnedPlan(stackDir, map[string]string{"web": "nextcloud:31.0.14-apache"}, false)("") p.StackDir = stackDir return p }, } { write(t, filepath.Join(stackDir, "docker-compose.yml"), "services: {}\n") // force a change each pass s.SetRenderPlanFn(plan) if _, _, err := s.copyTemplates(); err != nil { t.Fatal(err) } got := readFile(t, filepath.Join(stackDir, "docker-compose.yml")) if !strings.Contains(got, "image: nextcloud:31.0.14-apache@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") { t.Fatalf("no digest in the rendered compose:\n%s", got) } } if !strings.Contains(readFile(t, stacks.AppliedComposePath(stackDir)), "@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") { t.Fatal("the stored definition was not refreshed with the digest") } }