From b5381e02486291ce25b0a98a09576c65f2c4d5a5 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Fri, 29 Nov 2019 19:01:41 +0100 Subject: [PATCH] Make solver consume databases instead of world lists first step - it is slower in the implementation for now, but all cases seems to be sorted out. Drop Flagged() and IsSet() from solver. the solver wont care, and only the assertion value does matter (exception for uninstall) --- pkg/solver/decoder.go | 8 +- pkg/solver/decoder_test.go | 110 +++++++++---- pkg/solver/solver.go | 183 ++++++++++++++++------ pkg/solver/solver_test.go | 306 +++++++++++++++++++++++++++---------- 4 files changed, 446 insertions(+), 161 deletions(-) diff --git a/pkg/solver/decoder.go b/pkg/solver/decoder.go index bcb4d531..5781a5a7 100644 --- a/pkg/solver/decoder.go +++ b/pkg/solver/decoder.go @@ -22,7 +22,7 @@ import ( "unicode" pkg "github.com/mudler/luet/pkg/package" - "github.com/philopon/go-toposort" + toposort "github.com/philopon/go-toposort" "github.com/stevenle/topsort" ) @@ -88,7 +88,7 @@ func (assertions PackagesAssertions) EnsureOrder() PackagesAssertions { fingerprints = append(fingerprints, a.Package.GetFingerPrint()) unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered - if a.Package.Flagged() && a.Value { + if a.Value { unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered } else { orderedAssertions = append(orderedAssertions, a) // Keep last the ones which are not meant to be installed @@ -137,7 +137,7 @@ func (assertions PackagesAssertions) Order(fingerprint string) PackagesAssertion fingerprints = append(fingerprints, a.Package.GetFingerPrint()) unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered - if a.Package.Flagged() && a.Value { + if a.Value { unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered } else { orderedAssertions = append(orderedAssertions, a) // Keep last the ones which are not meant to be installed @@ -215,7 +215,7 @@ func (a PackagesAssertions) Less(i, j int) bool { func (assertions PackagesAssertions) AssertionHash() string { var fingerprint string for _, assertion := range assertions { // Note: Always order them first! - if assertion.Value && assertion.Package.Flagged() { // Tke into account only dependencies installed (get fingerprint of subgraph) + if assertion.Value { // Tke into account only dependencies installed (get fingerprint of subgraph) fingerprint += assertion.ToString() + "\n" } } diff --git a/pkg/solver/decoder_test.go b/pkg/solver/decoder_test.go index cfebaf7e..a9c80ac3 100644 --- a/pkg/solver/decoder_test.go +++ b/pkg/solver/decoder_test.go @@ -26,11 +26,22 @@ import ( ) var _ = Describe("Decoder", func() { + db := pkg.NewInMemoryDatabase(false) + dbInstalled := pkg.NewInMemoryDatabase(false) + dbDefinitions := pkg.NewInMemoryDatabase(false) + s := NewSolver(dbInstalled, dbDefinitions, db) + + BeforeEach(func() { + db = pkg.NewInMemoryDatabase(false) + dbInstalled = pkg.NewInMemoryDatabase(false) + dbDefinitions = pkg.NewInMemoryDatabase(false) + s = NewSolver(dbInstalled, dbDefinitions, db) + }) + Context("Assertion ordering", func() { eq := 0 for index := 0; index < 300; index++ { // Just to make sure we don't have false positives It("Orders them correctly #"+strconv.Itoa(index), func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -41,15 +52,23 @@ var _ = Describe("Decoder", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D, E, F, G}, db) + for _, p := range []pkg.Package{A, B, C, D, E, F, G} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Install([]pkg.Package{A}) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true})) Expect(len(solution)).To(Equal(6)) Expect(err).ToNot(HaveOccurred()) @@ -73,7 +92,6 @@ var _ = Describe("Decoder", func() { equality := 0 for index := 0; index < 300; index++ { // Just to make sure we don't have false positives It("Doesn't order them correctly otherwise #"+strconv.Itoa(index), func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -84,15 +102,23 @@ var _ = Describe("Decoder", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D, E, F, G}, db) + for _, p := range []pkg.Package{A, B, C, D, E, F, G} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Install([]pkg.Package{A}) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true})) Expect(len(solution)).To(Equal(6)) Expect(err).ToNot(HaveOccurred()) @@ -132,7 +158,6 @@ var _ = Describe("Decoder", func() { Context("Assertion hashing", func() { It("Hashes them, and could be used for comparison", func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -143,15 +168,23 @@ var _ = Describe("Decoder", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D, E, F, G}, db) + for _, p := range []pkg.Package{A, B, C, D, E, F, G} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Install([]pkg.Package{A}) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true})) Expect(len(solution)).To(Equal(6)) Expect(err).ToNot(HaveOccurred()) @@ -165,11 +198,11 @@ var _ = Describe("Decoder", func() { hash := solution.AssertionHash() solution, err = s.Install([]pkg.Package{B}) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true})) Expect(len(solution)).To(Equal(6)) Expect(err).ToNot(HaveOccurred()) @@ -183,18 +216,29 @@ var _ = Describe("Decoder", func() { Expect(solution[3].Package.GetName()).To(Equal("D")) Expect(solution[4].Package.GetName()).To(Equal("B")) Expect(solution[0].Value).ToNot(BeTrue()) - Expect(solution[0].Package.Flagged()).To(BeTrue()) Expect(hash).ToNot(Equal("")) Expect(hash2).ToNot(Equal("")) Expect(hash != hash2).To(BeTrue()) - db2 := pkg.NewInMemoryDatabase(false) + + }) + It("Hashes them, and could be used for comparison", func() { X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) Y := pkg.NewPackage("Y", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{}) Z := pkg.NewPackage("Z", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{}) - s = NewSolver([]pkg.Package{}, []pkg.Package{X, Y, Z}, db2) - solution, err = s.Install([]pkg.Package{Y}) + + for _, p := range []pkg.Package{X, Y, Z} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + solution, err := s.Install([]pkg.Package{Y}) Expect(err).ToNot(HaveOccurred()) solution2, err := s.Install([]pkg.Package{Z}) diff --git a/pkg/solver/solver.go b/pkg/solver/solver.go index ba22d117..3a98623d 100644 --- a/pkg/solver/solver.go +++ b/pkg/solver/solver.go @@ -16,9 +16,11 @@ package solver import ( - "errors" "sort" + //. "github.com/mudler/luet/pkg/logger" + "github.com/pkg/errors" + "github.com/crillab/gophersat/bf" version "github.com/hashicorp/go-version" pkg "github.com/mudler/luet/pkg/package" @@ -26,32 +28,57 @@ import ( // PackageSolver is an interface to a generic package solving algorithm type PackageSolver interface { - SetWorld(p []pkg.Package) + SetDefinitionDatabase(pkg.PackageDatabase) Install(p []pkg.Package) (PackagesAssertions, error) Uninstall(candidate pkg.Package) ([]pkg.Package, error) ConflictsWithInstalled(p pkg.Package) (bool, error) ConflictsWith(p pkg.Package, ls []pkg.Package) (bool, error) Best([]pkg.Package) pkg.Package + World() []pkg.Package } // Solver is the default solver for luet type Solver struct { - SolverDatabase pkg.PackageDatabase - Wanted []pkg.Package - Installed []pkg.Package - World []pkg.Package + DefinitionDatabase pkg.PackageDatabase + SolverDatabase pkg.PackageDatabase + Wanted []pkg.Package + InstalledDatabase pkg.PackageDatabase } // NewSolver accepts as argument two lists of packages, the first is the initial set, // the second represent all the known packages. -func NewSolver(init []pkg.Package, w []pkg.Package, solverdb pkg.PackageDatabase) PackageSolver { - for _, v := range init { - pkg.NormalizeFlagged(v) - } - for _, v := range w { - pkg.NormalizeFlagged(v) - } - return &Solver{Installed: init, World: w, SolverDatabase: solverdb} +func NewSolver(installed pkg.PackageDatabase, definitiondb pkg.PackageDatabase, solverdb pkg.PackageDatabase) PackageSolver { + // inst := pkg.NewInMemoryDatabase(false) + // def := pkg.NewInMemoryDatabase(false) + // // // FIXME: This should all be locked in the db - for now forbid the solver to be run in threads. + // for _, k := range installed.GetPackages() { + // pack, err := installed.GetPackage(k) + // if err == nil { + // inst.CreatePackage(pack) + // } + // } + // for _, k := range definitiondb.GetPackages() { + // pack, err := definitiondb.GetPackage(k) + // if err == nil { + // def.CreatePackage(pack) + // } + // } + // // FIXME: + // for _, k := range inst.GetPackages() { + // pack, err := inst.GetPackage(k) + // if err == nil { + + // pkg.NormalizeFlagged(inst, pack) + // } + // } + // for _, k := range def.GetPackages() { + // pack, err := def.GetPackage(k) + // if err == nil { + + // pkg.NormalizeFlagged(def, pack) + // } + // } + return &Solver{InstalledDatabase: installed, DefinitionDatabase: definitiondb, SolverDatabase: solverdb} } // TODO: []pkg.Package should have its own type with this kind of methods in (+Unique, sort, etc.) @@ -81,12 +108,36 @@ func (s *Solver) Best(set []pkg.Package) pkg.Package { // SetWorld is a setter for the list of all known packages to the solver -func (s *Solver) SetWorld(p []pkg.Package) { - s.World = p +func (s *Solver) SetDefinitionDatabase(db pkg.PackageDatabase) { + s.DefinitionDatabase = db +} + +func (s *Solver) World() []pkg.Package { + var all []pkg.Package + // FIXME: This should all be locked in the db - for now forbid the solver to be run in threads. + for _, k := range s.DefinitionDatabase.GetPackages() { + pack, err := s.DefinitionDatabase.GetPackage(k) + if err == nil { + all = append(all, pack) + } + } + return all +} + +func (s *Solver) Installed() []pkg.Package { + var all []pkg.Package + // FIXME: This should all be locked in the db - for now forbid the solver to be run in threads. + for _, k := range s.InstalledDatabase.GetPackages() { + pack, err := s.InstalledDatabase.GetPackage(k) + if err == nil { + all = append(all, pack) + } + } + return all } func (s *Solver) noRulesWorld() bool { - for _, p := range s.World { + for _, p := range s.World() { if len(p.GetConflicts()) != 0 || len(p.GetRequires()) != 0 { return false } @@ -97,8 +148,8 @@ func (s *Solver) noRulesWorld() bool { func (s *Solver) BuildInstalled() (bf.Formula, error) { var formulas []bf.Formula - for _, p := range s.Installed { - solvable, err := p.BuildFormula(s.SolverDatabase) + for _, p := range s.Installed() { + solvable, err := p.BuildFormula(s.DefinitionDatabase, s.SolverDatabase) if err != nil { return nil, err } @@ -124,8 +175,8 @@ func (s *Solver) BuildWorld(includeInstalled bool) (bf.Formula, error) { formulas = append(formulas, solvable) } - for _, p := range s.World { - solvable, err := p.BuildFormula(s.SolverDatabase) + for _, p := range s.World() { + solvable, err := p.BuildFormula(s.DefinitionDatabase, s.SolverDatabase) if err != nil { return nil, err } @@ -134,15 +185,42 @@ func (s *Solver) BuildWorld(includeInstalled bool) (bf.Formula, error) { return bf.And(formulas...), nil } -func (s *Solver) ConflictsWith(p pkg.Package, ls []pkg.Package) (bool, error) { - pkg.NormalizeFlagged(p) +func (s *Solver) getList(db pkg.PackageDatabase, lsp []pkg.Package) ([]pkg.Package, error) { + var ls []pkg.Package + for _, pp := range lsp { + cp, err := db.FindPackage(pp) + if err != nil { + cp = pp //Relax search, otherwise we cannot compute solutions for packages not in definitions + + //return nil, errors.Wrap(err, "Package not found in db") + } + ls = append(ls, cp) + } + return ls, nil +} + +func (s *Solver) ConflictsWith(pack pkg.Package, lsp []pkg.Package) (bool, error) { + p, err := s.DefinitionDatabase.FindPackage(pack) + if err != nil { + p = pack //Relax search, otherwise we cannot compute solutions for packages not in definitions + + // return false, errors.Wrap(err, "Package not found in definition db") + } + + ls, err := s.getList(s.DefinitionDatabase, lsp) + if err != nil { + return false, errors.Wrap(err, "Package not found in definition db") + } + + // TODO: Needs to be find in package def before encoding! + // pkg.NormalizeFlagged(s.DefinitionDatabase, p) var formulas []bf.Formula if s.noRulesWorld() { return false, nil } - encodedP, err := p.IsFlagged(true).Encode(s.SolverDatabase) + encodedP, err := p.Encode(s.SolverDatabase) if err != nil { return false, err } @@ -181,33 +259,45 @@ func (s *Solver) ConflictsWith(p pkg.Package, ls []pkg.Package) (bool, error) { } func (s *Solver) ConflictsWithInstalled(p pkg.Package) (bool, error) { - return s.ConflictsWith(p, s.Installed) + return s.ConflictsWith(p, s.Installed()) } // Uninstall takes a candidate package and return a list of packages that would be removed // in order to purge the candidate. Returns error if unsat. -func (s *Solver) Uninstall(candidate pkg.Package) ([]pkg.Package, error) { +func (s *Solver) Uninstall(c pkg.Package) ([]pkg.Package, error) { var res []pkg.Package - + candidate, err := s.InstalledDatabase.FindPackage(c) + if err != nil { + candidate = c //Relax search, otherwise we cannot compute solutions for packages not in definitions + // return nil, errors.Wrap(err, "Package not found between installed") + } // Build a fake "Installed" - Candidate and its requires tree var InstalledMinusCandidate []pkg.Package - for _, i := range s.Installed { - if !i.Matches(candidate) && !candidate.RequiresContains(i) { - InstalledMinusCandidate = append(InstalledMinusCandidate, i) + + // TODO: Can be optimized + for _, i := range s.Installed() { + if !i.Matches(candidate) { + contains, err := candidate.RequiresContains(s.SolverDatabase, i) + if err != nil { + return nil, errors.Wrap(err, "Failed getting installed list") + } + if !contains { + InstalledMinusCandidate = append(InstalledMinusCandidate, i) + } } } // Get the requirements to install the candidate - saved := s.Installed - s.Installed = []pkg.Package{} + saved := s.InstalledDatabase + s.InstalledDatabase = pkg.NewInMemoryDatabase(false) asserts, err := s.Install([]pkg.Package{candidate}) if err != nil { return nil, err } - s.Installed = saved + s.InstalledDatabase = saved for _, a := range asserts { - if a.Value && a.Package.Flagged() { + if a.Value { c, err := s.ConflictsWithInstalled(a.Package) if err != nil { @@ -249,13 +339,14 @@ func (s *Solver) BuildFormula() (bf.Formula, error) { return nil, err } W := bf.Var(encodedW) - - if len(s.Installed) == 0 { + installedWorld := s.Installed() + //TODO:Optimize + if len(installedWorld) == 0 { formulas = append(formulas, W) //bf.And(bf.True, W)) continue } - for _, installed := range s.Installed { + for _, installed := range installedWorld { encodedI, err := installed.Encode(s.SolverDatabase) if err != nil { return nil, err @@ -297,23 +388,23 @@ func (s *Solver) Solve() (PackagesAssertions, error) { // Install given a list of packages, returns package assertions to indicate the packages that must be installed in the system in order // to statisfy all the constraints -func (s *Solver) Install(coll []pkg.Package) (PackagesAssertions, error) { - for _, v := range coll { - v.IsFlagged(false) +func (s *Solver) Install(c []pkg.Package) (PackagesAssertions, error) { + + coll, err := s.getList(s.DefinitionDatabase, c) + if err != nil { + return nil, errors.Wrap(err, "Packages not found in definition db") } + s.Wanted = coll if s.noRulesWorld() { var ass PackagesAssertions - for _, p := range s.Installed { - pp := p.IsFlagged(true) - ass = append(ass, PackageAssert{Package: pp.(*pkg.DefaultPackage), Value: true}) + for _, p := range s.Installed() { + ass = append(ass, PackageAssert{Package: p.(*pkg.DefaultPackage), Value: true}) } for _, p := range s.Wanted { - pp := p.IsFlagged(true) - - ass = append(ass, PackageAssert{Package: pp.(*pkg.DefaultPackage), Value: true}) + ass = append(ass, PackageAssert{Package: p.(*pkg.DefaultPackage), Value: true}) } return ass, nil } diff --git a/pkg/solver/solver_test.go b/pkg/solver/solver_test.go index 8fffa2a6..a5db9033 100644 --- a/pkg/solver/solver_test.go +++ b/pkg/solver/solver_test.go @@ -17,7 +17,6 @@ package solver_test import ( pkg "github.com/mudler/luet/pkg/package" - "github.com/mudler/luet/pkg/solver" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -26,38 +25,66 @@ import ( var _ = Describe("Solver", func() { + db := pkg.NewInMemoryDatabase(false) + dbInstalled := pkg.NewInMemoryDatabase(false) + dbDefinitions := pkg.NewInMemoryDatabase(false) + s := NewSolver(dbInstalled, dbDefinitions, db) + + BeforeEach(func() { + db = pkg.NewInMemoryDatabase(false) + dbInstalled = pkg.NewInMemoryDatabase(false) + dbDefinitions = pkg.NewInMemoryDatabase(false) + s = NewSolver(dbInstalled, dbDefinitions, db) + }) Context("Simple set", func() { It("Solves correctly if the selected package has no requirements or conflicts and we have nothing installed yet", func() { - db := pkg.NewInMemoryDatabase(false) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{}, []pkg.Package{A, B, C}, db) + for _, p := range []pkg.Package{A, B, C} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + s = NewSolver(dbInstalled, dbDefinitions, db) + solution, err := s.Install([]pkg.Package{A}) Expect(err).ToNot(HaveOccurred()) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) Expect(len(solution)).To(Equal(1)) }) It("Solves correctly if the selected package has no requirements or conflicts and we have installed one package", func() { - db := pkg.NewInMemoryDatabase(false) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C}, db) + for _, p := range []pkg.Package{A, B, C} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + s = NewSolver(dbInstalled, dbDefinitions, db) + solution, err := s.Install([]pkg.Package{B}) Expect(err).ToNot(HaveOccurred()) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) Expect(len(solution)).To(Equal(2)) }) It("Solves correctly if the selected package to install has no requirement or conflicts, but in the world there is one with a requirement", func() { - db := pkg.NewInMemoryDatabase(false) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -65,72 +92,107 @@ var _ = Describe("Solver", func() { D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{E, C}, []pkg.Package{A, B, C, D, E}, db) + for _, p := range []pkg.Package{A, B, C, D, E} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{E, C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + s = NewSolver(dbInstalled, dbDefinitions, db) + solution, err := s.Install([]pkg.Package{A}) Expect(err).ToNot(HaveOccurred()) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: E.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: false})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: E, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: false})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: false})) Expect(len(solution)).To(Equal(5)) }) It("Solves correctly if the selected package to install has requirements", func() { - db := pkg.NewInMemoryDatabase(false) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, 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(dbInstalled, dbDefinitions, db) + solution, err := s.Install([]pkg.Package{A}) Expect(err).ToNot(HaveOccurred()) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) Expect(len(solution)).To(Equal(3)) }) It("Solves correctly", func() { - db := pkg.NewInMemoryDatabase(false) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C}, db) + for _, p := range []pkg.Package{A, B, C} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + s = NewSolver(dbInstalled, dbDefinitions, db) + solution, err := s.Install([]pkg.Package{A}) Expect(err).ToNot(HaveOccurred()) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) Expect(len(solution)).To(Equal(3)) }) It("Solves correctly more complex ones", func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, 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(dbInstalled, dbDefinitions, db) solution, err := s.Install([]pkg.Package{A}) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) Expect(len(solution)).To(Equal(4)) Expect(err).ToNot(HaveOccurred()) }) It("Solves correctly more complex ones", func() { - db := pkg.NewInMemoryDatabase(false) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -138,37 +200,53 @@ var _ = Describe("Solver", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{}, []pkg.Package{A, B, C, D, E}, db) + for _, p := range []pkg.Package{A, B, C, D, E} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + s = NewSolver(dbInstalled, dbDefinitions, db) solution, err := s.Install([]pkg.Package{A}) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) Expect(len(solution)).To(Equal(3)) Expect(err).ToNot(HaveOccurred()) }) It("Uninstalls simple package correctly", func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + s = NewSolver(dbInstalled, dbDefinitions, db) solution, err := s.Uninstall(A) Expect(err).ToNot(HaveOccurred()) Expect(solution).To(ContainElement(A.IsFlagged(false))) - // Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + // Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) Expect(len(solution)).To(Equal(1)) }) It("Find conflicts", func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -176,7 +254,16 @@ var _ = Describe("Solver", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + val, err := s.ConflictsWithInstalled(A) Expect(err).ToNot(HaveOccurred()) Expect(val).To(BeTrue()) @@ -184,7 +271,6 @@ var _ = Describe("Solver", func() { }) It("Find nested conflicts", func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -192,14 +278,22 @@ var _ = Describe("Solver", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + val, err := s.ConflictsWithInstalled(D) Expect(err).ToNot(HaveOccurred()) Expect(val).To(BeTrue()) }) It("Doesn't find nested conflicts", func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -207,14 +301,22 @@ var _ = Describe("Solver", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + val, err := s.ConflictsWithInstalled(C) Expect(err).ToNot(HaveOccurred()) Expect(val).ToNot(BeTrue()) }) It("Doesn't find conflicts", func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -222,40 +324,59 @@ var _ = Describe("Solver", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } val, err := s.ConflictsWithInstalled(C) Expect(err).ToNot(HaveOccurred()) Expect(val).ToNot(BeTrue()) }) It("Uninstalls simple packages not in world correctly", func() { - db := pkg.NewInMemoryDatabase(false) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{B, C, D}, db) + for _, p := range []pkg.Package{B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Uninstall(A) Expect(err).ToNot(HaveOccurred()) Expect(solution).To(ContainElement(A.IsFlagged(false))) - // Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + // Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) Expect(len(solution)).To(Equal(1)) }) It("Uninstalls complex packages not in world correctly", func() { - db := pkg.NewInMemoryDatabase(false) - C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{B, C, D}, db) + for _, p := range []pkg.Package{B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Uninstall(A) Expect(err).ToNot(HaveOccurred()) @@ -265,15 +386,20 @@ var _ = Describe("Solver", func() { }) It("Uninstalls complex packages correctly, even if shared deps are required by system packages", func() { - db := pkg.NewInMemoryDatabase(false) - D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Uninstall(A) Expect(err).ToNot(HaveOccurred()) @@ -284,14 +410,20 @@ var _ = Describe("Solver", func() { }) It("Uninstalls complex packages in world correctly", func() { - db := pkg.NewInMemoryDatabase(false) - C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{C}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{A, C, D}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{A, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Uninstall(A) Expect(err).ToNot(HaveOccurred()) @@ -303,23 +435,30 @@ var _ = Describe("Solver", func() { }) It("Uninstalls complex package correctly", func() { - db := pkg.NewInMemoryDatabase(false) - C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - C.IsFlagged(true) // installed + // C // installed - s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{A, B, C, D} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Uninstall(A) + Expect(err).ToNot(HaveOccurred()) + Expect(solution).To(ContainElement(A.IsFlagged(false))) Expect(solution).To(ContainElement(B.IsFlagged(false))) Expect(solution).To(ContainElement(D.IsFlagged(false))) Expect(len(solution)).To(Equal(3)) - Expect(err).ToNot(HaveOccurred()) }) @@ -328,14 +467,20 @@ var _ = Describe("Solver", func() { Context("Conflict set", func() { It("is unsolvable - as we something we ask to install conflict with system stuff", func() { - db := pkg.NewInMemoryDatabase(false) - C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) // D := pkg.NewPackage("D", "", []pkg.Package{}, []pkg.Package{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{C}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C}, db) + for _, p := range []pkg.Package{A, B, C} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Install([]pkg.Package{A}) Expect(len(solution)).To(Equal(0)) @@ -346,8 +491,6 @@ var _ = Describe("Solver", func() { Context("Complex data sets", func() { It("Solves them correctly", func() { - db := pkg.NewInMemoryDatabase(false) - C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) @@ -357,18 +500,26 @@ var _ = Describe("Solver", func() { B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) - s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D, E, F, G}, db) + for _, p := range []pkg.Package{A, B, C, D, E, F, G} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + for _, p := range []pkg.Package{C} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } solution, err := s.Install([]pkg.Package{A}) - Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) - Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) + Expect(err).ToNot(HaveOccurred()) + + Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true})) + Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true})) Expect(len(solution)).To(Equal(6)) - Expect(err).ToNot(HaveOccurred()) }) }) @@ -391,7 +542,6 @@ var _ = Describe("Solver", func() { Expect(lst).To(ContainElement(a03)) Expect(lst).ToNot(ContainElement(old)) Expect(len(lst)).To(Equal(5)) - s := solver.NewSolver([]pkg.Package{}, []pkg.Package{}, pkg.NewInMemoryDatabase(false)) p := s.Best(lst) Expect(p).To(Equal(a03)) })