diff --git a/pkg/deppy/solver/solver.go b/pkg/deppy/solver/solver.go deleted file mode 100644 index 785254c..0000000 --- a/pkg/deppy/solver/solver.go +++ /dev/null @@ -1,72 +0,0 @@ -package solver - -import ( - "errors" - - "github.com/operator-framework/deppy/internal/solver" - "github.com/operator-framework/deppy/pkg/deppy" -) - -// TODO: should disambiguate between solver errors due to constraints -// and other generic errors - -// Solution is returned by the Solver when the internal solver executed successfully. -// A successful execution of the solver can still end in an error when no solution can -// be found. -type Solution struct { - err error - selection map[deppy.Identifier]deppy.Variable -} - -// Error returns the resolution error in case the problem is unsat -// on successful resolution, it will return nil -func (s *Solution) Error() error { - return s.err -} - -// SelectedVariables returns the variables that were selected by the solver -// as part of the solution -func (s *Solution) SelectedVariables() map[deppy.Identifier]deppy.Variable { - return s.selection -} - -// IsSelected returns true if the variable identified by the identifier was selected -// in the solution by the resolver. It will return false otherwise. -func (s *Solution) IsSelected(identifier deppy.Identifier) bool { - _, ok := s.selection[identifier] - return ok -} - -// DeppySolver is a simple solver implementation that takes a slice of variables -// to produce a Solution (or error if no solution can be found) -type DeppySolver struct{} - -func NewDeppySolver() *DeppySolver { - return &DeppySolver{} -} - -func (d DeppySolver) Solve(vars []deppy.Variable) (*Solution, error) { - satSolver, err := solver.New() - if err != nil { - return nil, err - } - - selection, err := satSolver.Solve(vars) - if err != nil && !errors.As(err, &deppy.NotSatisfiable{}) { - return nil, err - } - - selectionMap := map[deppy.Identifier]deppy.Variable{} - for _, variable := range selection { - selectionMap[variable.Identifier()] = variable - } - - solution := &Solution{selection: selectionMap} - if err != nil { - unsatError := deppy.NotSatisfiable{} - errors.As(err, &unsatError) - solution.err = unsatError - } - - return solution, nil -} diff --git a/pkg/deppy/solver/solver_test.go b/pkg/deppy/solver/solver_test.go deleted file mode 100644 index c9568c2..0000000 --- a/pkg/deppy/solver/solver_test.go +++ /dev/null @@ -1,176 +0,0 @@ -package solver_test - -import ( - "fmt" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - . "github.com/onsi/gomega/gstruct" - - "github.com/operator-framework/deppy/pkg/deppy/input" - - "github.com/operator-framework/deppy/pkg/deppy/solver" - - "github.com/operator-framework/deppy/pkg/deppy/constraint" - - "github.com/operator-framework/deppy/pkg/deppy" -) - -func TestSolver(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Solver Suite") -} - -var _ = Describe("Entity", func() { - It("should select a mandatory entity", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Mandatory()), - input.NewSimpleVariable("2"), - } - - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution.SelectedVariables()).To(MatchAllKeys(Keys{ - deppy.Identifier("1"): Equal(input.NewSimpleVariable("1", constraint.Mandatory())), - })) - }) - - It("should select two mandatory entities", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Mandatory()), - input.NewSimpleVariable("2", constraint.Mandatory()), - } - - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution.Error()).ToNot(HaveOccurred()) - Expect(solution.SelectedVariables()).To(MatchAllKeys(Keys{ - deppy.Identifier("1"): Equal(input.NewSimpleVariable("1", constraint.Mandatory())), - deppy.Identifier("2"): Equal(input.NewSimpleVariable("2", constraint.Mandatory())), - })) - }) - - It("should select a mandatory entity and its dependency", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Mandatory(), constraint.Dependency("2")), - input.NewSimpleVariable("2"), - input.NewSimpleVariable("3"), - } - - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution.Error()).ToNot(HaveOccurred()) - Expect(solution.SelectedVariables()).To(MatchAllKeys(Keys{ - deppy.Identifier("1"): Equal(input.NewSimpleVariable("1", constraint.Mandatory(), constraint.Dependency("2"))), - deppy.Identifier("2"): Equal(input.NewSimpleVariable("2")), - })) - }) - - It("should return untyped nil error from solution.Error() when there is a solution", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Mandatory()), - } - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution).ToNot(BeNil()) - - // Using this style for the assertion to ensure that gomega - // doesn't equate nil errors of different types. - if err := solution.Error(); err != nil { - Fail(fmt.Sprintf("expected solution.Error() to be untyped nil, got %#v", solution.Error())) - } - }) - - It("should place resolution errors in the solution", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Mandatory(), constraint.Dependency("2")), - input.NewSimpleVariable("2", constraint.Prohibited()), - input.NewSimpleVariable("3"), - } - - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution.Error()).To(HaveOccurred()) - }) - - It("should select a mandatory entity and its dependency and ignore a non-mandatory prohibited variable", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Mandatory(), constraint.Dependency("2")), - input.NewSimpleVariable("2"), - input.NewSimpleVariable("3", constraint.Prohibited()), - } - - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution.Error()).ToNot(HaveOccurred()) - Expect(solution.SelectedVariables()).To(MatchAllKeys(Keys{ - deppy.Identifier("1"): Equal(input.NewSimpleVariable("1", constraint.Mandatory(), constraint.Dependency("2"))), - deppy.Identifier("2"): Equal(input.NewSimpleVariable("2")), - })) - }) - - It("should not select 'or' paths that are prohibited", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Or("2", false, false), constraint.Dependency("3")), - input.NewSimpleVariable("2", constraint.Dependency("4")), - input.NewSimpleVariable("3", constraint.Prohibited()), - input.NewSimpleVariable("4"), - } - - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution.Error()).ToNot(HaveOccurred()) - Expect(solution.SelectedVariables()).To(MatchAllKeys(Keys{ - deppy.Identifier("2"): Equal(input.NewSimpleVariable("2", constraint.Dependency("4"))), - deppy.Identifier("4"): Equal(input.NewSimpleVariable("4")), - })) - }) - - It("should respect atMost constraint", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Or("2", false, false), constraint.Dependency("3"), constraint.Dependency("4")), - input.NewSimpleVariable("2", constraint.Dependency("3")), - input.NewSimpleVariable("3", constraint.AtMost(1, "3", "4")), - input.NewSimpleVariable("4"), - } - - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution.Error()).ToNot(HaveOccurred()) - Expect(solution.SelectedVariables()).To(MatchAllKeys(Keys{ - deppy.Identifier("2"): Equal(input.NewSimpleVariable("2", constraint.Dependency("3"))), - deppy.Identifier("3"): Equal(input.NewSimpleVariable("3", constraint.AtMost(1, "3", "4"))), - })) - }) - - It("should respect dependency conflicts", func() { - variables := []deppy.Variable{ - input.NewSimpleVariable("1", constraint.Or("2", false, false), constraint.Dependency("3"), constraint.Dependency("4")), - input.NewSimpleVariable("2", constraint.Dependency("4"), constraint.Dependency("5")), - input.NewSimpleVariable("3", constraint.Conflict("6")), - input.NewSimpleVariable("4", constraint.Dependency("6")), - input.NewSimpleVariable("5"), - input.NewSimpleVariable("6"), - } - - so := solver.NewDeppySolver() - solution, err := so.Solve(variables) - Expect(err).ToNot(HaveOccurred()) - Expect(solution.Error()).ToNot(HaveOccurred()) - Expect(solution.SelectedVariables()).To(MatchAllKeys(Keys{ - deppy.Identifier("2"): Equal(input.NewSimpleVariable("2", constraint.Dependency("4"), constraint.Dependency("5"))), - deppy.Identifier("4"): Equal(input.NewSimpleVariable("4", constraint.Dependency("6"))), - deppy.Identifier("5"): Equal(input.NewSimpleVariable("5")), - deppy.Identifier("6"): Equal(input.NewSimpleVariable("6")), - })) - }) -})