Skip to content

Commit

Permalink
fix: order values in MultiResolutionResponse
Browse files Browse the repository at this point in the history
Signed-off-by: Guilhem Lettron <[email protected]>
  • Loading branch information
guilhem committed Jan 15, 2025
1 parent 0eae57e commit 7611fb7
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 9 deletions.
35 changes: 26 additions & 9 deletions pkg/reference/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package reference

import (
"context"
"slices"

kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -238,20 +239,23 @@ func (r *APIResolver) ResolveMultiple(ctx context.Context, req MultiResolutionRe
return MultiResolutionResponse{ResolvedValues: req.CurrentValues, ResolvedReferences: req.References}, nil
}

valueMap := make(map[string]xpv1.Reference)

// The references are already set - resolve them.
if len(req.References) > 0 {
vals := make([]string, len(req.References))
for i := range req.References {
if err := r.client.Get(ctx, types.NamespacedName{Name: req.References[i].Name}, req.To.Managed); err != nil {
if kerrors.IsNotFound(err) {
return MultiResolutionResponse{}, getResolutionError(req.References[i].Policy, errors.Wrap(err, errGetManaged))
}
return MultiResolutionResponse{}, errors.Wrap(err, errGetManaged)
}
vals[i] = req.Extract(req.To.Managed)
valueMap[req.Extract(req.To.Managed)] = req.References[i]
}

rsp := MultiResolutionResponse{ResolvedValues: vals, ResolvedReferences: req.References}
sortedKeys, sortedRefs := sortMapByKeys(valueMap)

rsp := MultiResolutionResponse{ResolvedValues: sortedKeys, ResolvedReferences: sortedRefs}
return rsp, rsp.Validate()
}

Expand All @@ -260,19 +264,17 @@ func (r *APIResolver) ResolveMultiple(ctx context.Context, req MultiResolutionRe
return MultiResolutionResponse{}, errors.Wrap(err, errListManaged)
}

items := req.To.List.GetItems()
refs := make([]xpv1.Reference, 0, len(items))
vals := make([]string, 0, len(items))
for _, to := range req.To.List.GetItems() {
if ControllersMustMatch(req.Selector) && !meta.HaveSameController(r.from, to) {
continue
}

vals = append(vals, req.Extract(to))
refs = append(refs, xpv1.Reference{Name: to.GetName()})
valueMap[req.Extract(to)] = xpv1.Reference{Name: to.GetName()}
}

rsp := MultiResolutionResponse{ResolvedValues: vals, ResolvedReferences: refs}
sortedKeys, sortedRefs := sortMapByKeys(valueMap)

rsp := MultiResolutionResponse{ResolvedValues: sortedKeys, ResolvedReferences: sortedRefs}
return rsp, getResolutionError(req.Selector.Policy, rsp.Validate())
}

Expand All @@ -283,6 +285,21 @@ func getResolutionError(p *xpv1.Policy, err error) error {
return nil
}

func sortMapByKeys(m map[string]xpv1.Reference) ([]string, []xpv1.Reference) {
// TODO: use go 1.23 maps.Keys when available
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
slices.Sort(keys)

values := make([]xpv1.Reference, 0, len(m))
for _, k := range keys {
values = append(values, m[k])
}
return keys, values
}

// ControllersMustMatch returns true if the supplied Selector requires that a
// reference be to a managed resource whose controller reference matches the
// referencing resource.
Expand Down
36 changes: 36 additions & 0 deletions pkg/reference/reference_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ func TestResolveMultiple(t *testing.T) {
errBoom := errors.New("boom")
now := metav1.Now()
value := "coolv"
value2 := "cooler"
ref := xpv1.Reference{Name: "cool"}
optionalPolicy := xpv1.ResolutionPolicyOptional
alwaysPolicy := xpv1.ResolvePolicyAlways
Expand All @@ -378,6 +379,11 @@ func TestResolveMultiple(t *testing.T) {
meta.SetExternalName(controlled, value)
meta.AddControllerReference(controlled, meta.AsController(&xpv1.TypedReference{UID: types.UID("very-unique")}))

controlled2 := &fake.Managed{}
controlled2.SetName(value2)
meta.SetExternalName(controlled2, value2)
meta.AddControllerReference(controlled2, meta.AsController(&xpv1.TypedReference{UID: types.UID("very-unique")}))

type args struct {
ctx context.Context
req MultiResolutionRequest
Expand Down Expand Up @@ -666,6 +672,36 @@ func TestResolveMultiple(t *testing.T) {
},
},
},
"OrderOutput": {
reason: "Output values should ordered",
c: &test.MockClient{
MockList: test.NewMockListFn(nil),
},
from: controlled,
args: args{
req: MultiResolutionRequest{
Selector: &xpv1.Selector{
MatchControllerRef: func() *bool { t := true; return &t }(),
},
To: To{List: &FakeManagedList{
Items: []resource.Managed{
&fake.Managed{}, // A resource that does not match.
controlled, // A resource with a matching controller reference.
&fake.Managed{}, // A resource that does not match.
controlled2, // A resource with a matching controller reference.
},
}},
Extract: ExternalName(),
},
},
want: want{
rsp: MultiResolutionResponse{
ResolvedValues: []string{value2, value},
ResolvedReferences: []xpv1.Reference{{Name: value2}, {Name: value}},
},
err: nil,
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
Expand Down

0 comments on commit 7611fb7

Please sign in to comment.