second first commit
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||
import {
|
||||
ConflictException,
|
||||
CreateNamespaceCommand,
|
||||
CreateTableBucketCommand,
|
||||
CreateTableCommand,
|
||||
DeleteNamespaceCommand,
|
||||
DeleteTableBucketCommand,
|
||||
DeleteTableBucketPolicyCommand,
|
||||
DeleteTableCommand,
|
||||
DeleteTablePolicyCommand,
|
||||
GetNamespaceCommand,
|
||||
GetTableBucketCommand,
|
||||
GetTableBucketMaintenanceConfigurationCommand,
|
||||
GetTableBucketPolicyCommand,
|
||||
GetTableCommand,
|
||||
GetTableMaintenanceConfigurationCommand,
|
||||
GetTableMetadataLocationCommand,
|
||||
GetTablePolicyCommand,
|
||||
ListNamespacesCommand,
|
||||
ListTableBucketsCommand,
|
||||
ListTablesCommand,
|
||||
NotFoundException,
|
||||
PutTableBucketMaintenanceConfigurationCommand,
|
||||
PutTableBucketPolicyCommand,
|
||||
PutTableMaintenanceConfigurationCommand,
|
||||
PutTablePolicyCommand,
|
||||
RenameTableCommand,
|
||||
S3TablesClient,
|
||||
UpdateTableMetadataLocationCommand,
|
||||
} from '@aws-sdk/client-s3tables';
|
||||
import { makeClient, uniqueName } from './setup';
|
||||
|
||||
describe('S3 Tables lifecycle', () => {
|
||||
let client: S3TablesClient;
|
||||
let bucketArn: string;
|
||||
const bucketName = uniqueName('table-bucket');
|
||||
const namespace = 'analytics';
|
||||
let tableName = uniqueName('events');
|
||||
let versionToken: string;
|
||||
|
||||
beforeAll(() => {
|
||||
client = makeClient(S3TablesClient);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
if (!bucketArn) return;
|
||||
await client.send(new DeleteTableCommand({ tableBucketARN: bucketArn, namespace, name: tableName })).catch(() => undefined);
|
||||
await client.send(new DeleteNamespaceCommand({ tableBucketARN: bucketArn, namespace })).catch(() => undefined);
|
||||
await client.send(new DeleteTableBucketCommand({ tableBucketARN: bucketArn })).catch(() => undefined);
|
||||
});
|
||||
|
||||
it('creates a table bucket, namespace, and Iceberg table', async () => {
|
||||
const bucket = await client.send(new CreateTableBucketCommand({
|
||||
name: bucketName,
|
||||
tags: { suite: 'sdk-node' },
|
||||
encryptionConfiguration: { sseAlgorithm: 'AES256' },
|
||||
storageClassConfiguration: { storageClass: 'STANDARD' },
|
||||
}));
|
||||
bucketArn = bucket.arn!;
|
||||
expect(bucketArn).toContain(`bucket/${bucketName}`);
|
||||
|
||||
const createdNamespace = await client.send(new CreateNamespaceCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
namespace: [namespace],
|
||||
}));
|
||||
expect(createdNamespace.namespace).toEqual([namespace]);
|
||||
|
||||
const table = await client.send(new CreateTableCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
namespace,
|
||||
name: tableName,
|
||||
format: 'ICEBERG',
|
||||
metadata: { iceberg: { properties: { 'format-version': '2' } } },
|
||||
encryptionConfiguration: { sseAlgorithm: 'AES256' },
|
||||
storageClassConfiguration: { storageClass: 'STANDARD' },
|
||||
tags: { suite: 'sdk-node' },
|
||||
}));
|
||||
versionToken = table.versionToken!;
|
||||
expect(table.tableARN).toBe(`${bucketArn}/table/${tableName}`);
|
||||
});
|
||||
|
||||
it('gets resources and applies list prefixes', async () => {
|
||||
const bucket = await client.send(new GetTableBucketCommand({ tableBucketARN: bucketArn }));
|
||||
expect(bucket.name).toBe(bucketName);
|
||||
|
||||
const buckets = await client.send(new ListTableBucketsCommand({ prefix: 'table-bucket' }));
|
||||
expect(buckets.tableBuckets?.some((item) => item.name === bucketName)).toBe(true);
|
||||
|
||||
const fetchedNamespace = await client.send(new GetNamespaceCommand({ tableBucketARN: bucketArn, namespace }));
|
||||
expect(fetchedNamespace.namespace).toEqual([namespace]);
|
||||
const namespaces = await client.send(new ListNamespacesCommand({ tableBucketARN: bucketArn, prefix: 'anal' }));
|
||||
expect(namespaces.namespaces?.some((item) => item.namespace?.includes(namespace))).toBe(true);
|
||||
|
||||
const tables = await client.send(new ListTablesCommand({ tableBucketARN: bucketArn, namespace, prefix: 'events' }));
|
||||
expect(tables.tables?.some((table) => table.name === tableName)).toBe(true);
|
||||
const table = await client.send(new GetTableCommand({ tableBucketARN: bucketArn, namespace, name: tableName }));
|
||||
expect(table.tableARN).toBe(`${bucketArn}/table/${tableName}`);
|
||||
});
|
||||
|
||||
it('round-trips policies and metadata version tokens', async () => {
|
||||
const policy = '{"Version":"2012-10-17","Statement":[]}';
|
||||
await client.send(new PutTableBucketPolicyCommand({ tableBucketARN: bucketArn, resourcePolicy: policy }));
|
||||
expect((await client.send(new GetTableBucketPolicyCommand({ tableBucketARN: bucketArn }))).resourcePolicy).toBe(policy);
|
||||
await client.send(new PutTablePolicyCommand({ tableBucketARN: bucketArn, namespace, name: tableName, resourcePolicy: policy }));
|
||||
expect((await client.send(new GetTablePolicyCommand({ tableBucketARN: bucketArn, namespace, name: tableName }))).resourcePolicy).toBe(policy);
|
||||
|
||||
const updated = await client.send(new UpdateTableMetadataLocationCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
namespace,
|
||||
name: tableName,
|
||||
metadataLocation: `s3://warehouse/${tableName}/v2.metadata.json`,
|
||||
versionToken,
|
||||
}));
|
||||
expect(updated.versionToken).not.toBe(versionToken);
|
||||
expect((await client.send(new GetTableMetadataLocationCommand({
|
||||
tableBucketARN: bucketArn, namespace, name: tableName,
|
||||
}))).metadataLocation).toBe(updated.metadataLocation);
|
||||
|
||||
await expect(client.send(new UpdateTableMetadataLocationCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
namespace,
|
||||
name: tableName,
|
||||
metadataLocation: `s3://warehouse/${tableName}/stale.metadata.json`,
|
||||
versionToken,
|
||||
}))).rejects.toBeInstanceOf(ConflictException);
|
||||
versionToken = updated.versionToken!;
|
||||
});
|
||||
|
||||
it('round-trips typed maintenance configuration maps', async () => {
|
||||
await client.send(new PutTableBucketMaintenanceConfigurationCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
type: 'icebergUnreferencedFileRemoval',
|
||||
value: { status: 'enabled' },
|
||||
}));
|
||||
const bucketMaintenance = await client.send(new GetTableBucketMaintenanceConfigurationCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
}));
|
||||
expect(bucketMaintenance.configuration?.icebergUnreferencedFileRemoval?.status).toBe('enabled');
|
||||
|
||||
await client.send(new PutTableMaintenanceConfigurationCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
namespace,
|
||||
name: tableName,
|
||||
type: 'icebergCompaction',
|
||||
value: { status: 'enabled' },
|
||||
}));
|
||||
const tableMaintenance = await client.send(new GetTableMaintenanceConfigurationCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
namespace,
|
||||
name: tableName,
|
||||
}));
|
||||
expect(tableMaintenance.configuration?.icebergCompaction?.status).toBe('enabled');
|
||||
});
|
||||
|
||||
it('renames a table and rotates its version token', async () => {
|
||||
const originalToken = versionToken;
|
||||
const renamedTableName = `${tableName}-renamed`;
|
||||
await client.send(new RenameTableCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
namespace,
|
||||
name: tableName,
|
||||
newName: renamedTableName,
|
||||
versionToken: originalToken,
|
||||
}));
|
||||
|
||||
const renamed = await client.send(new GetTableCommand({
|
||||
tableBucketARN: bucketArn,
|
||||
namespace,
|
||||
name: renamedTableName,
|
||||
}));
|
||||
expect(renamed.name).toBe(renamedTableName);
|
||||
expect(renamed.versionToken).not.toBe(originalToken);
|
||||
await expect(client.send(new GetTableCommand({ tableBucketARN: bucketArn, namespace, name: tableName })))
|
||||
.rejects.toBeInstanceOf(NotFoundException);
|
||||
tableName = renamedTableName;
|
||||
versionToken = renamed.versionToken!;
|
||||
});
|
||||
|
||||
it('deletes policies and the resource hierarchy', async () => {
|
||||
await client.send(new DeleteTablePolicyCommand({ tableBucketARN: bucketArn, namespace, name: tableName }));
|
||||
await expect(client.send(new GetTablePolicyCommand({ tableBucketARN: bucketArn, namespace, name: tableName })))
|
||||
.rejects.toBeInstanceOf(NotFoundException);
|
||||
await client.send(new DeleteTableBucketPolicyCommand({ tableBucketARN: bucketArn }));
|
||||
await expect(client.send(new GetTableBucketPolicyCommand({ tableBucketARN: bucketArn })))
|
||||
.rejects.toBeInstanceOf(NotFoundException);
|
||||
|
||||
await client.send(new DeleteTableCommand({ tableBucketARN: bucketArn, namespace, name: tableName }));
|
||||
await expect(client.send(new GetTableCommand({ tableBucketARN: bucketArn, namespace, name: tableName })))
|
||||
.rejects.toBeInstanceOf(NotFoundException);
|
||||
await client.send(new DeleteNamespaceCommand({ tableBucketARN: bucketArn, namespace }));
|
||||
await expect(client.send(new GetNamespaceCommand({ tableBucketARN: bucketArn, namespace })))
|
||||
.rejects.toBeInstanceOf(NotFoundException);
|
||||
await client.send(new DeleteTableBucketCommand({ tableBucketARN: bucketArn }));
|
||||
await expect(client.send(new GetTableBucketCommand({ tableBucketARN: bucketArn })))
|
||||
.rejects.toBeInstanceOf(NotFoundException);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user