david-streamlio opened a new pull request, #77:
URL: https://github.com/apache/pulsar-connectors/pull/77

   Fixes #50
   
   ### Motivation
   
   The `dynamodb` module previously had only `DynamoDBSourceConfigTest`, which 
covers config parsing. The actual source logic — `DynamoDBSource` reading from 
a DynamoDB Stream via the KCL DynamoDB Streams adapter — was entirely untested. 
This adds a Testcontainers/LocalStack integration test that exercises the full 
path from a stream-enabled DynamoDB table into the source's record queue.
   
   While wiring the test I hit a genuine bug in `DynamoDBSourceConfig`: all 
three client builders (`buildDynamoDBStreamsClient`, `buildDynamoDBClient`, 
`buildCloudwatchClient`) set **both** an `EndpointConfiguration` and a `Region` 
on the AWS SDK v1 builder. The SDK rejects that with `IllegalStateException: 
Only one of Region or EndpointConfiguration may be set`. Since `open()` 
mandates `awsRegion`, the endpoint-override path — the only way to target 
LocalStack (or any non-default endpoint) — was unusable. This bug had never 
surfaced because production usage leaves the endpoint empty.
   
   ### Modifications
   
   - `DynamoDBSourceConfig`: make endpoint configuration and region mutually 
exclusive (`else if`). The `EndpointConfiguration` already carries the signing 
region, so the region is applied only when no endpoint is set. The DynamoDB and 
CloudWatch builders now gate on their own endpoint fields (`dynamoEndpoint` / 
`cloudwatchEndpoint`) rather than `awsEndpoint`, which was a latent 
inconsistency (they checked `awsEndpoint` but applied a different field).
   - `dynamodb/build.gradle.kts`: add `testImplementation` for 
`testcontainers-localstack` and `awaitility`.
   - New `DynamoDBSourceIntegrationTest`:
     - Starts `LocalStackContainer` (`localstack/localstack:4.0.3`) with 
DynamoDB and CloudWatch (the KCL uses DynamoDB for its lease table and 
CloudWatch for metrics).
     - Creates a table with `StreamSpecification` enabled 
(`NEW_AND_OLD_IMAGES`), waits for `ACTIVE`, reads its `LatestStreamArn`.
     - Seeds items, opens `DynamoDBSource` with `TRIM_HORIZON` (plus a 
background writer for a steady supply), and asserts the source emits records 
carrying an event id and `EVENT_NAME` property.
     - `read()` blocks forever on an empty queue, so records are read on a 
bounded worker thread with a per-record deadline (never inside an Awaitility 
block). The test is bounded by `@Test(timeOut = 600_000)`.
   
   ### Verifying this change
   
   Run locally against Docker: `./gradlew :dynamodb:test`
   
   ```
   Gradle suite > Gradle test > 
org.apache.pulsar.io.dynamodb.DynamoDBSourceConfigTest > 
loadFromMapCredentialFromSecretTest PASSED
   Gradle suite > Gradle test > 
org.apache.pulsar.io.dynamodb.DynamoDBSourceConfigTest > loadFromMapTest PASSED
   Gradle suite > Gradle test > 
org.apache.pulsar.io.dynamodb.DynamoDBSourceConfigTest > loadFromYamlFileTest 
PASSED
   Gradle suite > Gradle test > 
org.apache.pulsar.io.dynamodb.DynamoDBSourceConfigTest > missingCredentialsTest 
PASSED
   Gradle suite > Gradle test > 
org.apache.pulsar.io.dynamodb.DynamoDBSourceConfigTest > missingStartTimeTest 
PASSED
   Gradle suite > Gradle test > 
org.apache.pulsar.io.dynamodb.DynamoDBSourceIntegrationTest > 
testReadFromDynamoDBStream PASSED
   
   BUILD SUCCESSFUL
   ```
   
   **Mutation check (proving the test is not vacuous):** with the live writer 
disabled and the source pointed at an empty/bogus stream ARN (and the read 
deadline temporarily shortened to 90s), the test fails instead of passing or 
hanging:
   
   ```
   Gradle suite > Gradle test > 
org.apache.pulsar.io.dynamodb.DynamoDBSourceIntegrationTest > 
testReadFromDynamoDBStream FAILED
       java.lang.AssertionError: Timed out after 90s waiting for a record from 
the DynamoDB stream. The source produced no record; see the KCL/worker logs 
above.
   
   BUILD FAILED
   ```
   
   The mutation was then reverted and `./gradlew :dynamodb:test --rerun-tasks` 
was re-run to confirm green. `./gradlew :dynamodb:spotlessCheck` also passes.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to