diff --git a/pkg/solver/decoder.go b/pkg/solver/decoder.go index 00cd947c..20e2ec12 100644 --- a/pkg/solver/decoder.go +++ b/pkg/solver/decoder.go @@ -146,6 +146,17 @@ func (assertions PackagesAssertions) Search(f string) *PackageAssert { return nil } +func (assertions PackagesAssertions) ToDB() pkg.PackageDatabase { + db := pkg.NewInMemoryDatabase(false) + for _, a := range assertions { + if a.Value { + db.CreatePackage(a.Package) + } + } + + return db +} + func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fingerprint string) (PackagesAssertions, error) { orderedAssertions := PackagesAssertions{} diff --git a/pkg/solver/solver.go b/pkg/solver/solver.go index b8baa572..bfff08d6 100644 --- a/pkg/solver/solver.go +++ b/pkg/solver/solver.go @@ -503,36 +503,41 @@ func inPackage(list []pkg.Package, p pkg.Package) bool { } // Compute upgrade between packages if specified, or all if none is specified -func (s *Solver) computeUpgrade(pps ...pkg.Package) func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase) { - return func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase) { +func (s *Solver) computeUpgrade(ppsToUpgrade, ppsToNotUpgrade []pkg.Package) func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase, []pkg.Package) { + return func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase, []pkg.Package) { toUninstall := pkg.Packages{} toInstall := pkg.Packages{} // we do this in memory so we take into account of provides, and its faster universe, _ := defDB.Copy() - installedcopy := pkg.NewInMemoryDatabase(false) - for _, p := range installDB.World() { installedcopy.CreatePackage(p) packages, err := universe.FindPackageVersions(p) + if err == nil && len(packages) != 0 { best := packages.Best(nil) - if !best.Matches(p) && len(pps) == 0 || - len(pps) != 0 && inPackage(pps, p) { + + // This make sure that we don't try to upgrade something that was specified + // specifically to not be marked for upgrade + // At the same time, makes sure that if we mark a package to look for upgrades + // it doesn't have to be in the blacklist (the packages to NOT upgrade) + if !best.Matches(p) && + ((len(ppsToUpgrade) == 0 && len(ppsToNotUpgrade) == 0) || + (inPackage(ppsToUpgrade, p) && !inPackage(ppsToNotUpgrade, p)) || + (len(ppsToUpgrade) == 0 && !inPackage(ppsToNotUpgrade, p))) { toUninstall = append(toUninstall, p) toInstall = append(toInstall, best) } } } - return toUninstall, toInstall, installedcopy + return toUninstall, toInstall, installedcopy, ppsToUpgrade } } -func (s *Solver) upgrade(fn func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase), defDB pkg.PackageDatabase, installDB pkg.PackageDatabase, checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error) { - - toUninstall, toInstall, installedcopy := fn(defDB, installDB) +func (s *Solver) upgrade(psToUpgrade, psToNotUpgrade pkg.Packages, fn func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase, []pkg.Package), defDB pkg.PackageDatabase, installDB pkg.PackageDatabase, checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error) { + toUninstall, toInstall, installedcopy, packsToUpgrade := fn(defDB, installDB) s2 := NewSolver(Options{Type: SingleCoreSimple}, installedcopy, defDB, pkg.NewInMemoryDatabase(false)) s2.SetResolver(s.Resolver) if !full { @@ -560,14 +565,42 @@ func (s *Solver) upgrade(fn func(defDB pkg.PackageDatabase, installDB pkg.Packag } return toUninstall, ass, nil } - assertions, err := s2.RelaxedInstall(toInstall.Unique()) + wantedSystem := assertions.ToDB() + + fn = s.computeUpgrade(pkg.Packages{}, pkg.Packages{}) + if len(packsToUpgrade) > 0 { + // If we have packages in input, + // compute what we are looking to upgrade. + // those are assertions minus packsToUpgrade + + var selectedPackages []pkg.Package + + for _, p := range assertions { + if p.Value && !inPackage(psToUpgrade, p.Package) { + selectedPackages = append(selectedPackages, p.Package) + } + } + fn = s.computeUpgrade(selectedPackages, psToNotUpgrade) + } + + _, toInstall, _, _ = fn(defDB, wantedSystem) + if len(toInstall) > 0 { + _, toInstall, ass := s.upgrade(psToUpgrade, psToNotUpgrade, fn, defDB, wantedSystem, checkconflicts, full) + return toUninstall, toInstall, ass + } return toUninstall, assertions, err } func (s *Solver) Upgrade(checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error) { - return s.upgrade(s.computeUpgrade(), s.DefinitionDatabase, s.InstalledDatabase, checkconflicts, full) + + installedcopy := pkg.NewInMemoryDatabase(false) + err := s.InstalledDatabase.Clone(installedcopy) + if err != nil { + return nil, nil, err + } + return s.upgrade(pkg.Packages{}, pkg.Packages{}, s.computeUpgrade(pkg.Packages{}, pkg.Packages{}), s.DefinitionDatabase, installedcopy, checkconflicts, full) } // Uninstall takes a candidate package and return a list of packages that would be removed @@ -787,16 +820,18 @@ func (s *Solver) Install(c pkg.Packages) (PackagesAssertions, error) { systemAfterInstall := pkg.NewInMemoryDatabase(false) toUpgrade := pkg.Packages{} - + toNotUpgrade := pkg.Packages{} for _, p := range c { if p.GetVersion() == ">=0" || p.GetVersion() == ">0" { toUpgrade = append(toUpgrade, p) + } else { + toNotUpgrade = append(toNotUpgrade, p) } } for _, p := range assertions { if p.Value { systemAfterInstall.CreatePackage(p.Package) - if !inPackage(c, p.Package) { + if !inPackage(c, p.Package) && !inPackage(toUpgrade, p.Package) && !inPackage(toNotUpgrade, p.Package) { toUpgrade = append(toUpgrade, p.Package) } } @@ -805,21 +840,26 @@ func (s *Solver) Install(c pkg.Packages) (PackagesAssertions, error) { if len(toUpgrade) == 0 { return assertions, nil } - // do partial upgrade based on input. - // IF there is no version specified in the input, or >=0 is specified, - // then compute upgrade for those - _, newassertions, err := s.upgrade(s.computeUpgrade(toUpgrade...), s.DefinitionDatabase, systemAfterInstall, false, false) - if err != nil { - // TODO: Emit warning. - // We were not able to compute upgrades (maybe for some pinned packages, or a conflict) - // so we return the relaxed result - return assertions, nil + + toUninstall, _, _, _ := s.computeUpgrade(toUpgrade, toNotUpgrade)(s.DefinitionDatabase, systemAfterInstall) + if len(toUninstall) > 0 { + // do partial upgrade based on input. + // IF there is no version specified in the input, or >=0 is specified, + // then compute upgrade for those + _, newassertions, err := s.upgrade(toUpgrade, toNotUpgrade, s.computeUpgrade(toUpgrade, toNotUpgrade), s.DefinitionDatabase, systemAfterInstall, false, false) + if err != nil { + // TODO: Emit warning. + // We were not able to compute upgrades (maybe for some pinned packages, or a conflict) + // so we return the relaxed result + return assertions, nil + } + + // Protect if we return no assertion at all + if len(newassertions) == 0 && len(assertions) > 0 { + return assertions, nil + } + return newassertions, nil } - // Protect if we return no assertion at all - if len(newassertions) == 0 && len(assertions) > 0 { - return assertions, nil - } - - return newassertions, nil + return assertions, nil } diff --git a/pkg/solver/solver_test.go b/pkg/solver/solver_test.go index cec95be2..f442408a 100644 --- a/pkg/solver/solver_test.go +++ b/pkg/solver/solver_test.go @@ -16,8 +16,6 @@ package solver_test import ( - "fmt" - pkg "github.com/mudler/luet/pkg/package" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -40,141 +38,142 @@ var _ = Describe("Solver", func() { }) Context("Select of best available package", func() { + for i := 0; i < 200; i++ { - It("picks the best versions available for each package, excluding the ones manually specified while installing", func() { + It("picks the best versions available for each package, excluding the ones manually specified while installing", func() { - B1 := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - B2 := pkg.NewPackage("B", "1.2", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - B3 := pkg.NewPackage("B", "1.3", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - B4 := pkg.NewPackage("B", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + B1 := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + B2 := pkg.NewPackage("B", "1.2", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + B3 := pkg.NewPackage("B", "1.3", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + B4 := pkg.NewPackage("B", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - A1 := pkg.NewPackage("A", "1.1", []*pkg.DefaultPackage{ - pkg.NewPackage("B", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), - }, []*pkg.DefaultPackage{}) - A2 := pkg.NewPackage("A", "1.2", []*pkg.DefaultPackage{ - pkg.NewPackage("B", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), - }, []*pkg.DefaultPackage{}) + A1 := pkg.NewPackage("A", "1.1", []*pkg.DefaultPackage{ + pkg.NewPackage("B", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), + }, []*pkg.DefaultPackage{}) + A2 := pkg.NewPackage("A", "1.2", []*pkg.DefaultPackage{ + pkg.NewPackage("B", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), + }, []*pkg.DefaultPackage{}) - D := pkg.NewPackage("D", "1.0", []*pkg.DefaultPackage{ - pkg.NewPackage("A", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), - }, []*pkg.DefaultPackage{}) + D := pkg.NewPackage("D", "1.0", []*pkg.DefaultPackage{ + pkg.NewPackage("A", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), + }, []*pkg.DefaultPackage{}) - C := pkg.NewPackage("C", "1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + C := pkg.NewPackage("C", "1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + + for _, p := range []pkg.Package{A1, A2, B1, B2, B3, B4, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db) + + solution, err := s.(*Solver).Install([]pkg.Package{D}) - for _, p := range []pkg.Package{A1, A2, B1, B2, B3, B4, C, D} { - _, err := dbDefinitions.CreatePackage(p) Expect(err).ToNot(HaveOccurred()) - } + Expect(len(solution)).To(Equal(8)) - for _, p := range []pkg.Package{C} { - _, err := dbInstalled.CreatePackage(p) + // Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B4, Value: true})) + + Expect(solution).To(ContainElement(PackageAssert{Package: A1, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B1, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B2, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false})) + + s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db) + + solution, err = s.(*Solver).Install([]pkg.Package{D, B2}) Expect(err).ToNot(HaveOccurred()) - } - s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db) + Expect(len(solution)).To(Equal(8)) - solution, err := s.(*Solver).Install([]pkg.Package{D}) - fmt.Println(solution) - Expect(err).ToNot(HaveOccurred()) - Expect(len(solution)).To(Equal(8)) + // Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B2, Value: true})) - // Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B4, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A1, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B1, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B4, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: A1, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B1, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B2, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false})) + }) - s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db) + It("picks the best available excluding those manually input. In this case we the input is a selector >=0", func() { - solution, err = s.(*Solver).Install([]pkg.Package{D, B2}) - fmt.Println(solution) - Expect(err).ToNot(HaveOccurred()) - Expect(len(solution)).To(Equal(8)) + B1 := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + B2 := pkg.NewPackage("B", "1.2", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + B3 := pkg.NewPackage("B", "1.3", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + B4 := pkg.NewPackage("B", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - // Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B2, Value: true})) + A1 := pkg.NewPackage("A", "1.1", []*pkg.DefaultPackage{ + pkg.NewPackage("B", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), + }, []*pkg.DefaultPackage{}) + A2 := pkg.NewPackage("A", "1.2", []*pkg.DefaultPackage{ + pkg.NewPackage("B", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), + }, []*pkg.DefaultPackage{}) - Expect(solution).To(ContainElement(PackageAssert{Package: A1, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B1, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B4, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false})) + D := pkg.NewPackage("D", "1.0", []*pkg.DefaultPackage{ + pkg.NewPackage("A", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), + }, []*pkg.DefaultPackage{}) - }) + C := pkg.NewPackage("C", "1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - It("picks the best available excluding those manually input. In this case we the input is a selector >=0", func() { + for _, p := range []pkg.Package{A1, A2, B1, B2, B3, B4, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } - B1 := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - B2 := pkg.NewPackage("B", "1.2", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - B3 := pkg.NewPackage("B", "1.3", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - B4 := pkg.NewPackage("B", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db) - A1 := pkg.NewPackage("A", "1.1", []*pkg.DefaultPackage{ - pkg.NewPackage("B", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), - }, []*pkg.DefaultPackage{}) - A2 := pkg.NewPackage("A", "1.2", []*pkg.DefaultPackage{ - pkg.NewPackage("B", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), - }, []*pkg.DefaultPackage{}) - - D := pkg.NewPackage("D", "1.0", []*pkg.DefaultPackage{ - pkg.NewPackage("A", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), - }, []*pkg.DefaultPackage{}) - - C := pkg.NewPackage("C", "1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - - for _, p := range []pkg.Package{A1, A2, B1, B2, B3, B4, C, D} { - _, err := dbDefinitions.CreatePackage(p) + solution, err := s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})}) Expect(err).ToNot(HaveOccurred()) - } + Expect(len(solution)).To(Equal(8)) - for _, p := range []pkg.Package{C} { - _, err := dbInstalled.CreatePackage(p) + // Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B4, Value: true})) + + Expect(solution).To(ContainElement(PackageAssert{Package: A1, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B1, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B2, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false})) + + s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db) + + solution, err = s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), B2}) Expect(err).ToNot(HaveOccurred()) - } - s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db) + Expect(len(solution)).To(Equal(8)) - solution, err := s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})}) - fmt.Println(solution) - Expect(err).ToNot(HaveOccurred()) - Expect(len(solution)).To(Equal(8)) + // Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B2, Value: true})) - // Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B4, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A1, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B1, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B4, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: A1, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B1, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B2, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false})) + }) - s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db) - - solution, err = s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), B2}) - fmt.Println(solution) - Expect(err).ToNot(HaveOccurred()) - Expect(len(solution)).To(Equal(8)) - - // Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B2, Value: true})) - - Expect(solution).To(ContainElement(PackageAssert{Package: A1, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B1, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B4, Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false})) - - }) + } }) + Context("Simple set", func() { It("Solves correctly if the selected package has no requirements or conflicts and we have nothing installed yet", func() {