51a0a60a73
CI / checks (pull_request) Successful in 25m28s
CI failed on a different set of tests each run because bun runs every test file in one process and the file order differs between machines: - the secretsmanager route test replaced the whole ../aws module, so files loaded after it lost awsClients, lambda and defaultAccountId (API Gateway, SES) - the Lightsail tests restored FLOCI_ENDPOINT by assigning undefined, which stores the string "undefined" (runtime diagnostics) - the auth tests used full-strength argon2 for ~30 sign-ins and timed out on slower runners; the OIDC cleanup test cached a discovery document without userinfo_endpoint for the shared issuer Checked with 20 runs under bun test --randomize.
116 lines
5.4 KiB
TypeScript
116 lines
5.4 KiB
TypeScript
import {afterEach, describe, expect, test} from 'bun:test'
|
|
import {
|
|
CloseInstancePublicPortsCommand,
|
|
CreateInstancesCommand,
|
|
DeleteInstanceCommand,
|
|
GetInstanceCommand,
|
|
GetInstancesCommand,
|
|
OpenInstancePublicPortsCommand,
|
|
RebootInstanceCommand,
|
|
StartInstanceCommand,
|
|
StopInstanceCommand,
|
|
type LightsailClient,
|
|
} from '@aws-sdk/client-lightsail'
|
|
import {AwsLightsailAdapter} from './AwsLightsailAdapter'
|
|
|
|
const originalEndpoint = process.env.FLOCI_ENDPOINT
|
|
|
|
afterEach(() => {
|
|
// Assigning undefined would store the string "undefined" for every later test file.
|
|
if (originalEndpoint === undefined) delete process.env.FLOCI_ENDPOINT
|
|
else process.env.FLOCI_ENDPOINT = originalEndpoint
|
|
})
|
|
|
|
function stubLightsail() {
|
|
const sent: object[] = []
|
|
const client = {
|
|
async send(command: object) {
|
|
sent.push(command)
|
|
if (command instanceof GetInstancesCommand) return {instances: [instance('web')]}
|
|
if (command instanceof GetInstanceCommand) return {instance: instance(command.input.instanceName ?? 'web')}
|
|
return {}
|
|
},
|
|
} as unknown as LightsailClient
|
|
return {client, sent}
|
|
}
|
|
|
|
function instance(name: string) {
|
|
return {
|
|
name,
|
|
arn: `arn:aws:lightsail:us-east-1:000000000000:Instance/${name}`,
|
|
createdAt: new Date('2026-10-09T00:00:00Z'),
|
|
state: {name: 'running'},
|
|
blueprintId: 'ubuntu_22_04',
|
|
blueprintName: 'Ubuntu',
|
|
bundleId: 'nano_3_0',
|
|
publicIpAddress: '203.0.113.10',
|
|
privateIpAddress: '10.0.0.10',
|
|
networking: {staticIp: '203.0.113.11', ports: [{fromPort: 80, toPort: 80, protocol: 'tcp'}]},
|
|
hardware: {disks: [{name: `${name}-root`, sizeInGb: 20, isSystemDisk: true, state: 'in-use'}]},
|
|
location: {availabilityZone: 'us-east-1a'},
|
|
}
|
|
}
|
|
|
|
describe('AwsLightsailAdapter', () => {
|
|
test('maps Lightsail instances to Cloud Explorer resources', async () => {
|
|
const [resource] = await new AwsLightsailAdapter(stubLightsail().client).list()
|
|
expect(resource).toMatchObject({id: 'web', service: 'lightsail', status: 'running', region: 'us-east-1a'})
|
|
expect(resource?.metadata.publicIpAddress).toBe('203.0.113.10')
|
|
expect(resource?.metadata).toMatchObject({privateIpAddress: '10.0.0.10', networking: {staticIp: '203.0.113.11'}, hardware: {disks: [{name: 'web-root'}]}})
|
|
})
|
|
|
|
test('merges diagnostic host-port mappings into UI metadata', async () => {
|
|
process.env.FLOCI_ENDPOINT = 'http://core.test:4566'
|
|
const fetchMock = globalThis.fetch
|
|
globalThis.fetch = (async () => new Response(JSON.stringify({mappings: [
|
|
{instancePort: 80, host: 'localhost', hostPort: 18080, protocol: 'tcp'},
|
|
]}))) as unknown as typeof fetch
|
|
try {
|
|
const resource = await new AwsLightsailAdapter(stubLightsail().client).get('web')
|
|
expect(resource?.metadata.hostPortMappings).toEqual([
|
|
{instancePort: 80, host: 'localhost', hostPort: 18080, protocol: 'tcp'},
|
|
])
|
|
} finally {
|
|
globalThis.fetch = fetchMock
|
|
}
|
|
})
|
|
|
|
test('uses Lightsail CreateInstances request fields', async () => {
|
|
const stub = stubLightsail()
|
|
await new AwsLightsailAdapter(stub.client).create({values: {
|
|
name: 'web', blueprintId: 'ubuntu_22_04', bundleId: 'nano_3_0', availabilityZone: 'us-east-1a',
|
|
}})
|
|
expect(stub.sent.find((command) => command instanceof CreateInstancesCommand))
|
|
.toMatchObject({input: {
|
|
instanceNames: ['web'], blueprintId: 'ubuntu_22_04', bundleId: 'nano_3_0', availabilityZone: 'us-east-1a',
|
|
}})
|
|
})
|
|
|
|
test('deletes instances by name', async () => {
|
|
const stub = stubLightsail()
|
|
await new AwsLightsailAdapter(stub.client).delete('web')
|
|
expect(stub.sent.find((command) => command instanceof DeleteInstanceCommand))
|
|
.toMatchObject({input: {instanceName: 'web'}})
|
|
})
|
|
|
|
test('uses Lightsail lifecycle commands', async () => {
|
|
const stub = stubLightsail()
|
|
const adapter = new AwsLightsailAdapter(stub.client)
|
|
await adapter.start('web')
|
|
await adapter.stop('web')
|
|
await adapter.reboot('web')
|
|
expect(stub.sent.find((command) => command instanceof StartInstanceCommand)).toMatchObject({input: {instanceName: 'web'}})
|
|
expect(stub.sent.find((command) => command instanceof StopInstanceCommand)).toMatchObject({input: {instanceName: 'web'}})
|
|
expect(stub.sent.find((command) => command instanceof RebootInstanceCommand)).toMatchObject({input: {instanceName: 'web'}})
|
|
})
|
|
|
|
test('opens and closes public ports with the Lightsail port contract', async () => {
|
|
const stub = stubLightsail()
|
|
const adapter = new AwsLightsailAdapter(stub.client)
|
|
await adapter.update('web', {values: {action: 'openPort', fromPort: 8080, toPort: 8080, protocol: 'tcp'}})
|
|
await adapter.update('web', {values: {action: 'closePort', fromPort: 8080, toPort: 8080, protocol: 'tcp'}})
|
|
expect(stub.sent.find((command) => command instanceof OpenInstancePublicPortsCommand)).toMatchObject({input: {instanceName: 'web', portInfo: {fromPort: 8080, toPort: 8080, protocol: 'tcp'}}})
|
|
expect(stub.sent.find((command) => command instanceof CloseInstancePublicPortsCommand)).toMatchObject({input: {instanceName: 'web', portInfo: {fromPort: 8080, toPort: 8080, protocol: 'tcp'}}})
|
|
})
|
|
})
|