mirror of
https://github.com/hanzoai/ci.git
synced 2026-10-20 15:28:05 +00:00
Hanzo CI/CD / cicd (push) Waiting to run
CI/CD / gate (push) Waiting to run
These types are published through the composed cloud document, whose
schema namespace is FLAT and global: `Service` appears in fifty-three
other app documents, `Run` and `Head` in ten each, and two names that
differ only in case are worse still — every generator PascalCases, so an
SDK binds whichever it read last or refuses to compile.
Three of the five are better names besides:
Version -> Artifact a tag and a digest identifying built bytes is
not a version; nothing here is semver.
Head -> Tip its own comment already said "the tip of the
default branch".
Service -> Pipeline the row is not a workload, it is the chain
behind one: head, built, declared, running.
Run -> Execution } free names for the two that only collided
Build -> Check }
The wire does not move: JSON comes from the tags and those are
untouched, which the shape test asserts. What changes is the name a
generated client gives the class.
Co-authored-by: Hanzo Dev <[email protected]>
118 lines
4.7 KiB
Go
118 lines
4.7 KiB
Go
package ci
|
|
|
|
import "testing"
|
|
|
|
// declared_test.go pins the reader against the shapes the fleet's values files
|
|
// actually take. It is weighted toward refusals: a reader that guesses would put
|
|
// a wrong version on the one page whose whole job is saying what is declared, and
|
|
// a wrong number there is worse than a blank, because a blank is visibly unknown.
|
|
|
|
func TestDeclaredReadsTheFleetsShapes(t *testing.T) {
|
|
cases := []struct {
|
|
name, body, image string
|
|
want Artifact
|
|
}{{
|
|
name: "tag and digest, the shape of almost every service",
|
|
body: "replicas: 1\nimage:\n repository: ghcr.io/hanzoai/cloud\n" +
|
|
" tag: v1.801.548\n digest: sha256:8830c2b1\n pullPolicy: IfNotPresent\n",
|
|
image: "ghcr.io/hanzoai/cloud",
|
|
want: Artifact{Tag: "v1.801.548", Digest: "sha256:8830c2b1"},
|
|
}, {
|
|
// The pin a human reads and the bytes the kubelet pulls are written in
|
|
// one edit, and comments explaining a release sit between them.
|
|
name: "comments inside the block",
|
|
body: "image:\n repository: ghcr.io/hanzoai/cloud\n" +
|
|
" # ROLLED BACK — the newer tag served no routes.\n #\n" +
|
|
" # Measured from outside the cluster.\n" +
|
|
" tag: v1.801.357\n digest: sha256:aabb\n",
|
|
image: "ghcr.io/hanzoai/cloud",
|
|
want: Artifact{Tag: "v1.801.357", Digest: "sha256:aabb"},
|
|
}, {
|
|
name: "pinned by digest alone",
|
|
body: "image:\n repository: ghcr.io/hanzoai/iam\n digest: sha256:ccdd\n pullPolicy: Always\n",
|
|
image: "ghcr.io/hanzoai/iam",
|
|
want: Artifact{Digest: "sha256:ccdd"},
|
|
}, {
|
|
name: "pinned by tag alone",
|
|
body: "image:\n repository: ghcr.io/hanzoai/bot-gateway\n tag: v0.3.1\n",
|
|
image: "ghcr.io/hanzoai/bot-gateway",
|
|
want: Artifact{Tag: "v0.3.1"},
|
|
}, {
|
|
name: "quoted",
|
|
body: "image:\n repository: \"ghcr.io/hanzoai/a\"\n tag: '0.1.0'\n",
|
|
image: "ghcr.io/hanzoai/a",
|
|
want: Artifact{Tag: "0.1.0"},
|
|
}, {
|
|
name: "a comment after the value is not the value",
|
|
body: "image:\n repository: ghcr.io/hanzoai/a # the published name\n tag: v1.0.0 # cut by hand\n",
|
|
image: "ghcr.io/hanzoai/a",
|
|
want: Artifact{Tag: "v1.0.0"},
|
|
}, {
|
|
name: "the block ends at the first dedent",
|
|
body: "image:\n repository: ghcr.io/hanzoai/a\n tag: v1.0.0\ningress:\n tag: not-an-image\n",
|
|
image: "ghcr.io/hanzoai/a",
|
|
want: Artifact{Tag: "v1.0.0"},
|
|
}}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
image, got := declared(tc.body)
|
|
if image != tc.image {
|
|
t.Fatalf("image = %q; want %q", image, tc.image)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("version = %+v; want %+v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestDeclaredRefusesWhatItDoesNotUnderstand — every one of these must yield no
|
|
// image, so the page shows the value as unknown rather than as a number nobody
|
|
// wrote.
|
|
func TestDeclaredRefusesWhatItDoesNotUnderstand(t *testing.T) {
|
|
cases := []struct{ name, body string }{
|
|
{"no image block at all — a chart of routes or hosts",
|
|
"replicas: 1\ningress:\n enabled: true\n hosts: [a.hanzo.ai]\n"},
|
|
{"empty file", ""},
|
|
{"a block with no repository", "image:\n tag: v1.0.0\n digest: sha256:aa\n"},
|
|
// A sidecar's image is not what the chart deploys, and reading it would
|
|
// report the fleet running a log shipper.
|
|
{"nested image belongs to something else",
|
|
"sidecars:\n- name: shipper\n image:\n repository: ghcr.io/other/shipper\n tag: v9\n"},
|
|
{"the word appears in prose only",
|
|
"# the image is published by the pipeline\nreplicas: 2\n"},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if image, v := declared(tc.body); image != "" {
|
|
t.Errorf("read image %q version %+v; want nothing", image, v)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSplitImageKeepsBothNames — a pinned reference names a release twice, and
|
|
// both halves are kept because they answer different questions.
|
|
func TestSplitImageKeepsBothNames(t *testing.T) {
|
|
cases := []struct {
|
|
ref, image string
|
|
want Artifact
|
|
}{
|
|
{"ghcr.io/hanzoai/cloud:v1.801.548@sha256:8830c2b1", "ghcr.io/hanzoai/cloud",
|
|
Artifact{Tag: "v1.801.548", Digest: "sha256:8830c2b1"}},
|
|
{"ghcr.io/hanzoai/cloud:v1.801.548", "ghcr.io/hanzoai/cloud", Artifact{Tag: "v1.801.548"}},
|
|
{"ghcr.io/hanzoai/cloud@sha256:8830", "ghcr.io/hanzoai/cloud", Artifact{Digest: "sha256:8830"}},
|
|
{"ghcr.io/hanzoai/cloud", "ghcr.io/hanzoai/cloud", Artifact{}},
|
|
// A colon before the last slash is a registry port, not a tag.
|
|
{"oci.hanzo.ai:5000/hanzo/a:v1", "oci.hanzo.ai:5000/hanzo/a", Artifact{Tag: "v1"}},
|
|
{"oci.hanzo.ai:5000/hanzo/a", "oci.hanzo.ai:5000/hanzo/a", Artifact{}},
|
|
}
|
|
for _, tc := range cases {
|
|
image, got := splitImage(tc.ref)
|
|
if image != tc.image || got != tc.want {
|
|
t.Errorf("splitImage(%q) = %q %+v; want %q %+v", tc.ref, image, got, tc.image, tc.want)
|
|
}
|
|
}
|
|
}
|