Files
athens/pkg/storage/compliance/tests.go
Nicholas Wiersma d932d50232 chore: lint code with golangci-lint (#1828)
* feat: add golangci-lint linting

* chore: fix linter issues

* feat: add linting into the workflow

* docs: update lint docs

* fix: cr suggestions

* fix: remove old formatting and vetting scripts

* fix: add docker make target

* fix: action go caching

* fix: depreciated actions checkout version

* fix: cr suggestion

* fix: cr suggestions

---------

Co-authored-by: Manu Gupta <manugupt1@gmail.com>
2023-02-24 20:39:17 -08:00

217 lines
5.8 KiB
Go

package compliance
import (
"bytes"
"context"
"fmt"
"io"
"math/rand"
"testing"
"github.com/gomods/athens/pkg/errors"
"github.com/gomods/athens/pkg/storage"
"github.com/stretchr/testify/require"
)
// RunTests takes a backend implementation and runs compliance tests
// against the interface.
func RunTests(t *testing.T, b storage.Backend, clearBackend func() error) {
require.NoError(t, clearBackend(), "pre-clearing backend failed")
defer require.NoError(t, clearBackend(), "post-clearing backend failed")
testNotFound(t, b)
testList(t, b)
testListSuffix(t, b)
testDelete(t, b)
testGet(t, b)
testExists(t, b)
testShouldNotExist(t, b)
}
// testNotFound ensures that a storage Backend
// returns a KindNotFound error when asking for
// non existing modules.
func testNotFound(t *testing.T, b storage.Backend) {
mod, ver := "github.com/gomods/athens", "yyy"
ctx := context.Background()
err := b.Delete(ctx, mod, ver)
require.Error(t, err)
require.Equal(t, errors.KindNotFound, errors.Kind(err))
_, err = b.GoMod(ctx, mod, ver)
require.Error(t, err)
require.Equal(t, errors.KindNotFound, errors.Kind(err))
_, err = b.Info(ctx, mod, ver)
require.Error(t, err)
require.Equal(t, errors.KindNotFound, errors.Kind(err))
vs, err := b.List(ctx, mod)
require.NoError(t, err)
require.Equal(t, 0, len(vs))
_, err = b.Zip(ctx, mod, ver)
require.Error(t, err)
require.Equal(t, errors.KindNotFound, errors.Kind(err))
}
// testListPrefixes makes sure that if you have two modules, such as
// github.com/one/two and github.com/one/two-suffix, then the versions
// should not be mixed just because they share a similar prefix.
func testListSuffix(t *testing.T, b storage.Backend) {
ctx := context.Background()
modVers := map[string][]string{
"github.com/one/two": {"v1.1.0", "v1.2.0", "v1.3.0"},
"github.com/one/two/v2": {"v2.1.0"},
"github.com/one/two-other": {"v0.9.0"},
"github.com/one": {}, // not a module but a valid query, so no versions
}
for modname, versions := range modVers {
for _, version := range versions {
mock := getMockModule()
err := b.Save(
ctx,
modname,
version,
mock.Mod,
mock.Zip,
mock.Info,
)
require.NoError(t, err, "Save for storage failed")
}
}
defer func() {
for modname, versions := range modVers {
for _, version := range versions {
b.Delete(ctx, modname, version)
}
}
}()
for modname, versions := range modVers {
retVersions, err := b.List(ctx, modname)
require.NoError(t, err)
if len(versions) == 0 {
require.Empty(t, retVersions)
} else {
require.Equal(t, versions, retVersions)
}
}
}
// testList tests that a storage Backend returns
// the exact list of versions that are saved.
func testList(t *testing.T, b storage.Backend) {
ctx := context.Background()
modname := "github.com/gomods/athens"
versions := []string{"v1.1.0", "v1.2.0", "v1.3.0"}
for _, version := range versions {
mock := getMockModule()
err := b.Save(
ctx,
modname,
version,
mock.Mod,
mock.Zip,
mock.Info,
)
require.NoError(t, err, "Save for storage failed")
}
defer func() {
for _, ver := range versions {
b.Delete(ctx, modname, ver)
}
}()
retVersions, err := b.List(ctx, modname)
require.NoError(t, err)
require.Equal(t, versions, retVersions)
}
// testGet saves and retrieves a module successfully.
func testGet(t *testing.T, b storage.Backend) {
ctx := context.Background()
modname := "github.com/gomods/athens"
ver := "v1.2.3"
mock := getMockModule()
zipBts, _ := io.ReadAll(mock.Zip)
b.Save(ctx, modname, ver, mock.Mod, bytes.NewReader(zipBts), mock.Info)
defer b.Delete(ctx, modname, ver)
info, err := b.Info(ctx, modname, ver)
require.NoError(t, err)
require.Equal(t, mock.Info, info)
mod, err := b.GoMod(ctx, modname, ver)
require.NoError(t, err)
require.Equal(t, string(mock.Mod), string(mod))
zip, err := b.Zip(ctx, modname, ver)
require.NoError(t, err)
givenZipBts, err := io.ReadAll(zip)
require.NoError(t, err)
require.Equal(t, zipBts, givenZipBts)
require.Equal(t, int64(len(zipBts)), zip.Size())
}
func testExists(t *testing.T, b storage.Backend) {
ctx := context.Background()
modname := "github.com/gomods/athens"
ver := "v1.2.3"
mock := getMockModule()
zipBts, _ := io.ReadAll(mock.Zip)
b.Save(ctx, modname, ver, mock.Mod, bytes.NewReader(zipBts), mock.Info)
defer b.Delete(ctx, modname, ver)
checker := storage.WithChecker(b)
exists, err := checker.Exists(ctx, modname, ver)
require.NoError(t, err)
require.Equal(t, true, exists)
}
func testShouldNotExist(t *testing.T, b storage.Backend) {
ctx := context.Background()
mod := "github.com/gomods/shouldNotExist"
ver := "v1.2.3-pre.1"
mock := getMockModule()
zipBts, _ := io.ReadAll(mock.Zip)
err := b.Save(ctx, mod, ver, mock.Mod, bytes.NewReader(zipBts), mock.Info)
require.NoError(t, err, "should successfully safe a mock module")
defer b.Delete(ctx, mod, ver)
prefixVer := "v1.2.3-pre"
exists, err := storage.WithChecker(b).Exists(ctx, mod, prefixVer)
require.NoError(t, err)
if exists {
t.Fatal("a non existing version that has the same prefix of an existing version should not exist")
}
}
// testDelete tests that a module can be deleted from a
// storage Backend and the Exists method returns false
// afterwards.
func testDelete(t *testing.T, b storage.Backend) {
ctx := context.Background()
modname := "github.com/gomods/athens"
version := fmt.Sprintf("%s%d", "delete", rand.Int())
mock := getMockModule()
err := b.Save(ctx, modname, version, mock.Mod, mock.Zip, mock.Info)
require.NoError(t, err)
err = b.Delete(ctx, modname, version)
require.NoError(t, err)
exists, err := storage.WithChecker(b).Exists(ctx, modname, version)
require.NoError(t, err)
require.Equal(t, false, exists)
}
func getMockModule() *storage.Version {
return &storage.Version{
Info: []byte("123"),
Mod: []byte("456"),
Zip: io.NopCloser(bytes.NewReader([]byte("789"))),
}
}