second first commit
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* ECR control-plane compatibility tests.
|
||||
*
|
||||
* Test-first: this file is committed before the server-side ECR implementation
|
||||
* lands. With ECR unimplemented, every test below should fail.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||
import {
|
||||
ECRClient,
|
||||
CreateRepositoryCommand,
|
||||
DescribeRepositoriesCommand,
|
||||
DeleteRepositoryCommand,
|
||||
GetAuthorizationTokenCommand,
|
||||
ListImagesCommand,
|
||||
PutImageTagMutabilityCommand,
|
||||
PutLifecyclePolicyCommand,
|
||||
GetLifecyclePolicyCommand,
|
||||
SetRepositoryPolicyCommand,
|
||||
GetRepositoryPolicyCommand,
|
||||
ImageTagMutability,
|
||||
RepositoryAlreadyExistsException,
|
||||
RepositoryNotFoundException,
|
||||
} from '@aws-sdk/client-ecr';
|
||||
import { makeClient } from './setup';
|
||||
|
||||
const REPO_NAME = 'floci-it/app-node';
|
||||
|
||||
describe('ECR Repository Lifecycle', () => {
|
||||
let ecr: ECRClient;
|
||||
|
||||
beforeAll(() => {
|
||||
ecr = makeClient(ECRClient);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
try {
|
||||
await ecr.send(new DeleteRepositoryCommand({ repositoryName: REPO_NAME, force: true }));
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
|
||||
it('CreateRepository returns a repositoryUri pointing at loopback', async () => {
|
||||
const resp = await ecr.send(new CreateRepositoryCommand({ repositoryName: REPO_NAME }));
|
||||
const repo = resp.repository!;
|
||||
expect(repo.repositoryName).toBe(REPO_NAME);
|
||||
expect(repo.repositoryArn).toMatch(new RegExp(`^arn:aws:ecr:.*:.*:repository/${REPO_NAME}$`));
|
||||
expect(repo.repositoryUri).toContain(`/${REPO_NAME}`);
|
||||
expect(repo.repositoryUri).toContain('localhost:');
|
||||
});
|
||||
|
||||
it('CreateRepository on duplicate name throws RepositoryAlreadyExistsException', async () => {
|
||||
await expect(
|
||||
ecr.send(new CreateRepositoryCommand({ repositoryName: REPO_NAME })),
|
||||
).rejects.toBeInstanceOf(RepositoryAlreadyExistsException);
|
||||
});
|
||||
|
||||
it('DescribeRepositories returns the created repository', async () => {
|
||||
const resp = await ecr.send(
|
||||
new DescribeRepositoriesCommand({ repositoryNames: [REPO_NAME] }),
|
||||
);
|
||||
expect(resp.repositories?.[0]?.repositoryName).toBe(REPO_NAME);
|
||||
});
|
||||
|
||||
it('GetAuthorizationToken returns a usable docker login token', async () => {
|
||||
const resp = await ecr.send(new GetAuthorizationTokenCommand({}));
|
||||
expect(resp.authorizationData).toBeTruthy();
|
||||
const data = resp.authorizationData![0];
|
||||
expect(data.authorizationToken).toBeTruthy();
|
||||
expect(data.proxyEndpoint).toMatch(/^https?:\/\//);
|
||||
expect(data.expiresAt).toBeDefined();
|
||||
const decoded = Buffer.from(data.authorizationToken!, 'base64').toString('utf-8');
|
||||
expect(decoded).toMatch(/^AWS:/);
|
||||
});
|
||||
|
||||
it('ListImages on an empty repository returns no image identifiers', async () => {
|
||||
const resp = await ecr.send(new ListImagesCommand({ repositoryName: REPO_NAME }));
|
||||
expect(resp.imageIds ?? []).toEqual([]);
|
||||
});
|
||||
|
||||
it('PutImageTagMutability round-trips IMMUTABLE', async () => {
|
||||
const resp = await ecr.send(
|
||||
new PutImageTagMutabilityCommand({
|
||||
repositoryName: REPO_NAME,
|
||||
imageTagMutability: ImageTagMutability.IMMUTABLE,
|
||||
}),
|
||||
);
|
||||
expect(resp.imageTagMutability).toBe(ImageTagMutability.IMMUTABLE);
|
||||
});
|
||||
|
||||
it('PutLifecyclePolicy round-trips the policy text', async () => {
|
||||
const policy =
|
||||
'{"rules":[{"rulePriority":1,"selection":{"tagStatus":"untagged","countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}';
|
||||
await ecr.send(
|
||||
new PutLifecyclePolicyCommand({ repositoryName: REPO_NAME, lifecyclePolicyText: policy }),
|
||||
);
|
||||
const got = await ecr.send(new GetLifecyclePolicyCommand({ repositoryName: REPO_NAME }));
|
||||
expect(got.lifecyclePolicyText).toBe(policy);
|
||||
});
|
||||
|
||||
it('SetRepositoryPolicy round-trips the policy text', async () => {
|
||||
const policy =
|
||||
'{"Version":"2012-10-17","Statement":[{"Sid":"AllowAll","Effect":"Allow","Principal":"*","Action":"ecr:*"}]}';
|
||||
await ecr.send(
|
||||
new SetRepositoryPolicyCommand({ repositoryName: REPO_NAME, policyText: policy }),
|
||||
);
|
||||
const got = await ecr.send(new GetRepositoryPolicyCommand({ repositoryName: REPO_NAME }));
|
||||
expect(got.policyText).toBe(policy);
|
||||
});
|
||||
|
||||
it('DeleteRepository force=true removes the repository', async () => {
|
||||
await ecr.send(new DeleteRepositoryCommand({ repositoryName: REPO_NAME, force: true }));
|
||||
await expect(
|
||||
ecr.send(new DescribeRepositoriesCommand({ repositoryNames: [REPO_NAME] })),
|
||||
).rejects.toBeInstanceOf(RepositoryNotFoundException);
|
||||
});
|
||||
|
||||
it('DescribeRepositories on missing name throws RepositoryNotFoundException', async () => {
|
||||
await expect(
|
||||
ecr.send(
|
||||
new DescribeRepositoriesCommand({ repositoryNames: ['does-not-exist-node'] }),
|
||||
),
|
||||
).rejects.toBeInstanceOf(RepositoryNotFoundException);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user