Skip to content

Commit

Permalink
Refactor slice utils package structure
Browse files Browse the repository at this point in the history
Signed-off-by: Per Goncalves da Silva <[email protected]>
  • Loading branch information
Per Goncalves da Silva committed Feb 10, 2025
1 parent 29547aa commit c7964fe
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 271 deletions.
6 changes: 3 additions & 3 deletions internal/catalogmetadata/filter/bundle_predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package filter

import (
mmsemver "github.com/Masterminds/semver/v3"
filterutils "github.com/operator-framework/operator-controller/internal/util/filter"

Check failure on line 5 in internal/catalogmetadata/filter/bundle_predicates.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gci)

"github.com/operator-framework/operator-registry/alpha/declcfg"

"github.com/operator-framework/operator-controller/internal/bundleutil"
slicesutil "github.com/operator-framework/operator-controller/internal/util/slices"
)

func InMastermindsSemverRange(semverRange *mmsemver.Constraints) slicesutil.Predicate[declcfg.Bundle] {
func InMastermindsSemverRange(semverRange *mmsemver.Constraints) filterutils.Predicate[declcfg.Bundle] {
return func(b declcfg.Bundle) bool {
bVersion, err := bundleutil.GetVersion(b)
if err != nil {
Expand All @@ -27,7 +27,7 @@ func InMastermindsSemverRange(semverRange *mmsemver.Constraints) slicesutil.Pred
}
}

func InAnyChannel(channels ...declcfg.Channel) slicesutil.Predicate[declcfg.Bundle] {
func InAnyChannel(channels ...declcfg.Channel) filterutils.Predicate[declcfg.Bundle] {
return func(bundle declcfg.Bundle) bool {
for _, ch := range channels {
for _, entry := range ch.Entries {
Expand Down
8 changes: 4 additions & 4 deletions internal/catalogmetadata/filter/successors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ package filter

import (
"fmt"
filterutils "github.com/operator-framework/operator-controller/internal/util/filter"

mmsemver "github.com/Masterminds/semver/v3"
bsemver "github.com/blang/semver/v4"

"github.com/operator-framework/operator-registry/alpha/declcfg"

ocv1 "github.com/operator-framework/operator-controller/api/v1"
slicesutil "github.com/operator-framework/operator-controller/internal/util/slices"
)

func SuccessorsOf(installedBundle ocv1.BundleMetadata, channels ...declcfg.Channel) (slicesutil.Predicate[declcfg.Bundle], error) {
func SuccessorsOf(installedBundle ocv1.BundleMetadata, channels ...declcfg.Channel) (filterutils.Predicate[declcfg.Bundle], error) {
installedBundleVersion, err := mmsemver.NewVersion(installedBundle.Version)
if err != nil {
return nil, fmt.Errorf("parsing installed bundle %q version %q: %w", installedBundle.Name, installedBundle.Version, err)
Expand All @@ -29,13 +29,13 @@ func SuccessorsOf(installedBundle ocv1.BundleMetadata, channels ...declcfg.Chann
}

// We need either successors or current version (no upgrade)
return slicesutil.Or(
return filterutils.Or(
successorsPredicate,
InMastermindsSemverRange(installedVersionConstraint),
), nil
}

func legacySuccessor(installedBundle ocv1.BundleMetadata, channels ...declcfg.Channel) (slicesutil.Predicate[declcfg.Bundle], error) {
func legacySuccessor(installedBundle ocv1.BundleMetadata, channels ...declcfg.Channel) (filterutils.Predicate[declcfg.Bundle], error) {
installedBundleVersion, err := bsemver.Parse(installedBundle.Version)
if err != nil {
return nil, fmt.Errorf("error parsing installed bundle version: %w", err)
Expand Down
7 changes: 4 additions & 3 deletions internal/resolve/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package resolve
import (
"context"
"fmt"
filterutils "github.com/operator-framework/operator-controller/internal/util/filter"
"slices"
"sort"
"strings"
Expand Down Expand Up @@ -76,7 +77,7 @@ func (r *CatalogResolver) Resolve(ctx context.Context, ext *ocv1.ClusterExtensio

var catStats []*catStat

resolvedBundles := []foundBundle{}
var resolvedBundles []foundBundle
var priorDeprecation *declcfg.Deprecation

listOptions := []client.ListOption{
Expand All @@ -97,7 +98,7 @@ func (r *CatalogResolver) Resolve(ctx context.Context, ext *ocv1.ClusterExtensio
cs.PackageFound = true
cs.TotalBundles = len(packageFBC.Bundles)

var predicates []slicesutil.Predicate[declcfg.Bundle]
var predicates []filterutils.Predicate[declcfg.Bundle]
if len(channels) > 0 {
channelSet := sets.New(channels...)
filteredChannels := slices.DeleteFunc(packageFBC.Channels, func(c declcfg.Channel) bool {
Expand All @@ -119,7 +120,7 @@ func (r *CatalogResolver) Resolve(ctx context.Context, ext *ocv1.ClusterExtensio
}

// Apply the predicates to get the candidate bundles
packageFBC.Bundles = slicesutil.RemoveInPlace(packageFBC.Bundles, slicesutil.And(predicates...))
packageFBC.Bundles = slicesutil.RemoveInPlace(packageFBC.Bundles, filterutils.And(predicates...))
cs.MatchedBundles = len(packageFBC.Bundles)
if len(packageFBC.Bundles) == 0 {
return nil
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,8 @@
package slices

import (
"slices"
)
package filter

// Predicate returns true if the object should be kept when filtering
type Predicate[T any] func(entity T) bool

// Filter creates a new slice with all elements from s for which the test returns true
func Filter[T any](s []T, test Predicate[T]) []T {
out := make([]T, 0, len(s))
for i := 0; i < len(s); i++ {
if test(s[i]) {
out = append(out, s[i])
}
}
return slices.Clip(out)
}

// RemoveInPlace removes all elements from s for which test returns true.
// Elements between new length and original length are zeroed out.
func RemoveInPlace[T any](s []T, test Predicate[T]) []T {
return slices.DeleteFunc(s, Not(test))
}

func And[T any](predicates ...Predicate[T]) Predicate[T] {
return func(obj T) bool {
for _, predicate := range predicates {
Expand Down
145 changes: 145 additions & 0 deletions internal/util/filter/predicates_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package filter_test

import (
"github.com/operator-framework/operator-controller/internal/util/filter"
"github.com/stretchr/testify/require"
"testing"
)

func TestAnd(t *testing.T) {
tests := []struct {
name string
predicates []filter.Predicate[int]
input int
want bool
}{
{
name: "all true",
predicates: []filter.Predicate[int]{
func(i int) bool { return i > 0 },
func(i int) bool { return i < 10 },
},
input: 5,
want: true,
},
{
name: "one false",
predicates: []filter.Predicate[int]{
func(i int) bool { return i > 0 },
func(i int) bool { return i < 5 },
},
input: 5,
want: false,
},
{
name: "all false",
predicates: []filter.Predicate[int]{
func(i int) bool { return i > 10 },
func(i int) bool { return i < 0 },
},
input: 5,
want: false,
},
{
name: "no predicates",
predicates: []filter.Predicate[int]{},
input: 5,
want: true,
},
{
name: "nil predicates",
predicates: nil,
input: 5,
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := filter.And(tt.predicates...)(tt.input)
require.Equal(t, tt.want, got, "And() = %v, want %v", got, tt.want)
})
}
}

func TestOr(t *testing.T) {
tests := []struct {
name string
predicates []filter.Predicate[int]
input int
want bool
}{
{
name: "all true",
predicates: []filter.Predicate[int]{
func(i int) bool { return i > 0 },
func(i int) bool { return i < 10 },
},
input: 5,
want: true,
},
{
name: "one false",
predicates: []filter.Predicate[int]{
func(i int) bool { return i > 0 },
func(i int) bool { return i < 5 },
},
input: 5,
want: true,
},
{
name: "all false",
predicates: []filter.Predicate[int]{
func(i int) bool { return i > 10 },
func(i int) bool { return i < 0 },
},
input: 5,
want: false,
},
{
name: "no predicates",
predicates: []filter.Predicate[int]{},
input: 5,
want: false,
},
{
name: "nil predicates",
predicates: nil,
input: 5,
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := filter.Or(tt.predicates...)(tt.input)
require.Equal(t, tt.want, got, "Or() = %v, want %v", got, tt.want)
})
}
}

func TestNot(t *testing.T) {
tests := []struct {
name string
predicate filter.Predicate[int]
input int
want bool
}{
{
name: "predicate is true",
predicate: func(i int) bool { return i > 0 },
input: 5,
want: false,
},
{
name: "predicate is false",
predicate: func(i int) bool { return i > 3 },
input: 2,
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := filter.Not(tt.predicate)(tt.input)
require.Equal(t, tt.want, got, "Not() = %v, want %v", got, tt.want)
})
}
}
Loading

0 comments on commit c7964fe

Please sign in to comment.