cuelang.org/go@v0.10.1/internal/mod/modrequirements/requirements_test.go (about) 1 package modrequirements 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "cuelabs.dev/go/oci/ociregistry/ociclient" 9 "github.com/go-quicktest/qt" 10 "golang.org/x/tools/txtar" 11 12 "cuelang.org/go/internal/mod/mvs" 13 "cuelang.org/go/internal/registrytest" 14 "cuelang.org/go/mod/modfile" 15 "cuelang.org/go/mod/modregistry" 16 "cuelang.org/go/mod/module" 17 ) 18 19 func TestRequirements(t *testing.T) { 20 const registryContents = ` 21 -- example.com_v0.0.1/cue.mod/module.cue -- 22 module: "example.com@v0" 23 language: version: "v0.8.0" 24 deps: { 25 "foo.com/bar/hello@v0": v: "v0.2.3" 26 "bar.com@v0": v: "v0.5.0" 27 } 28 29 -- foo.com_bar_hello_v0.2.3/cue.mod/module.cue -- 30 module: "foo.com/bar/hello@v0" 31 language: version: "v0.8.0" 32 deps: { 33 "bar.com@v0": v: "v0.0.2" 34 "baz.org@v0": v: "v0.10.1" 35 } 36 37 -- bar.com_v0.0.2/cue.mod/module.cue -- 38 module: "bar.com@v0" 39 language: version: "v0.8.0" 40 deps: "baz.org@v0": v: "v0.0.2" 41 42 -- bar.com_v0.5.0/cue.mod/module.cue -- 43 module: "bar.com@v0" 44 language: version: "v0.8.0" 45 deps: "baz.org@v0": v: "v0.5.0" 46 47 -- baz.org_v0.0.2/cue.mod/module.cue -- 48 module: "baz.org@v0" 49 language: version: "v0.8.0" 50 51 -- baz.org_v0.1.2/cue.mod/module.cue -- 52 module: "baz.org@v0" 53 language: version: "v0.8.0" 54 55 -- baz.org_v0.5.0/cue.mod/module.cue -- 56 module: "baz.org@v0" 57 language: version: "v0.8.0" 58 59 -- baz.org_v0.10.1/cue.mod/module.cue -- 60 module: "baz.org@v0" 61 language: version: "v0.8.0" 62 ` 63 64 ctx := context.Background() 65 reg := newRegistry(t, registryContents) 66 67 rootVersion := mustParseVersion("example.com@v0") 68 69 rs := NewRequirements(rootVersion.Path(), reg, versions("foo.com/bar/hello@v0.2.3"), nil) 70 71 v, ok := rs.RootSelected(rootVersion.Path()) 72 qt.Assert(t, qt.IsTrue(ok)) 73 qt.Assert(t, qt.Equals(v, "")) 74 75 v, ok = rs.RootSelected("foo.com/bar/hello@v0") 76 qt.Assert(t, qt.IsTrue(ok)) 77 qt.Assert(t, qt.Equals(v, "v0.2.3")) 78 79 // Other parts of the graph aren't loaded yet. 80 v, ok = rs.RootSelected("bar.com@v0") 81 qt.Assert(t, qt.IsFalse(ok)) 82 qt.Assert(t, qt.Equals(v, "")) 83 84 mg, err := rs.Graph(ctx) 85 qt.Assert(t, qt.IsNil(err)) 86 _ = mg 87 rv, ok := mg.RequiredBy(rootVersion) 88 qt.Assert(t, qt.Equals(ok, true)) 89 qt.Assert(t, qt.DeepEquals(rv, []module.Version{ 90 module.MustParseVersion("foo.com/bar/hello@v0.2.3"), 91 })) 92 rv, ok = mg.RequiredBy(module.MustParseVersion("foo.com/bar/hello@v0.2.3")) 93 qt.Assert(t, qt.Equals(ok, true)) 94 qt.Assert(t, qt.DeepEquals(rv, versions("bar.com@v0.0.2", "baz.org@v0.10.1"))) 95 96 qt.Assert(t, qt.DeepEquals(mg.BuildList(), versions( 97 "example.com@v0", 98 "bar.com@v0.0.2", 99 "baz.org@v0.10.1", 100 "foo.com/bar/hello@v0.2.3", 101 ))) 102 } 103 104 func TestRequirementsErrorFromMissingModule(t *testing.T) { 105 const registryContents = ` 106 -- example.com_v0.0.1/cue.mod/module.cue -- 107 module: "example.com@v0" 108 language: version: "v0.8.0" 109 deps: "foo.com/bar/hello@v0": v: "v0.2.3" 110 111 -- foo.com_bar_hello_v0.2.3/cue.mod/module.cue -- 112 module: "foo.com/bar/hello@v0" 113 language: version: "v0.8.0" 114 deps: "bar.com@v0": v: "v0.0.2" // doesn't exist 115 ` 116 ctx := context.Background() 117 reg := newRegistry(t, registryContents) 118 119 rootVersion := mustParseVersion("example.com@v0") 120 rs := NewRequirements(rootVersion.Path(), reg, versions( 121 "bar.com@v0.0.2", 122 "foo.com/bar/hello@v0.2.3", 123 ), nil) 124 _, err := rs.Graph(ctx) 125 qt.Assert(t, qt.ErrorMatches(err, `bar.com@v0.0.2: module bar.com@v0.0.2: module not found`)) 126 qt.Assert(t, qt.ErrorAs(err, new(*mvs.BuildListError[module.Version]))) 127 } 128 129 func TestRequirementsWithDefaultMajorVersions(t *testing.T) { 130 rs := NewRequirements("example.com@v0", nil, versions( 131 "bar.com@v0.0.2", 132 "bar.com@v1.2.3", 133 "bar.com@v2.0.1", 134 "baz.org@v0.10.1", 135 "baz.org@v1.2.3", 136 "foo.com/bar/hello@v0.2.3", 137 ), map[string]string{ 138 "bar.com": "v1", 139 }) 140 qt.Assert(t, qt.DeepEquals(rs.DefaultMajorVersions(), map[string]string{ 141 "bar.com": "v1", 142 })) 143 tests := []struct { 144 mpath string 145 wantVersion string 146 wantStatus MajorVersionDefaultStatus 147 }{{ 148 mpath: "bar.com", 149 wantVersion: "v1", 150 wantStatus: ExplicitDefault, 151 }, { 152 mpath: "baz.org", 153 wantStatus: AmbiguousDefault, 154 }, { 155 mpath: "foo.com/bar/hello", 156 wantVersion: "v0", 157 wantStatus: NonExplicitDefault, 158 }, { 159 mpath: "other.com", 160 wantVersion: "", 161 wantStatus: NoDefault, 162 }} 163 for _, test := range tests { 164 t.Run("", func(t *testing.T) { 165 v, st := rs.DefaultMajorVersion(test.mpath) 166 qt.Check(t, qt.Equals(v, test.wantVersion)) 167 qt.Check(t, qt.Equals(st, test.wantStatus)) 168 }) 169 } 170 171 } 172 173 type registryImpl struct { 174 reg *modregistry.Client 175 } 176 177 var _ Registry = (*registryImpl)(nil) 178 179 func (r *registryImpl) Requirements(ctx context.Context, mv module.Version) ([]module.Version, error) { 180 m, err := r.reg.GetModule(ctx, mv) 181 if err != nil { 182 return nil, err 183 } 184 data, err := m.ModuleFile(ctx) 185 if err != nil { 186 return nil, fmt.Errorf("cannot get module file from %v: %v", m, err) 187 } 188 mf, err := modfile.Parse(data, mv.String()) 189 if err != nil { 190 return nil, fmt.Errorf("cannot parse module file from %v: %v", m, err) 191 } 192 return mf.DepVersions(), nil 193 } 194 195 func versions(vs ...string) []module.Version { 196 mvs := make([]module.Version, len(vs)) 197 for i, v := range vs { 198 mvs[i] = mustParseVersion(v) 199 } 200 return mvs 201 } 202 203 // mustParseVersion is like module.MustParseVersion except 204 // that it accepts non-versioned modules too, e.g. foo.com@v0. 205 func mustParseVersion(s string) module.Version { 206 if v, err := module.ParseVersion(s); err == nil { 207 return v 208 } 209 v, err := module.NewVersion(s, "") 210 if err != nil { 211 panic(err) 212 } 213 return v 214 } 215 216 func newRegistry(t *testing.T, registryContents string) Registry { 217 regFS, err := txtar.FS(txtar.Parse([]byte(registryContents))) 218 qt.Assert(t, qt.IsNil(err)) 219 regSrv, err := registrytest.New(regFS, "") 220 qt.Assert(t, qt.IsNil(err)) 221 t.Cleanup(regSrv.Close) 222 regOCI, err := ociclient.New(regSrv.Host(), &ociclient.Options{ 223 Insecure: true, 224 }) 225 qt.Assert(t, qt.IsNil(err)) 226 return ®istryImpl{modregistry.NewClient(regOCI)} 227 }