Skip to content

Commit 6248a86

Browse files
committed
test(lambda): prove every projection matches its contract schema
Reading code confirmed the projections and schemas agree, but nothing ran them against each other. This runs all eight shared mappers against their schemas in both directions: every declared key is emitted and non-undefined, no undeclared key is emitted, and the result parses — for an empty AWS response, which is the common case, and for a fully-populated one. Verified the suite fails when either defect class is reintroduced: a mapper that stops emitting a declared key, and a projection that leaks `undefined` where the schema declares a value.
1 parent 0418829 commit 6248a86

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/**
2+
* @vitest-environment node
3+
*
4+
* Proves every shared response projection produces a shape its contract schema accepts, in
5+
* both the all-absent and fully-populated directions. This is the drift that reading code
6+
* misses: a mapper that emits `undefined` where the schema declares a non-nullable field, or
7+
* a schema field the mapper never emits, only shows up when the two are run against each other.
8+
*/
9+
import { describe, expect, it } from 'vitest'
10+
import {
11+
lambdaAliasSchema,
12+
lambdaEventInvokeConfigSchema,
13+
lambdaEventSourceMappingSchema,
14+
lambdaFunctionConfigurationSchema,
15+
lambdaFunctionUrlConfigSchema,
16+
lambdaLayerSchema,
17+
lambdaLayerVersionSchema,
18+
lambdaProvisionedConcurrencySchema,
19+
} from '@/lib/api/contracts/tools/aws/lambda-shared'
20+
import {
21+
mapAliasConfiguration,
22+
mapEventInvokeConfig,
23+
mapEventSourceMapping,
24+
mapFunctionConfiguration,
25+
mapFunctionUrlConfig,
26+
mapLayer,
27+
mapLayerVersion,
28+
mapProvisionedConcurrency,
29+
} from '@/lib/internal/lambda/client'
30+
31+
/** AWS omits most optional fields, so the empty response is the common real-world case. */
32+
const EMPTY_CASES = [
33+
['functionConfiguration', lambdaFunctionConfigurationSchema, () => mapFunctionConfiguration({})],
34+
['alias', lambdaAliasSchema, () => mapAliasConfiguration({})],
35+
['eventSourceMapping', lambdaEventSourceMappingSchema, () => mapEventSourceMapping({})],
36+
['eventInvokeConfig', lambdaEventInvokeConfigSchema, () => mapEventInvokeConfig({})],
37+
[
38+
'provisionedConcurrency',
39+
lambdaProvisionedConcurrencySchema,
40+
() => mapProvisionedConcurrency({}),
41+
],
42+
['layerVersion', lambdaLayerVersionSchema, () => mapLayerVersion({})],
43+
['layer', lambdaLayerSchema, () => mapLayer({})],
44+
[
45+
'functionUrlConfig',
46+
lambdaFunctionUrlConfigSchema,
47+
() =>
48+
mapFunctionUrlConfig({
49+
FunctionUrl: undefined,
50+
FunctionArn: undefined,
51+
AuthType: undefined,
52+
CreationTime: undefined,
53+
}),
54+
],
55+
] as const
56+
57+
describe('shared projections satisfy their contract schemas', () => {
58+
it.each(EMPTY_CASES)('%s maps an empty AWS response to a valid shape', (_name, schema, map) => {
59+
const parsed = schema.safeParse(map())
60+
61+
expect(parsed.error?.issues ?? []).toEqual([])
62+
expect(parsed.success).toBe(true)
63+
})
64+
65+
it.each(EMPTY_CASES)('%s emits every key its schema declares', (_name, schema, map) => {
66+
const projected = map() as Record<string, unknown>
67+
68+
for (const key of Object.keys(schema.shape)) {
69+
expect(projected, `missing projected key: ${key}`).toHaveProperty(key)
70+
expect(projected[key], `${key} must not be undefined`).not.toBeUndefined()
71+
}
72+
})
73+
74+
it.each(EMPTY_CASES)('%s emits no key its schema does not declare', (_name, schema, map) => {
75+
const declared = new Set(Object.keys(schema.shape))
76+
77+
for (const key of Object.keys(map() as Record<string, unknown>)) {
78+
expect(declared.has(key), `undeclared projected key: ${key}`).toBe(true)
79+
}
80+
})
81+
82+
it('accepts a fully-populated function configuration', () => {
83+
const parsed = lambdaFunctionConfigurationSchema.safeParse(
84+
mapFunctionConfiguration({
85+
FunctionName: 'alpha',
86+
Architectures: ['arm64'],
87+
EphemeralStorage: { Size: 512 },
88+
FileSystemConfigs: [{ Arn: 'arn:efs:1', LocalMountPath: '/mnt/data' }],
89+
Layers: [{ Arn: 'arn:layer:1' }],
90+
VpcConfig: { SubnetIds: ['subnet-1'], SecurityGroupIds: ['sg-1'] },
91+
Environment: { Variables: { STAGE: 'prod' } },
92+
ImageConfigResponse: { ImageConfig: { Command: ['app.handler'] } },
93+
SnapStart: { ApplyOn: 'PublishedVersions' },
94+
RuntimeVersionConfig: { RuntimeVersionArn: 'arn:runtime:1' },
95+
LoggingConfig: { LogFormat: 'JSON' },
96+
CapacityProviderConfig: {
97+
LambdaManagedInstancesCapacityProviderConfig: { CapacityProviderArn: 'arn:cp:1' },
98+
},
99+
DurableConfig: { RetentionPeriodInDays: 7 },
100+
TenancyConfig: { TenantIsolationMode: 'PER_TENANT' },
101+
})
102+
)
103+
104+
expect(parsed.error?.issues ?? []).toEqual([])
105+
})
106+
107+
it('accepts a file system config whose fields AWS omitted', () => {
108+
const parsed = lambdaFunctionConfigurationSchema.safeParse(
109+
mapFunctionConfiguration({ FileSystemConfigs: [{}] })
110+
)
111+
112+
expect(parsed.error?.issues ?? []).toEqual([])
113+
})
114+
115+
it('accepts a fully-populated event source mapping, including the Kafka endpoints', () => {
116+
const projected = mapEventSourceMapping({
117+
UUID: 'esm-1',
118+
LastModified: new Date('2026-01-02T03:04:05Z'),
119+
StartingPositionTimestamp: new Date('2026-01-01T00:00:00Z'),
120+
ScalingConfig: { MaximumConcurrency: 20 },
121+
LoggingConfig: { SystemLogLevel: 'DEBUG' },
122+
MetricsConfig: { Metrics: ['EventCount'] },
123+
FilterCriteria: { Filters: [{ Pattern: '{"a":1}' }] },
124+
DestinationConfig: { OnFailure: { Destination: 'arn:sqs:fail' } },
125+
SourceAccessConfigurations: [{ Type: 'BASIC_AUTH', URI: 'arn:secret:1' }],
126+
SelfManagedEventSource: { Endpoints: { KAFKA_BOOTSTRAP_SERVERS: ['broker-1:9092'] } },
127+
DocumentDBEventSourceConfig: { DatabaseName: 'db' },
128+
ProvisionedPollerConfig: { MinimumPollers: 1 },
129+
})
130+
131+
expect(projected.selfManagedKafkaBootstrapServers).toEqual(['broker-1:9092'])
132+
expect(lambdaEventSourceMappingSchema.safeParse(projected).error?.issues ?? []).toEqual([])
133+
})
134+
})

0 commit comments

Comments
 (0)