Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
23 changes: 23 additions & 0 deletions cmd/crossplane/composition/integration_main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//go:build integration

package composition_test

import (
"fmt"
"os"
"testing"

"github.com/crossplane/cli/v2/internal/testutils/integration"
)

// TestMain runs before all tests.
func TestMain(m *testing.M) {
// Kill envtest servers that an earlier run left behind when it died abnormally.
integration.ReapOrphanedEnvtest(func(format string, args ...any) { fmt.Fprintf(os.Stderr, format+"\n", args...) })

// Run all tests
exitCode := m.Run()

// Exit with the test suite's exit code
os.Exit(exitCode)
}
2,521 changes: 2,521 additions & 0 deletions cmd/crossplane/composition/integration_test.go

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions cmd/crossplane/composition/testdata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# composition simulate integration tests

`integration_test.go` runs `TestCompDiffIntegration`: crossplane-diff's composition cases, run as
`crossplane composition simulate -f <Composition files>` against an envtest cluster. A case keeps its
crossplane-diff args; `simharness`'s `RunIntegrationTest` translates them
into the command's flags and runs it. Fixtures only this suite uses are in
`testdata/comp`; those shared with another suite are in
`internal/testutils/integration/testdata/comp` (and `crds`).

The skips, how to run the suite and its coverage are in
`cmd/crossplane/project/testdata/README.md`. Run only this suite with
`go test -tags integration -run TestCompDiffIntegration ./cmd/crossplane/composition/`.
2 changes: 1 addition & 1 deletion cmd/crossplane/project/integration_main_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build integration

package project
package project_test

import (
"fmt"
Expand Down
95 changes: 48 additions & 47 deletions cmd/crossplane/project/integration_plan_output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package project
package project_test

import (
"bytes"
Expand All @@ -34,36 +34,37 @@ import (
"github.com/crossplane/cli/v2/internal/plan"
"github.com/crossplane/cli/v2/internal/simulate"
"github.com/crossplane/cli/v2/internal/testutils/integration"
"github.com/crossplane/cli/v2/internal/testutils/integration/simharness"
)

// TestSimulatePlanOutput runs simulate's own output formats, -o plan and
// -o json's simulate.ProjectResult, for xr, composition and the plain project
// -o json's simulate.Result, for xr, composition and the plain project
// fixture, which crossplane-diff's cases cannot express. Each case passes
// simulate args directly rather than crossplane-diff's.
func TestSimulatePlanOutput(t *testing.T) {
t.Parallel()

xrCase := integration.Setup{
CRDDirs: []string{"testdata/diff/crds"},
CRDDirs: []string{"../../../internal/testutils/integration/testdata/diff/crds"},
SetupFiles: []string{
"testdata/diff/resources/xrd.yaml",
"testdata/diff/resources/composition.yaml",
"testdata/diff/resources/functions.yaml",
"../../../internal/testutils/integration/testdata/diff/resources/xrd.yaml",
"../../../internal/testutils/integration/testdata/diff/resources/composition.yaml",
"../../../internal/testutils/integration/testdata/diff/resources/functions.yaml",
},
CrossplaneManagedResources: []integration.HierarchicalOwnershipRelation{
integration.Composes("testdata/diff/resources/existing-xr.yaml", "testdata/diff/resources/existing-downstream-resource.yaml"),
integration.Composes("../../../internal/testutils/integration/testdata/diff/resources/existing-xr.yaml", "../../../internal/testutils/integration/testdata/diff/resources/existing-downstream-resource.yaml"),
},
}
compCase := integration.Setup{
CRDDirs: []string{"testdata/comp/crds"},
CRDDirs: []string{"../../../internal/testutils/integration/testdata/comp/crds"},
SetupFiles: []string{
"testdata/comp/resources/xrd.yaml",
"testdata/comp/resources/original-composition.yaml",
"testdata/comp/resources/functions.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/xrd.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/original-composition.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/functions.yaml",
},
CrossplaneManagedResources: []integration.HierarchicalOwnershipRelation{
integration.Composes("testdata/comp/resources/existing-xr-1.yaml", "testdata/comp/resources/existing-downstream-1.yaml"),
integration.Composes("testdata/comp/resources/existing-xr-2.yaml", "testdata/comp/resources/existing-downstream-2.yaml"),
integration.Composes("../../../internal/testutils/integration/testdata/comp/resources/existing-xr-1.yaml", "../../../internal/testutils/integration/testdata/comp/resources/existing-downstream-1.yaml"),
integration.Composes("../../../internal/testutils/integration/testdata/comp/resources/existing-xr-2.yaml", "../../../internal/testutils/integration/testdata/comp/resources/existing-downstream-2.yaml"),
},
}

Expand All @@ -72,8 +73,8 @@ func TestSimulatePlanOutput(t *testing.T) {
another.Name = "another-resource"
comp := plan.ResourceRef{APIVersion: "apiextensions.crossplane.io/v1", Kind: "Composition", Name: "xnopresources.diff.example.org"}

xrArgs := []string{"-f", "testdata/diff/modified-xr.yaml"}
compArgs := []string{"-f", "testdata/comp/updated-composition.yaml", "--namespace=default"}
xrArgs := []string{"-f", "../../../internal/testutils/integration/testdata/diff/modified-xr.yaml"}
compArgs := []string{"-f", "../../../internal/testutils/integration/testdata/comp/updated-composition.yaml", "--namespace=default"}

cases := map[string]struct {
reason string
Expand Down Expand Up @@ -111,7 +112,7 @@ Note: Provider plan not run: no provider diff server planned these resources.
"XRCreatePlanText": {
reason: "-o plan prints a dotted annotation or label key, such as crossplane.io/composite, whole as one level.",
tt: &integration.Setup{CRDDirs: xrCase.CRDDirs, SetupFiles: xrCase.SetupFiles},
args: []string{"-f", "testdata/diff/new-xr.yaml"},
args: []string{"-f", "../../../internal/testutils/integration/testdata/diff/new-xr.yaml"},
wantText: `XR: XNopResource.ns.diff.example.org default/test-resource
[+] XDownstreamResource.ns.nop.example.org default/test-resource (create)
metadata:
Expand All @@ -133,7 +134,7 @@ Note: Provider plan not run: no provider diff server planned these resources.
`,
},
"XRPlanJSON": {
reason: "-o json emits simulate.ProjectResult: the XR as a changed composite, with both its plans grouped under it.",
reason: "-o json emits simulate.Result: the XR as a changed composite, with both its plans grouped under it.",
tt: &xrCase,
args: append([]string{"-o", "json"}, xrArgs...),
wantResult: &planShape{
Expand Down Expand Up @@ -177,7 +178,7 @@ Note: Provider plan not run: no provider diff server planned these resources.
`,
},
"CompPlanJSON": {
reason: "-o json emits simulate.ProjectResult: the Composition's revision impact, both affected XRs as changed composites, and their plans.",
reason: "-o json emits simulate.Result: the Composition's revision impact, both affected XRs as changed composites, and their plans.",
compArgv: true,
args: append([]string{"-o", "json"}, compArgs...),
wantResult: &planShape{
Expand Down Expand Up @@ -252,11 +253,11 @@ Note: Provider plan not run: no provider diff server planned these resources.
argv := append(plainProjectArgv(t), tc.args...)
switch {
case tc.compArgv:
argv = append([]string{"composition", "simulate", "--timeout=" + defaultTimeout.String()}, tc.args...)
argv = append([]string{"composition", "simulate", "--timeout=" + simharness.DefaultTimeout.String()}, tc.args...)
case tc.tt != nil:
argv = append([]string{"xr", "simulate", "--timeout=" + defaultTimeout.String()}, tc.args...)
argv = append([]string{"xr", "simulate", "--timeout=" + simharness.DefaultTimeout.String()}, tc.args...)
}
code, err := runSimulateArgv(t, cfg, argv, localCrossplaneBinary(t), nil, &stdout, &stderr)
code, err := simharness.RunSimulateArgv(t, cfg, argv, simharness.LocalCrossplaneBinary(t), nil, &stdout, &stderr)
if err != nil {
t.Fatalf("\n%s\nsimulate: unexpected error: %v\nstderr:\n%s", tc.reason, err, stderr.String())
}
Expand All @@ -271,9 +272,9 @@ Note: Provider plan not run: no provider diff server planned these resources.
return
}

var res simulate.ProjectResult
var res simulate.Result
if err := json.Unmarshal(stdout.Bytes(), &res); err != nil {
t.Fatalf("\n%s\nsimulate -o json: output is not a simulate.ProjectResult: %v\n%s", tc.reason, err, stdout.String())
t.Fatalf("\n%s\nsimulate -o json: output is not a simulate.Result: %v\n%s", tc.reason, err, stdout.String())
}
if res.FormatVersion != plan.ResultFormatVersion || res.Errored {
t.Errorf("\n%s\nsimulate -o json: want formatVersion %q and not errored, got %q, errored %t", tc.reason, plan.ResultFormatVersion, res.FormatVersion, res.Errored)
Expand All @@ -285,7 +286,7 @@ Note: Provider plan not run: no provider diff server planned these resources.
}
}

// planShape is the part of a simulate.ProjectResult these cases pin: everything but
// planShape is the part of a simulate.Result these cases pin: everything but
// the field changes, dry-run details and notes, which the plan text cases and
// the mapper's unit tests cover.
type planShape struct {
Expand All @@ -302,7 +303,7 @@ type planEntry struct {
Composite string
}

func summarize(r simulate.ProjectResult) planShape {
func summarize(r simulate.Result) planShape {
s := planShape{Summary: r.Summary, Composites: r.Composites, Compositions: r.Compositions}
for _, p := range r.Plans {
e := planEntry{Kind: p.Kind, Name: p.Name, Action: p.Action}
Expand All @@ -327,7 +328,7 @@ func summarize(r simulate.ProjectResult) planShape {
func integrationEnvGap() string {
// integration.Start fails, rather than skips, a run without envtest's
// binaries or Crossplane's CRDs.
if !dockerAvailable() {
if !simharness.DockerAvailable() {
return "env: no Docker daemon for the function render engine"
}
return ""
Expand Down Expand Up @@ -356,7 +357,7 @@ func TestSimulatePinnedChangedFunction(t *testing.T) {
},
"PinnedXRWithUnchangedFunctionDeferred": {
reason: "A Manual XR whose pinned revision calls no changed function stays deferred.",
composition: "testdata/comp/resources/original-composition.yaml",
composition: "../../../internal/testutils/integration/testdata/comp/resources/original-composition.yaml",
wantDeferred: true,
},
}
Expand All @@ -370,17 +371,17 @@ func TestSimulatePinnedChangedFunction(t *testing.T) {
}

cluster := integration.Start(t, integration.Setup{
CRDDirs: []string{"testdata/comp/crds"},
CRDDirs: []string{"../../../internal/testutils/integration/testdata/comp/crds"},
SetupFiles: []string{
"testdata/comp/resources/xrd.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/xrd.yaml",
tc.composition,
"testdata/comp/resources/functions.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/functions.yaml",
"testdata/project/embedded/cluster-function.yaml",
},
CrossplaneManagedResources: []integration.HierarchicalOwnershipRelation{
integration.Composes(
"testdata/comp/resources/existing-xr-manual.yaml",
"testdata/comp/resources/existing-downstream-manual.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/existing-xr-manual.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/existing-downstream-manual.yaml",
),
},
})
Expand All @@ -395,20 +396,20 @@ func TestSimulatePinnedChangedFunction(t *testing.T) {
}
rev, _, _ := un.NestedString(xr.Object, "spec", "crossplane", "compositionRevisionRef", "name")

base := withRenderBinary([]string{
"project", "simulate", "--timeout=" + defaultTimeout.String(),
base := simharness.WithRenderBinary([]string{
"project", "simulate", "--timeout=" + simharness.DefaultTimeout.String(),
"-f", copyProjectFixture(t, "embedded"),
"--cache-dir=" + t.TempDir(), "--skip-plan", "-n", "default",
}, localCrossplaneBinary(t))
}, simharness.LocalCrossplaneBinary(t))

var stdout, stderr bytes.Buffer
code, err := runSimulateArgvWith(t, cfg, append(slices.Clip(base), "-o", "json"), &simulate.Hooks{}, &stdout, &stderr)
code, err := simharness.RunSimulateArgvWith(t, cfg, append(slices.Clip(base), "-o", "json"), &simulate.Hooks{}, &stdout, &stderr)
if err != nil {
t.Fatalf("\n%s\nsimulate: unexpected error: %v\nstderr:\n%s", tc.reason, err, stderr.String())
}
var res simulate.ProjectResult
var res simulate.Result
if err := json.Unmarshal(stdout.Bytes(), &res); err != nil {
t.Fatalf("\n%s\nsimulate -o json: output is not a simulate.ProjectResult: %v\n%s", tc.reason, err, stdout.String())
t.Fatalf("\n%s\nsimulate -o json: output is not a simulate.Result: %v\n%s", tc.reason, err, stdout.String())
}
if len(res.Composites) != 1 {
t.Fatalf("\n%s\nsimulate -o json: want 1 composite, got %+v", tc.reason, res.Composites)
Expand Down Expand Up @@ -443,7 +444,7 @@ func TestSimulatePinnedChangedFunction(t *testing.T) {
}

var text bytes.Buffer
if _, err := runSimulateArgvWith(t, cfg, base, &simulate.Hooks{}, &text, &stderr); err != nil {
if _, err := simharness.RunSimulateArgvWith(t, cfg, base, &simulate.Hooks{}, &text, &stderr); err != nil {
t.Fatalf("simulate -o plan: unexpected error: %v", err)
}
if os.Getenv("SIMULATE_DEMO") != "" {
Expand All @@ -464,15 +465,15 @@ func TestSimulateNameRejected(t *testing.T) {
t.Parallel()

compCase := integration.Setup{
CRDDirs: []string{"testdata/comp/crds"},
CRDDirs: []string{"../../../internal/testutils/integration/testdata/comp/crds"},
SetupFiles: []string{
"testdata/comp/resources/xrd.yaml",
"testdata/comp/resources/original-composition.yaml",
"testdata/comp/resources/functions.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/xrd.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/original-composition.yaml",
"../../../internal/testutils/integration/testdata/comp/resources/functions.yaml",
},
CrossplaneManagedResources: []integration.HierarchicalOwnershipRelation{
integration.Composes("testdata/comp/resources/existing-xr-1.yaml", "testdata/comp/resources/existing-downstream-1.yaml"),
integration.Composes("testdata/comp/resources/existing-xr-2.yaml", "testdata/comp/resources/existing-downstream-2.yaml"),
integration.Composes("../../../internal/testutils/integration/testdata/comp/resources/existing-xr-1.yaml", "../../../internal/testutils/integration/testdata/comp/resources/existing-downstream-1.yaml"),
integration.Composes("../../../internal/testutils/integration/testdata/comp/resources/existing-xr-2.yaml", "../../../internal/testutils/integration/testdata/comp/resources/existing-downstream-2.yaml"),
},
}
cases := map[string]struct {
Expand Down Expand Up @@ -507,7 +508,7 @@ func TestSimulateNameRejected(t *testing.T) {

var stdout, stderr bytes.Buffer
argv := append(plainProjectArgv(t), tc.args...)
code, err := runSimulateArgv(t, cfg, argv, localCrossplaneBinary(t), nil, &stdout, &stderr)
code, err := simharness.RunSimulateArgv(t, cfg, argv, simharness.LocalCrossplaneBinary(t), nil, &stdout, &stderr)
if err == nil || !strings.Contains(err.Error(), tc.wantErr) {
t.Fatalf("\n%s\nsimulate: want error containing %q, got %v (exit %d)", tc.reason, tc.wantErr, err, code)
}
Expand All @@ -527,7 +528,7 @@ func plainProjectArgv(t *testing.T) []string {
t.Helper()

return []string{
"project", "simulate", "--timeout=" + defaultTimeout.String(),
"project", "simulate", "--timeout=" + simharness.DefaultTimeout.String(),
"-f", copyProjectFixture(t, "plain"),
"--cache-dir=" + t.TempDir(),
}
Expand Down
Loading
Loading