mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-03 18:47:04 +09:00
test(system): anchor index-addressed negative asserts to what they name (#3608)
## What this PR does
Some negative assertions in these suites can't fail for the reason their
test names give. `contains` and `notContains` compare list elements for
equality, so `--pinned-tenants=` never equals a rendered
`--pinned-tenants=tenant-a=shard0`, and `{name:
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET}` never matches an env entry
carrying a `valueFrom` beside the name. Others forbid one rendered value
under a name that claims the flag itself, so `notContains
--compatibility=cilium` leaves the kilo default render free to carry
`--compatibility=flannel` off the same values key.
Flag guards become `notMatchRegex` on `args[*]`, which matches per
element, so any value fails and so does the bare form. Mapping guards
get `any: true`. flux-shard-operator gets an `equal` on the whole
default arg list instead, and `--shard-cpu-limit=` is dropped because
that list covers it. The vendored ouroboros templates keep per-flag
guards: a whole-list pin there would go red on any upstream flag change,
under a test name about one flag.
Several of these address `containers[0]` with nothing pinning that
index, so a sidecar rendered ahead of the workload turns them green
while the flag is live on the real container. Those get an `equal` on
the container name first. A Cilium deny rule has no name, so that one
pins the selector plus the rule and `toPorts` counts. Where a positive
`contains` already sits on the same path it holds the index by itself
and gets no extra anchor.
Assertions of the same shape remain in files this PR doesn't touch,
including one in a package it does.
## Tests
Every dead guard was confirmed dead first: make the forbidden content
render, watch the old form stay green. `compatibility: flannel` in
kilo's values, `--gateway-api=true` in place of the bare flag,
`--proxy-fqdn` baked beside the composition flags, the OIDC client
secret in the `mode=None` grafana render. Each one turns the new
assertion red. Anchors checked the same way, with a sidecar rendered
ahead of the workload.
`hack/helm-unit-tests.sh` is green.
### Screenshots
None. This changes test files.
### Downstream repositories
Every changed file is under a `tests/` directory. No templates, no
values, no rendered output.
- [x] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
### Release note
```release-note
NONE
```
This commit is contained in:
7 files changed
+132
-59
No files matched your search
@@ -81,7 +81,35 @@ tests:
|
||||
# bound by anything cozystack ships, so listing it in the deny rule is
|
||||
# misleading.
|
||||
asserts:
|
||||
# Anchor the rule before asserting about it. notContains passes whenever
|
||||
# its path resolves to something that lacks the content, and a different
|
||||
# deny rule at [0] qualifies, so reordering spec.ingressDeny would leave
|
||||
# this green while 7473 came back on the rule it names. A deny rule has no
|
||||
# name, so the anchor is its selector, which is what identifies it rather
|
||||
# than one of the ports it happens to list.
|
||||
#
|
||||
# The selector identifies it only while there is one rule to identify: a
|
||||
# second world-scoped deny inserted ahead of this one would satisfy the
|
||||
# selector and shift the real rule to [1], which is the reordering above.
|
||||
# lengthEqual is what makes the selector sufficient.
|
||||
# Both indexes in the path, not just the outer one. A second toPorts entry
|
||||
# on the same rule carries its own ports list, so 7473 could come back
|
||||
# there with the rule count and the selector both still satisfied.
|
||||
- lengthEqual:
|
||||
path: spec.ingressDeny
|
||||
count: 1
|
||||
- lengthEqual:
|
||||
path: spec.ingressDeny[0].toPorts
|
||||
count: 1
|
||||
- contains:
|
||||
path: spec.ingressDeny[0].fromEntities
|
||||
content: world
|
||||
# any: true matches on the port alone. Without it the comparison is a
|
||||
# deep-equal against the whole entry, so 7473 re-added with a protocol
|
||||
# beside it, which is how the neighbouring 7946 entry is written, would
|
||||
# slip past a guard that looks like it forbids the port outright.
|
||||
- notContains:
|
||||
path: spec.ingressDeny[0].toPorts[0].ports
|
||||
any: true
|
||||
content:
|
||||
port: "7473"
|
||||
@@ -17,48 +17,31 @@ tests:
|
||||
- equal:
|
||||
path: spec.template.spec.serviceAccountName
|
||||
value: flux-shard-operator
|
||||
- contains:
|
||||
# The whole list, so the pin fails on an argument added, removed or
|
||||
# swapped rather than only on the ones someone thought to enumerate.
|
||||
# This template is first-party, so a failure here is a deliberate change
|
||||
# asking to be read, not upstream churn arriving on its own schedule.
|
||||
#
|
||||
# --metrics-bind-address and --metrics-secure are load-bearing among
|
||||
# these: the README-advertised cozy_flux_shard_* gauges, autosizing
|
||||
# recommendation included, are the operator's observability surface.
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --leader-elect
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --flux-namespace=cozy-fluxcd
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --shard-count=auto
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --shard-concurrent=5
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --rebalance-threshold=0.25
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --shard-cpu-request=100m
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --shard-memory-request=64Mi
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --shard-memory-limit=1Gi
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --shard-cpu-limit=
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --zap-log-level=info
|
||||
value:
|
||||
- --leader-elect
|
||||
- --metrics-bind-address=:8080
|
||||
- --metrics-secure=false
|
||||
- --flux-namespace=cozy-fluxcd
|
||||
- --shard-count=auto
|
||||
- --shard-concurrent=5
|
||||
- --rebalance-threshold=0.25
|
||||
- --shard-cpu-request=100m
|
||||
- --shard-memory-request=64Mi
|
||||
- --shard-memory-limit=1Gi
|
||||
- --zap-log-level=info
|
||||
- equal:
|
||||
path: spec.template.spec.volumes[0].secret.secretName
|
||||
value: flux-shard-operator-cert
|
||||
# The metrics endpoint must stay reachable: the README-advertised
|
||||
# cozy_flux_shard_* gauges (incl. the autosizing recommendation) are the
|
||||
# operator's observability surface.
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --metrics-bind-address=:8080
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --metrics-secure=false
|
||||
- equal:
|
||||
path: spec.template.metadata.annotations["prometheus.io/scrape"]
|
||||
value: "true"
|
||||
@@ -72,9 +55,16 @@ tests:
|
||||
- it: does not render --pinned-tenants by default
|
||||
template: templates/workload.yaml
|
||||
asserts:
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --pinned-tenants=
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].name
|
||||
value: flux-shard-operator
|
||||
# Match the flag name per element, not one whole element against one
|
||||
# value: contains and notContains compare elements for equality, so
|
||||
# `--pinned-tenants=` never equals a rendered
|
||||
# `--pinned-tenants=tenant-a=shard0` and the negative could not fail.
|
||||
- notMatchRegex:
|
||||
path: spec.template.spec.containers[0].args[*]
|
||||
pattern: "^--pinned-tenants"
|
||||
|
||||
- it: renders shardCount and pinned tenants from values
|
||||
template: templates/workload.yaml
|
||||
|
||||
@@ -445,6 +445,13 @@ tests:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
# Anchor the index before asserting on it. notContains passes whenever its
|
||||
# path resolves to something that lacks the content, and a different
|
||||
# container at [0] qualifies, so without this the guard goes green if a
|
||||
# sidecar is ever placed ahead of the proxy.
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].name
|
||||
value: proxy
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
any: true
|
||||
|
||||
@@ -61,6 +61,19 @@ tests:
|
||||
|
||||
- it: "no --compatibility arg in the default render"
|
||||
asserts:
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: "--compatibility=cilium"
|
||||
# Anchor the index before asserting on it. A negative assert passes
|
||||
# whenever its path resolves to something that does not match, and a
|
||||
# different container at [0] qualifies — as does an index resolving to
|
||||
# nothing at all — so without this the guard goes green if a sidecar is
|
||||
# ever placed ahead of kilo.
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].name
|
||||
value: kilo
|
||||
# Match the flag name per element, not one whole element against one
|
||||
# value: contains and notContains compare elements for equality, and the
|
||||
# chart renders --compatibility=<value> off a single values key, so an
|
||||
# equality check against the cilium value leaves every other value
|
||||
# unforbidden.
|
||||
- notMatchRegex:
|
||||
path: spec.template.spec.containers[0].args[*]
|
||||
pattern: "^--compatibility"
|
||||
@@ -79,12 +79,25 @@ tests:
|
||||
asserts:
|
||||
- notExists:
|
||||
path: spec.config["auth.generic_oauth"]
|
||||
# Anchor the index before asserting on it. notContains passes whenever its
|
||||
# path resolves to something that lacks the content, and a different
|
||||
# container at [0] qualifies, so without this both guards go green if a
|
||||
# sidecar is ever placed ahead of grafana in the CR's deployment spec.
|
||||
- equal:
|
||||
path: spec.deployment.spec.template.spec.containers[0].name
|
||||
value: grafana
|
||||
# any: true matches on the element name alone. Without it the comparison
|
||||
# is a deep-equal against the whole entry, and the real ones carry a
|
||||
# valueFrom or a value alongside the name, so {name: ...} matches nothing
|
||||
# and the guard passes whether or not the variable is rendered.
|
||||
- notContains:
|
||||
path: spec.deployment.spec.template.spec.containers[0].env
|
||||
any: true
|
||||
content:
|
||||
name: GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET
|
||||
- notContains:
|
||||
path: spec.deployment.spec.template.spec.containers[0].env
|
||||
any: true
|
||||
content:
|
||||
name: GF_PATHS_CUSTOM_INI
|
||||
|
||||
|
||||
@@ -22,16 +22,32 @@ tests:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --proxy-service-namespace=cozy-ouroboros
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --proxy-fqdn=ouroboros-proxy.cozy-ouroboros.svc.cluster.local.
|
||||
# Match the flag name per element, not one whole element against one
|
||||
# value: contains and notContains compare elements for equality, and the
|
||||
# baked FQDN carries whatever controller.clusterDomain is set to, so an
|
||||
# equality check against the form the default cluster-domain produces
|
||||
# leaves every other value unforbidden.
|
||||
- notMatchRegex:
|
||||
path: spec.template.spec.containers[0].args[*]
|
||||
pattern: "^--proxy-fqdn"
|
||||
|
||||
- it: leaves Gateway-API watching off at the parent default (consumer enables)
|
||||
template: charts/ouroboros/templates/controller-deployment.yaml
|
||||
asserts:
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --gateway-api
|
||||
# Anchor the index before asserting on it. A negative assert passes
|
||||
# whenever its path resolves to something that does not match, and a
|
||||
# different container at [0] qualifies — as does an index resolving to
|
||||
# nothing at all — so without this the guard goes green if a sidecar is
|
||||
# ever placed ahead of the controller.
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].name
|
||||
value: controller
|
||||
# Match the flag name per element. An equality check against the bare
|
||||
# form the chart renders today would go on passing if it ever rendered
|
||||
# --gateway-api=true, with watching on.
|
||||
- notMatchRegex:
|
||||
path: spec.template.spec.containers[0].args[*]
|
||||
pattern: "^--gateway-api"
|
||||
|
||||
- it: emits chart-default --resync=30s — host scenario inherits the upstream chart default (changed from 10m in upstream v0.7.x). The reduction is the controller's only recovery path when an Ingress watch silently dies, and 30s caps worst-case event-to-reconcile latency under broken-watch conditions. Pinning here catches a future upstream bump back to the longer value before it lands as a CI surprise.
|
||||
template: charts/ouroboros/templates/controller-deployment.yaml
|
||||
@@ -151,15 +167,15 @@ tests:
|
||||
# too — this is the mode tenants actually run, so a future refactor
|
||||
# in the upstream controller-deployment template that drops the
|
||||
# composition block from this branch only would break tenants
|
||||
# silently. The negative-assert pins that --proxy-fqdn does NOT
|
||||
# bake the cluster-domain at render time when no clusterDomain is
|
||||
# configured (the platform-agnostic default).
|
||||
# silently. The negative assert pins that no --proxy-fqdn is baked at
|
||||
# render time when no clusterDomain is configured (the
|
||||
# platform-agnostic default).
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --proxy-service-name=ouroboros-proxy
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --proxy-service-namespace=cozy-ouroboros
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --proxy-fqdn=ouroboros-proxy.cozy-ouroboros.svc.cluster.local.
|
||||
- notMatchRegex:
|
||||
path: spec.template.spec.containers[0].args[*]
|
||||
pattern: "^--proxy-fqdn"
|
||||
@@ -27,9 +27,15 @@ tests:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --target-service-namespace=cozy-ingress-nginx
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: --target-host=
|
||||
# Match the flag name per element, not one whole element against one
|
||||
# value: contains and notContains compare elements for equality, so
|
||||
# `--target-host=` never equals a rendered `--target-host=<value>` and
|
||||
# that negative could not fail. A length assertion would not do either,
|
||||
# since an upstream bump that adds the flag while consolidating another
|
||||
# argument keeps the count.
|
||||
- notMatchRegex:
|
||||
path: spec.template.spec.containers[0].args[*]
|
||||
pattern: "^--target-host"
|
||||
|
||||
- it: controller image is pinned to the digest the values.yaml ships
|
||||
template: charts/ouroboros/templates/controller-deployment.yaml
|
||||
|
||||
Reference in new issue
Block a user