mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
123 lines
4.4 KiB
Go
123 lines
4.4 KiB
Go
//go:build integration
|
|
|
|
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"testing"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
"github.com/aws/aws-sdk-go/service/ecr"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// uniqueRepo returns a collision-resistant repo name scoped to a test.
|
|
// Matching the E2E source's naming keeps a future side-by-side diff greppable.
|
|
func uniqueRepo(prefix string) string {
|
|
return fmt.Sprintf("e2e/%s-%d", prefix, time.Now().UnixNano())
|
|
}
|
|
|
|
// TestECRControlPlane round-trips the ECR control-plane surface: repository
|
|
// CRUD, repository policy, and lifecycle policy. All of it dispatches to
|
|
// ECRRegistry.Meta over NATS (gateway/ecr_createrepository.go and friends), so
|
|
// this needs StartECRDaemonLite subscribed before any call.
|
|
func TestECRControlPlane(t *testing.T) {
|
|
gw := StartGateway(t)
|
|
StartECRDaemonLite(t, gw)
|
|
c := gw.ECRClient(t)
|
|
repo := uniqueRepo("ctl")
|
|
|
|
_, err := c.CreateRepository(&ecr.CreateRepositoryInput{RepositoryName: aws.String(repo)})
|
|
require.NoError(t, err, "create-repository")
|
|
|
|
t.Run("an invalid name is refused with InvalidParameterException", func(t *testing.T) {
|
|
_, err := c.CreateRepository(&ecr.CreateRepositoryInput{RepositoryName: aws.String("Bad_Name!")})
|
|
var aerr awserr.Error
|
|
require.ErrorAs(t, err, &aerr)
|
|
assert.Equal(t, ecr.ErrCodeInvalidParameterException, aerr.Code())
|
|
assert.Equal(t, `Invalid parameter at 'repositoryName' failed to satisfy constraint: 'must satisfy regular expression '[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*(/[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*)*''`, aerr.Message())
|
|
})
|
|
|
|
t.Run("DescribeRepositories lists the new repo", func(t *testing.T) {
|
|
out, err := c.DescribeRepositories(&ecr.DescribeRepositoriesInput{
|
|
RepositoryNames: []*string{aws.String(repo)},
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, out.Repositories, 1)
|
|
assert.Equal(t, repo, aws.StringValue(out.Repositories[0].RepositoryName))
|
|
assert.Contains(t, aws.StringValue(out.Repositories[0].RepositoryUri), repo)
|
|
})
|
|
|
|
t.Run("repository policy round-trips", func(t *testing.T) {
|
|
policy := `{"Version":"2012-10-17","Statement":[{"Sid":"allow-pull","Effect":"Allow","Principal":"*","Action":["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]}`
|
|
_, err := c.SetRepositoryPolicy(&ecr.SetRepositoryPolicyInput{
|
|
RepositoryName: aws.String(repo),
|
|
PolicyText: aws.String(policy),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
got, err := c.GetRepositoryPolicy(&ecr.GetRepositoryPolicyInput{
|
|
RepositoryName: aws.String(repo),
|
|
})
|
|
require.NoError(t, err)
|
|
assert.JSONEq(t, policy, aws.StringValue(got.PolicyText))
|
|
})
|
|
|
|
t.Run("lifecycle policy round-trips", func(t *testing.T) {
|
|
policy := `{"rules":[{"rulePriority":1,"selection":{"tagStatus":"untagged","countType":"sinceImagePushed","countUnit":"days","countNumber":14},"action":{"type":"expire"}}]}`
|
|
_, err := c.PutLifecyclePolicy(&ecr.PutLifecyclePolicyInput{
|
|
RepositoryName: aws.String(repo),
|
|
LifecyclePolicyText: aws.String(policy),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
got, err := c.GetLifecyclePolicy(&ecr.GetLifecyclePolicyInput{
|
|
RepositoryName: aws.String(repo),
|
|
})
|
|
require.NoError(t, err)
|
|
assert.JSONEq(t, policy, aws.StringValue(got.LifecyclePolicyText))
|
|
})
|
|
|
|
t.Run("DeleteRepository removes it", func(t *testing.T) {
|
|
_, err := c.DeleteRepository(&ecr.DeleteRepositoryInput{
|
|
RepositoryName: aws.String(repo),
|
|
Force: aws.Bool(true),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
_, err = c.DescribeRepositories(&ecr.DescribeRepositoriesInput{
|
|
RepositoryNames: []*string{aws.String(repo)},
|
|
})
|
|
require.Error(t, err, "deleted repo must not be describable")
|
|
assert.Contains(t, err.Error(), "RepositoryNotFoundException")
|
|
})
|
|
}
|
|
|
|
// TestECRGetLoginPassword confirms GetAuthorizationToken returns a usable
|
|
// AWS:<jwt> credential — the input to docker login. Minting needs only
|
|
// ECRTokenIssuer, wired unconditionally by StartGateway, so no daemon-lite
|
|
// subscription is required here.
|
|
func TestECRGetLoginPassword(t *testing.T) {
|
|
gw := StartGateway(t)
|
|
pass := ecrGetLoginPassword(t, gw.ECRClient(t))
|
|
assert.NotEmpty(t, pass)
|
|
// JWT shape: three dot-separated segments.
|
|
assert.Len(t, splitDots(pass), 3, "authorization password should be a JWT")
|
|
}
|
|
|
|
func splitDots(s string) []string {
|
|
var out []string
|
|
start := 0
|
|
for i := 0; i < len(s); i++ {
|
|
if s[i] == '.' {
|
|
out = append(out, s[start:i])
|
|
start = i + 1
|
|
}
|
|
}
|
|
return append(out, s[start:])
|
|
}
|