1 package modcache
2
3 import (
4 "bytes"
5 "context"
6 "fmt"
7 "io/fs"
8 "os"
9 "path/filepath"
10 "sync"
11 "testing"
12
13 "cuelabs.dev/go/oci/ociregistry"
14 "cuelabs.dev/go/oci/ociregistry/ociclient"
15 "github.com/go-quicktest/qt"
16 "golang.org/x/tools/txtar"
17
18 "cuelang.org/go/internal/registrytest"
19 "cuelang.org/go/internal/txtarfs"
20 "cuelang.org/go/mod/modregistry"
21 "cuelang.org/go/mod/module"
22 )
23
24 func TestRequirements(t *testing.T) {
25 dir := t.TempDir()
26 ctx := context.Background()
27 r := newRegistry(t, `
28 -- example.com_foo_v0.0.1/cue.mod/module.cue --
29 module: "example.com/foo@v0"
30 deps: {
31 "foo.com/bar/hello@v0": v: "v0.2.3"
32 "bar.com@v0": v: "v0.5.0"
33 }
34 `)
35 wantRequirements := []module.Version{
36 module.MustNewVersion("bar.com", "v0.5.0"),
37 module.MustNewVersion("foo.com/bar/hello", "v0.2.3"),
38 }
39
40 var wg sync.WaitGroup
41 fetch := func(r ociregistry.Interface) {
42 defer wg.Done()
43 cr, err := New(modregistry.NewClient(r), dir)
44 if !qt.Check(t, qt.IsNil(err)) {
45 return
46 }
47 summary, err := cr.Requirements(ctx, module.MustNewVersion("example.com/foo", "v0.0.1"))
48 if !qt.Check(t, qt.IsNil(err)) {
49 return
50 }
51 if !qt.Check(t, qt.DeepEquals(summary, wantRequirements)) {
52 return
53 }
54
55 summary, err = cr.Requirements(ctx, module.MustNewVersion("example.com/foo", "v0.0.1"))
56 if !qt.Check(t, qt.IsNil(err)) {
57 return
58 }
59 if !qt.Check(t, qt.DeepEquals(summary, wantRequirements)) {
60 return
61 }
62 }
63 wg.Add(2)
64 go fetch(r)
65 go fetch(r)
66 wg.Wait()
67
68
69 wg.Add(1)
70 fetch(nil)
71
72
73 data, err := os.ReadFile(filepath.Join(dir, "cache/download/example.com/foo/@v/v0.0.1.mod"))
74 qt.Assert(t, qt.IsNil(err))
75 qt.Assert(t, qt.Matches(string(data), `(?s).*module: "example.com/foo@v0".*`))
76 }
77
78 func TestFetch(t *testing.T) {
79 dir := t.TempDir()
80 t.Cleanup(func() {
81 RemoveAll(dir)
82 })
83 ctx := context.Background()
84 registryContents := `
85 -- example.com_foo_v0.0.1/cue.mod/module.cue --
86 module: "example.com/foo@v0"
87 deps: {
88 "foo.com/bar/hello@v0": v: "v0.2.3"
89 "bar.com@v0": v: "v0.5.0"
90 }
91 -- example.com_foo_v0.0.1/example.cue --
92 package example
93 -- example.com_foo_v0.0.1/x/x.cue --
94 package x
95 `
96 r := newRegistry(t, registryContents)
97 wantContents, err := txtarContents(fsSub(txtarfs.FS(txtar.Parse([]byte(registryContents))), "example.com_foo_v0.0.1"))
98 qt.Assert(t, qt.IsNil(err))
99 checkContents := func(t *testing.T, loc module.SourceLoc) bool {
100 gotContents, err := txtarContents(fsSub(loc.FS, loc.Dir))
101 if !qt.Check(t, qt.IsNil(err)) {
102 return false
103 }
104 if !qt.Check(t, qt.Equals(string(gotContents), string(wantContents))) {
105 return false
106 }
107
108 osrFS, ok := loc.FS.(module.OSRootFS)
109 if !qt.Check(t, qt.IsTrue(ok)) {
110 return false
111 }
112 root := osrFS.OSRoot()
113 if !qt.Check(t, qt.Not(qt.Equals(root, ""))) {
114 return false
115 }
116
117 srcPath := filepath.Join(root, loc.Dir, "example.cue")
118 data, err := os.ReadFile(srcPath)
119 qt.Assert(t, qt.IsNil(err))
120 qt.Assert(t, qt.Equals(string(data), "package example\n"))
121
122 qt.Check(t, qt.Equals(srcPath, filepath.Join(dir, "example.com", "foo@v0.0.1", "example.cue")))
123 return true
124 }
125 var wg sync.WaitGroup
126 fetch := func(r ociregistry.Interface) {
127 defer wg.Done()
128 cr, err := New(modregistry.NewClient(r), dir)
129 if !qt.Check(t, qt.IsNil(err)) {
130 return
131 }
132 loc, err := cr.Fetch(ctx, module.MustNewVersion("example.com/foo", "v0.0.1"))
133 if !qt.Check(t, qt.IsNil(err)) {
134 return
135 }
136 checkContents(t, loc)
137 }
138 wg.Add(2)
139 go fetch(r)
140 go fetch(r)
141 wg.Wait()
142
143 wg.Add(1)
144 fetch(nil)
145 }
146
147 func fsSub(fsys fs.FS, sub string) fs.FS {
148 fsys, err := fs.Sub(fsys, sub)
149 if err != nil {
150 panic(err)
151 }
152 return fsys
153 }
154
155
156
157
158 func txtarContents(fsys fs.FS) ([]byte, error) {
159 var buf bytes.Buffer
160 err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
161 if err != nil {
162 return err
163 }
164 if d.IsDir() {
165 return nil
166 }
167 data, err := fs.ReadFile(fsys, path)
168 if err != nil {
169 return err
170 }
171 fmt.Fprintf(&buf, "-- %s --\n", path)
172 buf.Write(data)
173 return nil
174 })
175 return buf.Bytes(), err
176 }
177
178 func newRegistry(t *testing.T, registryContents string) ociregistry.Interface {
179 regSrv, err := registrytest.New(txtarfs.FS(txtar.Parse([]byte(registryContents))), "")
180 qt.Assert(t, qt.IsNil(err))
181 t.Cleanup(regSrv.Close)
182 regOCI, err := ociclient.New(regSrv.Host(), &ociclient.Options{
183 Insecure: true,
184 })
185 qt.Assert(t, qt.IsNil(err))
186 return regOCI
187 }
188
View as plain text