105 lines
5.3 KiB
Go
105 lines
5.3 KiB
Go
package ckconfig
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
commandkit "go.maximumdirect.net/commandkit"
|
|
configkit "go.maximumdirect.net/configkit"
|
|
)
|
|
|
|
func TestDetailedDiffPreservesNativeEvidenceAndAssertions(t *testing.T) {
|
|
values := []configkit.Difference{
|
|
{Path: configkit.Keys("added"), Right: configkit.ValueSnapshot{Present: true, YAML: "null\n"}},
|
|
{Path: configkit.Keys("removed"), Left: configkit.ValueSnapshot{Present: true, YAML: "false\n"}},
|
|
{Path: configkit.Keys("secret"), Left: configkit.ValueSnapshot{Present: true, Redacted: true, YAML: "'***'\n"}, Right: configkit.ValueSnapshot{Present: true, Redacted: true, YAML: "'***'\n"}, HiddenChanged: true},
|
|
{Path: configkit.Keys("list"), Left: configkit.ValueSnapshot{Present: true, YAML: "[one, two]\n"}, Right: configkit.ValueSnapshot{Present: true, YAML: "[three]\n"}},
|
|
{Path: configkit.Keys("marker"), Left: configkit.ValueSnapshot{Present: true, YAML: "'redacted'\n"}, Right: configkit.ValueSnapshot{Present: true, YAML: "'***'\n"}},
|
|
}
|
|
calls := 0
|
|
scope := Scope[struct{}, struct{}]{Name: "app", Operations: []Operation{Diff}, Compare: func(context.Context, ComparisonRequest[struct{}], struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
|
|
calls++
|
|
return commandkit.Acquired[[]configkit.Difference]{Value: values}, nil
|
|
}}
|
|
app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{scope}}))
|
|
for _, format := range []string{"json", "yaml", "text"} {
|
|
var out bytes.Buffer
|
|
result := app.Execute(context.Background(), []string{"config", "diff", "--details", "--check", "--format=" + format}, commandkit.Streams{Out: &out, Err: io.Discard})
|
|
var logical any
|
|
var err error
|
|
if format == "json" {
|
|
err = json.Unmarshal(out.Bytes(), &logical)
|
|
} else {
|
|
logical, err = commandkit.DecodeYAMLReport(&out)
|
|
}
|
|
if result.Kind != commandkit.OutcomeDomain || result.Status != 3 || err != nil {
|
|
t.Fatalf("format %s = %#v %v %q", format, result, err, out.String())
|
|
}
|
|
report := logical.(map[string]any)
|
|
entries := report["differences"].([]any)
|
|
if report["scope"] != "app" || len(entries) != len(values) {
|
|
t.Fatalf("format %s report %#v", format, report)
|
|
}
|
|
added := entries[0].(map[string]any)
|
|
before, after := added["before"].(map[string]any), added["after"].(map[string]any)
|
|
if before["present"] != false || before["value"] != nil || after["present"] != true || after["value"] != nil {
|
|
t.Fatalf("null/absence: %#v", added)
|
|
}
|
|
secret := entries[2].(map[string]any)
|
|
if secret["hidden_changed"] != true || !reflect.DeepEqual(secret["before"].(map[string]any)["value"], secret["after"].(map[string]any)["value"]) {
|
|
t.Fatalf("hidden change: %#v", secret)
|
|
}
|
|
list := entries[3].(map[string]any)["after"].(map[string]any)["value"]
|
|
if !reflect.DeepEqual(list, []any{"three"}) {
|
|
t.Fatalf("atomic sequence: %#v", list)
|
|
}
|
|
marker := entries[4].(map[string]any)["after"].(map[string]any)
|
|
if marker["value"] != "***" || marker["redacted"] != false {
|
|
t.Fatalf("marker string: %#v", marker)
|
|
}
|
|
}
|
|
if calls != 3 {
|
|
t.Fatalf("provider calls=%d", calls)
|
|
}
|
|
result := app.Execute(context.Background(), []string{"config", "diff"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
|
if result.Kind != commandkit.OutcomeSuccess || calls != 4 {
|
|
t.Fatalf("ordinary diff: %#v calls=%d", result, calls)
|
|
}
|
|
values = nil
|
|
var out bytes.Buffer
|
|
result = app.Execute(context.Background(), []string{"config", "diff", "--check", "--details", "--format=json"}, commandkit.Streams{Out: &out, Err: io.Discard})
|
|
if result.Kind != commandkit.OutcomeSuccess || !strings.Contains(out.String(), `"differences": []`) {
|
|
t.Fatalf("equality: %#v %q", result, out.String())
|
|
}
|
|
}
|
|
|
|
func TestDiffAssertionRetainsDomainOutcomeOnDeliveryFailures(t *testing.T) {
|
|
values := []configkit.Difference{{Path: configkit.Keys("x"), Right: configkit.ValueSnapshot{Present: true, YAML: "true\n"}}}
|
|
cause := errors.New("provider failed")
|
|
var providerErr error
|
|
scope := Scope[struct{}, struct{}]{Name: "app", Operations: []Operation{Diff}, Compare: func(context.Context, ComparisonRequest[struct{}], struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
|
|
return commandkit.Acquired[[]configkit.Difference]{Value: values}, providerErr
|
|
}}
|
|
app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{scope}}))
|
|
result := app.Execute(context.Background(), []string{"config", "diff", "--check", "--details"}, commandkit.Streams{Out: shortWriter{}, Err: io.Discard})
|
|
if result.Kind != commandkit.OutcomeDomain || result.Status != 3 || result.Presentation.Output.State != commandkit.DeliveryIncomplete {
|
|
t.Fatalf("writer failure: %#v", result)
|
|
}
|
|
values[0].Right.YAML = "[invalid"
|
|
result = app.Execute(context.Background(), []string{"config", "diff", "--check", "--details"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
|
if result.Kind != commandkit.OutcomeDomain || result.Status != 3 || result.Presentation.Output.RenderError == nil {
|
|
t.Fatalf("render failure: %#v", result)
|
|
}
|
|
providerErr = cause
|
|
result = app.Execute(context.Background(), []string{"config", "diff", "--check"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
|
if result.Kind != commandkit.OutcomeOperational || !errors.Is(result.Cause, cause) {
|
|
t.Fatalf("provider failure: %#v", result)
|
|
}
|
|
}
|