1
0
mirror of synced 2026-06-26 21:50:48 +00:00
Files
flux2/cmd/flux/get_test.go
T
3uzbcqje 5afd1d8728 cmd: support type!=status in get --status-selector
`flux get --status-selector` only supported equality (`type=status`),
so finding objects that are not in a given state required multiple
invocations, e.g. listing everything that is not ready needed both
`Ready=False` and `Ready=Unknown`.

Add support for a negated selector `type!=status`. Since all resource
adapters delegate matching to the shared `statusMatches` helper and
filtering is centralised in `getRowsToPrint`, negation is implemented
purely in the parse/filter layer by inverting the match result. This
covers every resource type and the `--watch` path without touching the
per-resource adapters.

A missing condition is treated as not-matching by `statusMatches` (Flux
considers it "waiting to be reconciled"), so `Ready!=True` also surfaces
objects that have no Ready condition yet, i.e. the complete not-ready set:

    flux get all -A --status-selector Ready!=True

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: 3uzbcqje <3uzbcqje@addy.to>
2026-06-24 10:53:37 -07:00

183 lines
4.4 KiB
Go

//go:build unit
// +build unit
/*
Copyright 2023 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"testing"
)
func Test_GetCmd(t *testing.T) {
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
testEnv.CreateObjectFile("./testdata/get/objects.yaml", tmpl, t)
tests := []struct {
name string
args string
expected string
}{
{
name: "no label selector",
expected: "testdata/get/get.golden",
},
{
name: "equal label selector",
args: "-l sharding.fluxcd.io/key=shard1",
expected: "testdata/get/get_label_one.golden",
},
{
name: "notin label selector",
args: `-l "sharding.fluxcd.io/key notin (shard1, shard2)"`,
expected: "testdata/get/get_label_two.golden",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: "get sources git " + tt.args + " -n " + tmpl["fluxns"],
assert: assertGoldenTemplateFile(tt.expected, nil),
}
cmd.runTestCmd(t)
})
}
}
func Test_GetCmdStatusSelector(t *testing.T) {
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
testEnv.CreateObjectFile("./testdata/get/status_objects.yaml", tmpl, t)
tests := []struct {
name string
args string
expected string
}{
{
name: "equal status selector matches one",
args: "--status-selector Ready=True",
expected: "testdata/get/get_status_ready_true.golden",
},
{
name: "equal status selector matches false",
args: "--status-selector Ready=False",
expected: "testdata/get/get_status_ready_false.golden",
},
{
name: "not-equal status selector matches all not-true",
args: "--status-selector Ready!=True",
expected: "testdata/get/get_status_ready_not_true.golden",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: "get sources git " + tt.args + " -n " + tmpl["fluxns"],
assert: assertGoldenTemplateFile(tt.expected, nil),
}
cmd.runTestCmd(t)
})
}
}
func Test_GetCmdErrors(t *testing.T) {
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
testEnv.CreateObjectFile("./testdata/get/objects.yaml", tmpl, t)
tests := []struct {
name string
args string
assert assertFunc
}{
{
name: "specific object not found",
args: "get kustomization non-existent-resource -n " + tmpl["fluxns"],
assert: assertError(fmt.Sprintf("Kustomization object 'non-existent-resource' not found in \"%s\" namespace", tmpl["fluxns"])),
},
{
name: "no objects found in namespace",
args: "get helmrelease -n " + tmpl["fluxns"],
assert: assertError(fmt.Sprintf("no HelmRelease objects found in \"%s\" namespace", tmpl["fluxns"])),
},
{
name: "malformed status selector",
args: "get sources git --status-selector Ready -n " + tmpl["fluxns"],
assert: assertError("expected status selector in type=status or type!=status format, but found: Ready"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: tt.args,
assert: tt.assert,
}
cmd.runTestCmd(t)
})
}
}
func Test_GetCmdSuccess(t *testing.T) {
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
testEnv.CreateObjectFile("./testdata/get/objects.yaml", tmpl, t)
tests := []struct {
name string
args string
assert assertFunc
}{
{
name: "list sources git",
args: "get sources git -n " + tmpl["fluxns"],
assert: assertSuccess(),
},
{
name: "get help",
args: "get --help",
assert: assertSuccess(),
},
{
name: "get with all namespaces flag",
args: "get sources git -A",
assert: assertSuccess(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: tt.args,
assert: tt.assert,
}
cmd.runTestCmd(t)
})
}
}