diff --git a/.kiro/steering/async-programming-guidelines.md b/.kiro/steering/async-programming-guidelines.md new file mode 100644 index 00000000000..0b17d4a1063 --- /dev/null +++ b/.kiro/steering/async-programming-guidelines.md @@ -0,0 +1,133 @@ +--- +title: Asynchronous Programming Guidelines for AWS SDK v2 +inclusion: fileMatch +fileMatchPattern: "**/*.java" +--- + +# Asynchronous Programming Guidelines for AWS SDK v2 + +## Use of CompletableFuture + +### Best Practices for CompletableFuture + +- **Read the documentation**: Always read the [CompletionStage Javadocs](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html) to understand the nuances of CompletableFuture +- **Prefer Non-Blocking Methods for Getting Results**: + +```java + // Avoid when possible - blocks the current thread + String result = future.get(); + + // Better - use callbacks + future.thenAccept(result -> processResult(result)); +``` +- **Add stacktrace to exceptions**: When using `CompletableFuture#join`, use `CompletableFutureUtils#joinLikeSync` to preserve stacktraces +- **Don't ignore results**: Never ignore the result of a new `CompletionStage` if the parent stage can fail (unless you're absolutely sure it's safe to) +- **Don't make thread assumptions**: Never make assumptions about which thread completes the future + - CompletableFuture callbacks may execute on: + - The thread that completed the future + - A thread from the common ForkJoinPool (for async methods without explicit executor) + - A thread from a provided executor + - Thread behavior can vary based on: + - Whether the future is already completed when a callback is added + - Whether an async or non-async method is used (e.g., `thenApply` vs `thenApplyAsync`) + - The specific JVM implementation and platform + - Always ensure thread safety when: + - Accessing shared state in callbacks + - Modifying UI components (use the appropriate UI thread) + - Working with thread-affinity resources like ThreadLocals + - Example of incorrect assumption: + ```java + // INCORRECT: Assuming the callback runs on a specific thread + ThreadLocal contextHolder = new ThreadLocal<>(); + + public void processAsync(CompletableFuture responseFuture) { + Context context = new Context(); + contextHolder.set(context); // Set in current thread + + responseFuture.thenApply(response -> { + // WRONG: Assuming contextHolder still has the context + Context ctx = contextHolder.get(); // May be null if running on different thread! + return processWithContext(response, ctx); + }); + } + ``` + - Correct approach: + ```java + // CORRECT: Explicitly passing context to callback + public void processAsync(CompletableFuture responseFuture) { + Context context = new Context(); + + responseFuture.thenApply(response -> { + // Explicitly use the context passed from the outer scope + return processWithContext(response, context); + }); + } + ``` +- **Always provide custom executors**: Don't use `CompletableFuture#xxAsync` methods (like `runAsync` or `thenComposeAsync`) without providing a custom executor, as the default `ForkJoinPool.commonPool()` behavior can vary by platform +- **Handle cancellation properly**: CompletableFuture does not support automatic cancellation propagation, so use `CompletableFutureUtils#forwardExceptionTo` to manually propagate cancellation +- **Avoid chaining multiple API calls**: This can lead to cancellation issues without proper handling +- **Avoid blocking operations**: Never use `get()` or `join()` inside a CompletableFuture chain as it defeats the purpose of asynchronous execution +- **Handle exceptions properly**: Always include exception handling with `exceptionally()` or `handle()` methods +```java + CompletableFuture.supplyAsync(() -> fetchData()) + .exceptionally(ex -> { + logger.error("Error processing data", ex); + return fallbackData(); + }, executor); +``` +- **Use appropriate completion methods**: + - thenApply() - when transforming a result + - thenAccept() - when consuming a result without returning anything + - thenRun() - when executing code regardless of the result + - thenCompose() - when the next step returns a CompletableFuture +- **Test asynchronous code properly**: + - Use `CompletableFuture.join()` in tests to wait for completion + - Set appropriate timeouts for tests + +## Reactive Streams Implementation + +The AWS SDK for Java v2 uses Reactive Streams for asynchronous, non-blocking data processing with backpressure support. All implementations must adhere to the following requirements: + +### Compliance Requirements + +- All implementations **MUST** fully comply with the [Reactive Streams Specification](https://github.com/reactive-streams/reactive-streams-jvm) +- All implementations **MUST** pass the [Reactive Streams Technology Compatibility Kit (TCK)](https://github.com/reactive-streams/reactive-streams-jvm/tree/master/tck) tests +- Any code changes to Reactive Streams implementations **MUST** include TCK verification tests + +### Implementation Guidelines + +- Publishers **MUST** respect backpressure signals from subscribers +- Publishers **MUST** properly propagate cancellation signals +- Publishers **MUST** properly handle and propagate errors +- Subscribers **MUST** handle onNext, onError, and onComplete signals appropriately +- Subscribers **MUST** send appropriate request(n) signals to maintain backpressure +- Processors **MUST** maintain all Publisher and Subscriber contracts +- Developers **SHOULD NOT** implement new Publisher or Subscriber interfaces from scratch +- Developers **SHOULD** utilize existing utility classes such as: + - `SimplePublisher` - A simple implementation of the Publisher interface + - `ByteBufferStoringSubscriber` - A subscriber that stores received ByteBuffers + - Methods in `SdkPublisher` - Utility methods for common Publisher operations + +### Common Patterns + +- Use `SdkPublisher` for SDK-specific publisher implementations +- Implement proper resource cleanup in both success and failure scenarios +- Handle cancellation gracefully, including cleanup of any allocated resources +- Ensure thread safety in all implementations +- Document thread safety characteristics and any assumptions about execution context + +### Testing Requirements + +- All Reactive Streams implementations **MUST** include TCK verification tests +- Tests **SHOULD** cover both normal operation and edge cases: + - Cancellation during active streaming + - Error propagation + - Backpressure handling under various request scenarios + - Resource cleanup in all termination scenarios + +## References + +- [CompletableFuture JavaDoc](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) +- [CompletionStage JavaDoc](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html) +- [Reactive Streams Specification](https://github.com/reactive-streams/reactive-streams-jvm) +- [AWS SDK for Java Developer Guide - Async Programming](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/asynchronous.html) \ No newline at end of file diff --git a/.kiro/steering/aws-sdk-java-v2-general.md b/.kiro/steering/aws-sdk-java-v2-general.md new file mode 100644 index 00000000000..1047e007c4b --- /dev/null +++ b/.kiro/steering/aws-sdk-java-v2-general.md @@ -0,0 +1,162 @@ +--- +title: AWS SDK for Java v2 General Guidelines +inclusion: always +--- + +# AWS SDK for Java v2 General Guidelines + +## General Principles + +- Write clean, readable, and maintainable code +- Follow the SOLID principles of object-oriented design +- Favor composition over inheritance +- Program to interfaces, not implementations +- Fail fast - detect and report errors as soon as possible +- Maintain backward compatibility when modifying existing APIs + +## Code Style Standards + +- Follow Java coding conventions and the existing style in the codebase +- Use meaningful variable, method, and class names that clearly indicate purpose +- Include comprehensive Javadoc for public APIs +- Keep methods short and focused on a single responsibility +- Limit the number of method parameters (ideally 3 or fewer) +- Use appropriate access modifiers (private, protected, public) +- Follow consistent indentation and formatting + +## Common Design Patterns + +- Use builder pattern for object creation +- Follow reactive programming principles for async operations +- Use SdkException hierarchy for error handling +- Prefer immutable objects where appropriate + +## Naming Conventions + +### Class Naming + +#### General Rules +- Prefer singular class names: `SdkSystemSetting`, not `SdkSystemSettings` +- Treat acronyms as a single word: `DynamoDbClient`, not `DynamoDBClient` + +#### Classes that instantiate other classes + +- If the class's primary purpose is to return instances of another class: + - If the "get" method has no parameters: + - If the class implements `Supplier`: `{Noun}Supplier` (e.g. `CachedSupplier`) + - If the class does not implement `Supplier`: `{Noun}Provider` (e.g. `AwsCredentialsProvider`) + - If the "get" method has parameters: `{Noun}Factory` (e.g. `AwsJsonProtocolFactory`) + +#### Service-specific classes + +- If the class makes service calls: + - If the class can be used to invoke *every* data-plane operation: + - If the class is code generated: + - If the class uses sync HTTP: `{ServiceName}Client` (e.g. `DynamoDbClient`) + - If the class uses async HTTP: `{ServiceName}AsyncClient` (e.g. `DynamoDbAsyncClient`) + - If the class is hand-written: + - If the class uses sync HTTP: `{ServiceName}EnhancedClient` (e.g. `DynamoDbEnhancedClient`) + - If the class uses async HTTP: `{ServiceName}EnhancedAsyncClient` (e.g. `DynamoDbEnhancedAsyncClient`) + - If the class can be used to invoke only *some* data-plane operations: + - If the class uses sync HTTP: `{ServiceName}{Noun}Manager` (e.g. `SqsBatchManager`) + - If the class uses async HTTP: `{ServiceName}Async{Noun}Manager` (e.g. `SqsAsyncBatchManager`) + - Note: If only one implementation exists and it uses async HTTP, `Async` may be excluded. (e.g. `S3TransferManager`) +- If the class does not make service calls: + - If the class creates presigned URLs: `{ServiceName}Presigner` (e.g. `S3Presigner`) + - If the class is a collection of various unrelated "helper" methods: `{ServiceName}Utilities` (e.g. `S3Utilities`) + +## Class Initialization + +- Favor static factory methods over constructors: + - Static factory methods provide meaningful names compared with constructors + - They are useful when working with immutable classes as we can reuse the same object + - Static factory methods can return any subtype of that class + +### Naming Conventions for Static Factory Methods +- `create()`, `create(params)` when creating a new instance (e.g., `DynamoDBClient.create()`) +- `defaultXXX()` when returning an instance with default settings (e.g., `BackoffStrategy.defaultStrategy()`) + +## Use of Optional + +- `Optional` **MUST NOT** be used when the result will never be null +- For return types: + - `Optional` **SHOULD** be used when it is not obvious to a caller whether a result will be null + - `Optional` **MUST NOT** be used for "getters" in generated service model classes +- For member variables: `Optional` **SHOULD NOT** be used +- For method parameters: `Optional` **MUST NOT** be used + +## Object Methods (toString, equals, hashCode) + +- All public POJO classes **MUST** implement `toString()`, `equals()`, and `hashCode()` methods +- When adding new fields to existing POJO classes, these methods **MUST** be updated to include the new fields +- Implementation guidelines: + - `toString()`: Include class name and all fields with their values + - **MUST** use the SDK's `ToString` utility class (`utils/src/main/java/software/amazon/awssdk/utils/ToString.java`) for consistent formatting: + ```java + @Override + public String toString() { + return ToString.builder("YourClassName") + .add("fieldName1", fieldValue1) + .add("fieldName2", fieldValue2) + .build(); + } + ``` + - `equals()`: Compare all fields for equality, including proper null handling + - `hashCode()`: Include all fields in the hash code calculation +- Consider using IDE-generated implementations +- For immutable objects, consider caching the hash code value for better performance +- Unit tests **MUST** be added using EqualsVerifier to ensure all fields are properly included in equals and hashCode implementations. Example: + ```java + @Test + public void equalsHashCodeTest() { + EqualsVerifier.forClass(YourClass.class) + .withNonnullFields("requiredFields") + .verify(); + } + ``` + +## Exception Handling + +- Avoid throwing checked exceptions in public APIs +- Don't catch exceptions unless you can handle them properly +- Always include meaningful error messages +- Clean up resources in finally blocks or use try-with-resources +- Don't use exceptions for flow control + +## Use of Existing Utility Classes + +- Developers **MUST** check for existing utility methods before implementing their own +- Common utility classes are available in the `utils` module and **SHOULD** be used when applicable +- Examples of available utility classes: + - `Lazy` (`utils/src/main/java/software/amazon/awssdk/utils/Lazy.java`): For thread-safe lazy initialization of singleton objects + - `ToString` (`utils/src/main/java/software/amazon/awssdk/utils/ToString.java`): For consistent toString() implementations + - `IoUtils`: For safely closing resources and handling I/O operations + - `StringUtils`: For common string operations + - `CollectionUtils`: For common collection operations + - `ValidationUtils`: For input validation +- Using existing utilities ensures: + - Consistent behavior across the codebase + - Thread-safety where applicable + - Proper handling of edge cases + - Reduced code duplication +- Example of using `Lazy` for thread-safe singleton initialization: + ```java + private static final Lazy INSTANCE = new Lazy<>(() -> new ExpensiveObject()); + + public static ExpensiveObject getInstance() { + return INSTANCE.getValue(); + } + ``` + +## Performance + +- Avoid premature optimization +- Use appropriate data structures for the task +- Be mindful of memory usage, especially with large collections +- Consider thread safety in concurrent applications +- Use profiling tools to identify actual bottlenecks + +## References + +- [AWS SDK for Java Developer Guide](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html) +- [Design Documentation](https://github.com/aws/aws-sdk-java-v2/tree/master/docs/design) \ No newline at end of file diff --git a/.kiro/steering/aws-sdk-java-v2-guidelines.md b/.kiro/steering/aws-sdk-java-v2-guidelines.md new file mode 100644 index 00000000000..9867dcbfab4 --- /dev/null +++ b/.kiro/steering/aws-sdk-java-v2-guidelines.md @@ -0,0 +1,44 @@ +--- +title: AWS SDK for Java v2 Development Guidelines +inclusion: always +--- + +# AWS SDK for Java v2 Development Guidelines + +This document serves as an index to the AWS SDK for Java v2 development guidelines. The guidelines have been organized into separate, focused documents to make them more manageable and easier to reference. + +## Available Guidelines + +### [General Guidelines](aws-sdk-java-v2-general.md) +- General Principles +- Code Style Standards +- Common Design Patterns +- Naming Conventions +- Class Initialization +- Use of Optional +- Exception Handling +- Performance +- Documentation + +### [Asynchronous Programming Guidelines](async-programming-guidelines.md) +- Use of CompletableFuture +- Reactive Streams Implementation + +### [Testing Guidelines](testing-guidelines.md) +- General Testing Principles +- Test Naming Conventions +- Unit Testing Best Practices +- Testing Asynchronous Code + +### [Javadoc Guidelines](javadoc-guidelines.md) +- API Classification +- Documentation Requirements +- Style Guidelines +- Code Snippets +- Examples + +## References + +- [AWS SDK for Java Developer Guide](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html) +- [Design Documentation](https://github.com/aws/aws-sdk-java-v2/tree/master/docs/design) +- [Migration Guide](https://docs.aws.amazon.com/sdk-for-java/v2/migration-guide/what-is-java-migration.html) \ No newline at end of file diff --git a/.kiro/steering/javadoc-guidelines.md b/.kiro/steering/javadoc-guidelines.md new file mode 100644 index 00000000000..31adadf580d --- /dev/null +++ b/.kiro/steering/javadoc-guidelines.md @@ -0,0 +1,160 @@ +--- +title: Javadoc Guidelines for AWS SDK v2 +inclusion: fileMatch +fileMatchPattern: "**/*.java" +--- + +# Javadoc Guidelines for AWS SDK v2 + +## API Classification + +The AWS SDK for Java v2 uses annotations to classify APIs: + +- **SDK Public APIs**: Classes/interfaces annotated with `@SdkPublicApi` +- **SDK Protected APIs**: Classes/interfaces annotated with `@SdkProtectedApi` +- **SDK Internal APIs**: Classes/interfaces annotated with `@SdkInternalApi` + +## Documentation Requirements + +### Required Documentation + +- All SDK public APIs **MUST** have documentation +- All public methods in SDK public APIs **MUST** have documentation except: + - Methods that implement or override a method in an interface + - Methods that override a method in a superclass +- For SDK protected APIs and internal APIs, documentation is recommended but not required +- Javadocs for SDK public APIs in high-level libraries (e.g., DynamoDB Enhanced Client) **SHOULD** include code snippets + +## Style Guidelines + +### General Formatting + +- Javadoc **MUST** be properly formatted following the [Javadoc standard](https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html) +- A single `

` **MUST** be used at the beginning of paragraphs (except the first paragraph), with no closing tag, as shown in this example: + + ```java + /** + * First paragraph with no

tag. + * + *

Second paragraph starts with a

tag. + * + *

Third paragraph also starts with a

tag. + */ + ``` + +- First sentence should be a summary of the method/class purpose +- Use complete sentences with proper punctuation +- Use third person (e.g., "Returns the value" not "Return the value") + +### Javadoc Tags + +- Use `@param` to document all parameters with clear descriptions +- Use `@return` to document return values (except for void methods) +- Use `@throws` to specify exceptions that could be thrown from a method +- Use `@link` and `@see` tags to point to related methods/classes +- Use `@deprecated` tag for deprecated methods, including: + - When the method was deprecated + - Why it was deprecated + - The replacement method, linked using `{@link}` +- Avoid using `@version` and `@since` tags + +### Code Snippets + +- Use `@snippet` to add code snippets +- [External code snippets](https://docs.oracle.com/en/java/javase/18/code-snippet/index.html#external-snippets) **SHOULD** be favored over inline code snippets +- Code snippets should be: + - Concise and focused on demonstrating the API + - Compilable and correct + - Well-commented to explain key points + - Following the same code style as the rest of the codebase + +## Examples + +### Class Documentation Example + +```java +/** + * A high-level library for uploading and downloading objects to and from Amazon S3. + * This can be created using the static {@link #builder()} method. + * + *

S3TransferManager provides a simplified API for efficient transfers between a local environment + * and S3. It handles multipart uploads/downloads, concurrent transfers, progress tracking, and + * automatic retries. + * + *

See {@link S3TransferManagerBuilder} for information on configuring an S3TransferManager. + * + *

Example usage: + * {@snippet : + * S3TransferManager transferManager = S3TransferManager.builder() + * .s3ClientConfiguration(b -> b.credentialsProvider(credentialsProvider) + * .region(Region.US_WEST_2)) + * .build(); + * + * // Upload a file + * UploadFileRequest uploadRequest = UploadFileRequest.builder() + * .putObjectRequest(req -> req.bucket("bucket").key("key")) + * .source(Paths.get("file.txt")) + * .build(); + * + * FileUpload upload = transferManager.uploadFile(uploadRequest); + * CompletedFileUpload uploadResult = upload.completionFuture().join(); + * } + * + * @see S3TransferManagerBuilder + */ +@SdkPublicApi +public interface S3TransferManager extends SdkAutoCloseable { + // ... +} +``` + +### Method Documentation Example + +```java +/** + * Uploads a file from a specified path to an S3 bucket. + * + *

This method handles large files efficiently by using multipart uploads when appropriate. + * Progress can be tracked through the returned {@link FileUpload} object. + * + *

Example: + * {@snippet : + * UploadFileRequest request = UploadFileRequest.builder() + * .putObjectRequest(r -> r.bucket("bucket-name").key("key")) + * .source(Paths.get("my-file.txt")) + * .build(); + * + * FileUpload upload = transferManager.uploadFile(request); + * CompletedFileUpload completedUpload = upload.completionFuture().join(); + * } + * + * @param request Object containing the bucket, key, and file path for the upload + * @return A {@link FileUpload} object to track the upload and access the result + * @throws S3Exception If any errors occur during the S3 operation + * @throws SdkClientException If any client-side errors occur + * @throws IOException If the file cannot be read + */ +FileUpload uploadFile(UploadFileRequest request); +``` + +### Deprecated Method Example + +```java +/** + * Returns the value of the specified header. + * + *

This method provides direct access to the header value. + * + * @param name The name of the header + * @return The value of the specified header + * @deprecated Use {@link #firstMatchingHeader(String)} instead, as it properly handles + * headers with multiple values. + */ +@Deprecated +String header(String name); +``` + +## References + +- [Oracle Javadoc Guide](https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html) +- [AWS SDK for Java v2 API Reference Convention](https://github.com/aws/aws-sdk-java-v2/blob/master/docs/design/APIReference.md) \ No newline at end of file diff --git a/.kiro/steering/testing-guidelines.md b/.kiro/steering/testing-guidelines.md new file mode 100644 index 00000000000..3428025b23a --- /dev/null +++ b/.kiro/steering/testing-guidelines.md @@ -0,0 +1,186 @@ +--- +title: Testing Guidelines for AWS SDK v2 +inclusion: fileMatch +fileMatchPattern: "**/{test,it}/**/*.java" +--- + +# Testing Guidelines for AWS SDK v2 + +## General Guidelines + +- **Prefer JUnit 5** for new test classes +- **Prefer AssertJ** over Hamcrest for assertions +- Create dedicated test method for each test scenario +- Prefer parameterized tests for testing multiple similar cases +- Test names **SHOULD** follow `methodToTest_when_expectedBehavior` or `given_when_then` pattern +- When testing a module with dependencies, creating a constructor for dependency injection is preferred over exposing getter/setter APIs just for testing +- Test-only methods/constructors **MUST NOT** be public +- While test coverage is not a strict requirement, we **SHOULD** aim to cover 80% of the code + +## Test Naming Conventions + +Test names **SHOULD** follow `methodToTest_when_expectedBehavior` pattern: + +- Example: `close_withCustomExecutor_shouldNotCloseCustomExecutor` +- Example: `uploadDirectory_withDelimiter_filesSentCorrectly` + +This naming convention makes it clear: +1. What method is being tested +2. Under what conditions it's being tested +3. What behavior is expected + +## Unit Testing Best Practices + +- Each test should focus on a single behavior or aspect +- Use descriptive test names that explain the test's purpose +- Arrange-Act-Assert (AAA) pattern: + - Arrange: Set up the test data and conditions + - Act: Perform the action being tested + - Assert: Verify the expected outcome +- Use appropriate assertions for the specific condition being tested +- Avoid test interdependencies - tests should be able to run in any order +- Clean up resources in @After or @AfterEach methods +- Unit tests **MUST** be added using EqualsVerifier to ensure all fields are properly included in equals and hashCode implementations: + ```java + @Test + public void equalsHashCodeTest() { + EqualsVerifier.forClass(YourClass.class) + .withNonnullFields("requiredFields") + .verify(); + } + ``` +- See example implementation in `core/regions/src/test/java/software/amazon/awssdk/regions/PartitionEndpointKeyTest.java` + +## Mocking Guidelines + +- Mock external dependencies, not the class under test +- Only mock what you need to control for the test +- Prefer constructor injection to make dependencies mockable +- Use Mockito's verify() to ensure interactions with mocks are as expected +- Avoid excessive stubbing - it can make tests brittle and hard to maintain +- [Wiremock](https://wiremock.org/) is commonly used to mock server responses in functional tests + +## Testing Asynchronous Code + +- Use appropriate mechanisms to wait for async operations to complete +- Set reasonable timeouts to prevent tests from hanging +- For CompletableFuture: + - Use `join()` or `get()` with timeout in tests to wait for completion + - Test both successful completion and exceptional completion paths +- For Reactive Streams: + - Use StepVerifier or similar tools to test reactive flows + - Test backpressure handling + - Test cancellation scenarios + - Test error propagation + - For Publisher/Subscriber implementations, use TCK tests (see [Reactive Streams TCK Tests](#reactive-streams-tck-tests) section) + +## Test Suites + +### Unit Tests + +Unit tests verify the behaviors of an individual unit of source code. + +- **Goal**: Verify behaviors of a specific component and catch regressions +- **Location**: Under `src/test` directory in each module +- **When to add**: New unit tests **SHOULD** be added for any new changes +- **Naming Convention**: ClassNameTest, MethodNameTest +- **Test Automation**: Run for every PR and before release +- **Example**: [S3TransferManagerTest](https://github.com/aws/aws-sdk-java-v2/blob/master/services-custom/s3-transfer-manager/src/test/java/software/amazon/awssdk/transfer/s3/internal/S3TransferManagerTest.java) + +### Functional Tests + +Functional tests verify end-to-end behaviors and functionalities of an SDK feature. + +- **Goal**: Verify end-to-end behaviors of an SDK feature +- **Location**: + - Generated SDK common functionalities: In [codegen-generated-classes-test](https://github.com/aws/aws-sdk-java-v2/tree/master/test/codegen-generated-classes-test) module and [protocol-test](https://github.com/aws/aws-sdk-java-v2/tree/master/test/protocol-tests) module + - Service-specific functionalities: Under `src/test` directory in that service module + - High-level libraries (HLL): Under `src/test` directory in that HLL module +- **When to add**: Functional tests **SHOULD** be added for new SDK features or critical bug fixes +- **Naming Convention**: BehaviorTest, OperationTest +- **Test Automation**: Run for every PR and before release +- **Examples**: [WaitersSyncFunctionalTest](https://github.com/aws/aws-sdk-java-v2/blob/2532ec4f8ab36bab545689a2406d6a61d1696650/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/waiters/WaitersSyncFunctionalTest.java), [SelectObjectContentTest](https://github.com/aws/aws-sdk-java-v2/blob/master/services/s3/src/test/java/software/amazon/awssdk/services/s3/functionaltests/SelectObjectContentTest.java) + +### Reactive Streams TCK Tests + +[Reactive Streams TCK tests](https://github.com/reactive-streams/reactive-streams-jvm/tree/master/tck) verify Reactive Streams implementations against the rules defined in [the Reactive Streams Specification](https://github.com/reactive-streams/reactive-streams-jvm). + +- **Goal**: Ensure implementations are compliant with the spec +- **Location**: Under `src/test` directory in each module. The tests always have `TckTest` suffix +- **When to add**: New reactive streams TCK tests **MUST** be added when a new Subscriber/Publisher implementation is added +- **Naming Convention**: ClassNameTckTest +- **Test Automation**: Run for every PR and before release +- **Example**: [FileAsyncRequestPublisherTckTest](https://github.com/aws/aws-sdk-java-v2/blob/master/core/sdk-core/src/test/java/software/amazon/awssdk/core/async/FileAsyncRequestPublisherTckTest.java) + +### Integration Tests + +Integration tests verify end-to-end behaviors of the SDK with real AWS services. + +- **Goal**: Verify end-to-end behaviors of an SDK feature with real services +- **Location**: Under `src/it` directory in each module. The tests always have `IntegrationTest` suffix +- **When to add**: Integration tests **MAY** be added for new SDK features (functional tests are preferred) +- **Naming Convention**: ClassNameIntegrationTest, OperationIntegrationTest, BehaviorIntegrationTest +- **Important Notes**: Resources **MUST** be cleaned up after each test +- **Test Automation**: Run before release +- **Example**: [S3TransferManagerDownloadDirectoryIntegrationTest](https://github.com/aws/aws-sdk-java-v2/blob/master/services-custom/s3-transfer-manager/src/it/java/software/amazon/awssdk/transfer/s3/S3TransferManagerDownloadDirectoryIntegrationTest.java) + +### Stability Tests + +[Stability regression tests](https://github.com/aws/aws-sdk-java-v2/tree/master/test/stability-tests) detect stability regressions by sending high concurrent requests to AWS services. + +- **Goal**: Detect SDK errors in high-concurrency environment +- **Location**: Under `src/it` directory in `stability-tests` module. The tests always have `StabilityTest` suffix +- **When to add**: Stability tests **SHOULD** be added when a critical feature is being developed such as an HTTP Client +- **Naming Convention**: ClassNameStabilityTest +- **Test Automation**: Run before release +- **Example**: [KinesisStabilityTest](https://github.com/aws/aws-sdk-java-v2/blob/master/test/stability-tests/src/it/java/software/amazon/awssdk/stability/tests/kinesis/KinesisStabilityTest.java) + +### Long Running Canaries + +Long-running canaries continuously send requests to real or mock services at a constant rate, collecting resource usage, error rate, and latency metrics. + +- **Goal**: Detect resource leaks, latency increases, and performance issues +- **Location**: In a separate internal repository +- **When to add**: Canaries **SHOULD** be added when a critical feature is being developed such as an HTTP Client +- **Naming Convention**: FeatureTxnCreator +- **Test Automation**: Always running, deployed weekly + +### Performance Tests + +Performance tests are built using [Java Microbenchmark Harness (JMH)](https://github.com/openjdk/jmh) and measure throughput and latency. + +- **Goal**: Detect performance regression +- **Location**: In [sdk-benchmarks](https://github.com/aws/aws-sdk-java-v2/tree/master/test/sdk-benchmarks) module +- **When to add**: Benchmark code **SHOULD** be added for critical features or when verifying SDK performance impact +- **Naming Convention**: FeatureBenchmark +- **Test Automation**: No automation, manually triggered +- **Example**: [ApacheHttpClientBenchmark](https://github.com/aws/aws-sdk-java-v2/blob/master/test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/httpclient/sync/ApacheHttpClientBenchmark.java) + +### Protocol Tests + +Protocol tests verify SDK behavior with different [protocols](https://smithy.io/2.0/aws/protocols/index.html) including rest-json, rest-xml, json, xml, and query protocols. + +- **Goal**: Verify marshalling/unmarshalling with different protocols +- **Location**: In [protocol-tests](https://github.com/aws/aws-sdk-java-v2/tree/master/test/protocol-tests) module and [protocol-tests-core](https://github.com/aws/aws-sdk-java-v2/tree/master/test/protocol-tests-core) module +- **When to add**: Protocol tests **MUST** be added if we are adding support for a new structure +- **Naming Convention**: XmlProtocolTest +- **Test Automation**: Run for every PR and before release +- **Example**: [RestJsonProtocolTest](https://github.com/aws/aws-sdk-java-v2/blob/master/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/RestJsonProtocolTest.java) + +## Test Coverage + +- Aim for high test coverage, especially for critical paths +- Don't focus solely on line coverage - consider branch and path coverage +- Identify and test edge cases and boundary conditions +- Test error handling and exception paths +- While test coverage is not a strict requirement, we **SHOULD** aim to cover 80% of the code + +## References + +- [JUnit 5 User Guide](https://junit.org/junit5/docs/current/user-guide/) +- [AssertJ Documentation](https://assertj.github.io/doc/) +- [Mockito Documentation](https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html) +- [Wiremock Documentation](https://wiremock.org/) +- [AWS SDK for Java Developer Guide - Testing](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/testing.html) +- [Reactive Streams Specification](https://github.com/reactive-streams/reactive-streams-jvm) +- [Reactive Streams TCK](https://github.com/reactive-streams/reactive-streams-jvm/tree/master/tck) \ No newline at end of file