...

Source file src/cuelang.org/go/internal/mod/modrequirements/requirements_test.go

Documentation: cuelang.org/go/internal/mod/modrequirements

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

View as plain text