-
Notifications
You must be signed in to change notification settings - Fork 1
feat: DB v2 test default db #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
7b8bac4
396e648
b295e28
35bc5cb
19c3ece
ce83def
292b549
d4120ce
b09a6c0
53061fe
c32427b
cb12a13
784af7f
4df9363
b439523
0195797
2d399cf
b17a54f
def9885
9cc3856
bb298bc
6af2d1b
950fe1a
ff389f9
817f100
0605888
15927fe
f72366f
3b4d3e5
ef9fea4
c826e12
20a59e3
3648874
3bba784
3602506
7822894
3107de3
e0cae9b
117e798
7c2b479
06fe2d8
17f5e9e
f491332
9056cf8
75308bc
3ba47f5
6b0648f
65f030a
bfec1fc
a48d054
379dc30
14d208b
c629546
6906eb4
8f5939e
80804be
98fb66b
5cfb8f9
823598e
9d7d045
1937146
311d792
b43859c
62b03d9
e8a017b
f9fdc02
6467dff
3375e86
dce0103
a783195
41783a5
54ca753
b70eb78
b3e2bc8
dd0efc7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,198 @@ | ||
| import { | ||
| DescribeKeyCommand, | ||
| GetKeyRotationStatusCommand, | ||
| } from '@aws-sdk/client-kms'; | ||
| import { | ||
| DescribeSecurityGroupsCommand, | ||
| IpPermission, | ||
| } from '@aws-sdk/client-ec2'; | ||
| import * as assert from 'node:assert'; | ||
| import { DatabaseTestContext } from './test-context'; | ||
| import { DescribeDBSubnetGroupsCommand } from '@aws-sdk/client-rds'; | ||
| import { it } from 'node:test'; | ||
|
|
||
| export function testDefaultDb(ctx: DatabaseTestContext) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Name of this suite is confusing to me. I would just put these tests as part of |
||
| it('should create a database and all other resources', () => { | ||
| const database = ctx.outputs.defaultDb.value; | ||
|
|
||
| assert.ok(database, 'Database should be defined'); | ||
| assert.strictEqual( | ||
| database.name, | ||
| `${ctx.config.appName}-default`, | ||
| 'Database should have correct name', | ||
| ); | ||
|
|
||
| assert.ok(database.instance, 'Db instance should be defined'); | ||
| assert.ok(database.dbSecurityGroup, 'Db security group should be defined'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Split into separate tests. |
||
| assert.ok(database.dbSubnetGroup, 'Db subnet group should be defined'); | ||
| assert.ok(database.kmsKeyId, 'Kms key id should be defined'); | ||
| assert.ok(database.password, 'Password should be defined'); | ||
| }); | ||
|
|
||
| it('should create database instance with correct default configuration', () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Too many asserts for one test. Ideally, one assertion per test.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or alternatively, just use |
||
| const instance = ctx.outputs.defaultDb.value.instance; | ||
|
|
||
| assert.strictEqual( | ||
| instance.dbName, | ||
| ctx.config.dbName, | ||
| 'Database instance should have correct dbName', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.masterUsername, | ||
| ctx.config.dbUsername, | ||
| 'Database instance should have correct master username', | ||
| ); | ||
|
|
||
| assert.strictEqual( | ||
| instance.multiAz, | ||
| false, | ||
| 'Multi-AZ argument should be set to false', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.applyImmediately, | ||
| false, | ||
| 'Apply immediately argument should be set to false', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.allocatedStorage, | ||
| '20', | ||
| 'Allocated storage argument should be set to 20', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.maxAllocatedStorage, | ||
| 100, | ||
| 'Max allocated storage argument should be set to 100', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.dbInstanceClass, | ||
| 'db.t4g.micro', | ||
| 'DB instance class argument should be set to db.t4g.micro', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.enablePerformanceInsights, | ||
| false, | ||
| 'Enable performance insights argument should be set to false', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.allowMajorVersionUpgrade, | ||
| false, | ||
| 'Allow major version upgrade argument should be set to false', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.autoMinorVersionUpgrade, | ||
| true, | ||
| 'Auto minor version upgrade argument should be set to true', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.engineVersion, | ||
| '17.2', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we could export defaults and assert those values directly here like we did for example in redis tests?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like to use config for the thing I'm testing 🤔
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't do as suggested, as it is not considered a good practice, and it can give false negatives. Just keep it as is. |
||
| 'Engine version argument should be set to 17.2', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.engine, | ||
| 'postgres', | ||
| 'Engine argument should be set to postgres', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.storageEncrypted, | ||
| true, | ||
| 'Storage encrypted argument should be set to true', | ||
| ); | ||
| assert.strictEqual( | ||
| instance.publiclyAccessible, | ||
| false, | ||
| 'Publicly accessible argument should be set to false', | ||
| ); | ||
| }); | ||
|
|
||
| it('should create subnet group in the correct VPC', async () => { | ||
| const database = ctx.outputs.defaultDb.value; | ||
| const vpc = ctx.outputs.vpc.value; | ||
| const dbSubnetGroupName = database.dbSubnetGroup.name; | ||
|
|
||
| const command = new DescribeDBSubnetGroupsCommand({ | ||
| DBSubnetGroupName: dbSubnetGroupName, | ||
| }); | ||
|
|
||
| const { DBSubnetGroups } = await ctx.clients.rds.send(command); | ||
| assert.ok( | ||
| DBSubnetGroups && DBSubnetGroups.length > 0, | ||
| 'DB subnet groups should exist', | ||
| ); | ||
| const [subnetGroup] = DBSubnetGroups; | ||
| assert.strictEqual( | ||
| subnetGroup.VpcId, | ||
| vpc.vpc.vpcId, | ||
| 'DB subnet group should be in the correct VPC', | ||
| ); | ||
| assert.ok( | ||
| subnetGroup.Subnets && subnetGroup.Subnets.length > 0, | ||
| 'DB subnet group should have subnets', | ||
| ); | ||
| }); | ||
|
|
||
| it('should create a security group with correct ingress rules', async () => { | ||
| const database = ctx.outputs.defaultDb.value; | ||
| const vpc = ctx.outputs.vpc.value; | ||
| const dbSecurityGroupId = database.dbSecurityGroup.id; | ||
|
|
||
| const command = new DescribeSecurityGroupsCommand({ | ||
| GroupIds: [dbSecurityGroupId], | ||
| }); | ||
| const { SecurityGroups } = await ctx.clients.ec2.send(command); | ||
| assert.ok( | ||
| SecurityGroups && SecurityGroups.length > 0, | ||
| 'DB security groups should exist', | ||
| ); | ||
| const [securityGroup] = SecurityGroups; | ||
| assert.strictEqual( | ||
| securityGroup.VpcId, | ||
| vpc.vpc.vpcId, | ||
| 'DB security group should be in the correct VPC', | ||
| ); | ||
|
|
||
| const postgresRule = securityGroup.IpPermissions?.find( | ||
| (rule: IpPermission) => rule.FromPort === 5432 && rule.ToPort === 5432, | ||
| ); | ||
| assert.ok(postgresRule, 'Should have postgres port 5432 ingress rule'); | ||
| assert.strictEqual( | ||
| postgresRule.IpProtocol, | ||
| 'tcp', | ||
| 'Should allow TCP protocol', | ||
| ); | ||
| }); | ||
|
|
||
| it('should create a correctly configured RDS KMS key', async () => { | ||
| const database = ctx.outputs.defaultDb.value; | ||
| const kmsKeyId = database.kmsKeyId; | ||
|
|
||
| const describeCommand = new DescribeKeyCommand({ | ||
| KeyId: kmsKeyId, | ||
| }); | ||
| const { KeyMetadata } = await ctx.clients.kms.send(describeCommand); | ||
| assert.strictEqual( | ||
| KeyMetadata?.KeySpec, | ||
| 'SYMMETRIC_DEFAULT', | ||
| 'KMS key should use SYMMETRIC_DEFAULT spec', | ||
| ); | ||
| assert.strictEqual( | ||
| KeyMetadata.KeyUsage, | ||
| 'ENCRYPT_DECRYPT', | ||
| 'KMS key should be used for encryption/decryption', | ||
| ); | ||
| assert.strictEqual(KeyMetadata.Enabled, true, 'KMS key should be enabled'); | ||
| assert.strictEqual( | ||
| KeyMetadata.MultiRegion, | ||
| false, | ||
| 'KMS key should not be multi-region', | ||
| ); | ||
|
|
||
| const rotationCmd = new GetKeyRotationStatusCommand({ KeyId: kmsKeyId }); | ||
| const { KeyRotationEnabled } = await ctx.clients.kms.send(rotationCmd); | ||
| assert.strictEqual( | ||
| KeyRotationEnabled, | ||
| true, | ||
| 'KMS key rotation should be enabled', | ||
| ); | ||
| }); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import { describe, before, after } from 'node:test'; | ||
| import * as automation from '../automation'; | ||
| import { cleanupSnapshots } from './utils/cleanup-snapshots'; | ||
| import * as config from './infrastructure/config'; | ||
| import { DatabaseTestContext } from './test-context'; | ||
| import { EC2Client } from '@aws-sdk/client-ec2'; | ||
| import { InlineProgramArgs } from '@pulumi/pulumi/automation'; | ||
| import { KMSClient } from '@aws-sdk/client-kms'; | ||
| import { RDSClient } from '@aws-sdk/client-rds'; | ||
| import { requireEnv } from '../util'; | ||
| import { testDefaultDb } from './default-db.test'; | ||
|
|
||
| const programArgs: InlineProgramArgs = { | ||
| stackName: 'dev', | ||
| projectName: 'icb-test-database', | ||
| program: () => import('./infrastructure'), | ||
| }; | ||
|
|
||
| const region = requireEnv('AWS_REGION'); | ||
| const ctx: DatabaseTestContext = { | ||
| outputs: {}, | ||
| config, | ||
| clients: { | ||
| rds: new RDSClient({ region }), | ||
| ec2: new EC2Client({ region }), | ||
| kms: new KMSClient({ region }), | ||
| }, | ||
| }; | ||
|
|
||
| describe('Database component deployment', () => { | ||
| before(async () => { | ||
| ctx.outputs = await automation.deploy(programArgs); | ||
| }); | ||
|
|
||
| after(async () => { | ||
| await automation.destroy(programArgs); | ||
| await cleanupSnapshots(ctx); | ||
| }); | ||
|
|
||
| describe('Default database', () => testDefaultDb(ctx)); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export const appName = 'db-test'; | ||
| export const dbName = 'dbname'; | ||
| export const dbUsername = 'dbusername'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { appName, dbName, dbUsername } from './config'; | ||
| import { next as studion } from '@studion/infra-code-blocks'; | ||
| import { DatabaseBuilder } from '../../../dist/v2/components/database/builder'; | ||
mandryllo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const vpc = new studion.Vpc(`${appName}-vpc`, {}); | ||
|
|
||
| const defaultDb = new DatabaseBuilder(`${appName}-default`) | ||
| .withInstance({ | ||
| dbName, | ||
| }) | ||
| .withCredentials({ | ||
| username: dbUsername, | ||
| }) | ||
| .withVpc(vpc.vpc) | ||
| .build(); | ||
|
|
||
| export { vpc, defaultDb }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing connection to db is not possible due to isolated subnets placement. But we should definitely use the SDK and check if actual db is created.