From 91411d6fe9111dc4a9506c488b56b5cceeb08f2b Mon Sep 17 00:00:00 2001 From: Jason Quesenberry Date: Thu, 6 Nov 2025 09:33:09 -0700 Subject: [PATCH] Go: Added steering docs --- steering_docs/go-tech/actions.md | 435 +++++++++++++++++ steering_docs/go-tech/basics.md | 432 +++++++++++++++++ steering_docs/go-tech/hello.md | 201 ++++++++ steering_docs/go-tech/metadata.md | 407 ++++++++++++++++ steering_docs/go-tech/readme_writeme.md | 421 +++++++++++++++++ steering_docs/go-tech/tests.md | 604 ++++++++++++++++++++++++ 6 files changed, 2500 insertions(+) create mode 100644 steering_docs/go-tech/actions.md create mode 100644 steering_docs/go-tech/basics.md create mode 100644 steering_docs/go-tech/hello.md create mode 100644 steering_docs/go-tech/metadata.md create mode 100644 steering_docs/go-tech/readme_writeme.md create mode 100644 steering_docs/go-tech/tests.md diff --git a/steering_docs/go-tech/actions.md b/steering_docs/go-tech/actions.md new file mode 100644 index 00000000000..771bbd20c8e --- /dev/null +++ b/steering_docs/go-tech/actions.md @@ -0,0 +1,435 @@ +# Go Actions/Wrapper Generation + +## MANDATORY: Knowledge Base Consultation (FIRST STEP) +**🚨 CRITICAL - Must be completed BEFORE any code generation** + +```bash +# Step 1: List available knowledge bases +ListKnowledgeBases() + +# Step 2: Query coding standards (REQUIRED) +QueryKnowledgeBases("coding-standards-KB", "Go-code-example-standards") + +# Step 3: Query implementation patterns (REQUIRED) +QueryKnowledgeBases("Go-premium-KB", "Go implementation patterns structure") + +# Step 4: AWS service research (REQUIRED) +search_documentation("What is [AWS Service] and what are its key API operations?") +read_documentation("https://docs.aws.amazon.com/[service]/latest/[relevant-page]") +``` + +**FAILURE TO COMPLETE KNOWLEDGE BASE CONSULTATION WILL RESULT IN INCORRECT CODE STRUCTURE** + +## Purpose +Generate service wrapper structs that encapsulate AWS SDK operations with enhanced error handling, logging, and simplified interfaces for use in scenarios and examples. + +## Requirements +- **Encapsulation**: Wrap AWS SDK client operations in service-specific structs +- **Error Handling**: Provide enhanced error handling with user-friendly messages +- **Context Support**: ALWAYS use context.Context for AWS operations +- **Testability**: Design for easy unit testing with interfaces +- **Documentation**: Comprehensive documentation for all exported methods + +## File Structure +``` +gov2/{service}/actions/ +├── {service}_basics.go # Actions struct and methods +├── {service}_basics_test.go # Unit tests +└── {service}_basics_integ_test.go # Integration tests +``` + +## Actions Struct Pattern +```go +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package actions contains wrapper functions for {AWS Service} operations. +package actions + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/aws/aws-sdk-go-v2/service/{service}" + "github.com/aws/aws-sdk-go-v2/service/{service}/types" + "github.com/aws/smithy-go" +) + +// {Service}Actions encapsulates {AWS Service} operations. +type {Service}Actions struct { + {Service}Client *{service}.Client +} + +// ListResources lists all resources in the {AWS Service}. +func (actions *{Service}Actions) ListResources(ctx context.Context) ([]types.{ResourceType}, error) { + var resources []types.{ResourceType} + + result, err := actions.{Service}Client.List{Resources}(ctx, &{service}.List{Resources}Input{}) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "AccessDenied": + return nil, fmt.Errorf("you don't have permission to list {resources}: %w", err) + case "InternalServerError": + return nil, fmt.Errorf("service temporarily unavailable, please retry: %w", err) + default: + return nil, fmt.Errorf("couldn't list {resources}: %w", err) + } + } + return nil, fmt.Errorf("couldn't list {resources}: %w", err) + } + + resources = result.{Resources} + log.Printf("Found %d {resource}(s)", len(resources)) + + return resources, nil +} + +// CreateResource creates a new resource in {AWS Service}. +func (actions *{Service}Actions) CreateResource(ctx context.Context, resourceName string) (string, error) { + input := &{service}.Create{Resource}Input{ + {ResourceName}: &resourceName, + // Add other required parameters + } + + result, err := actions.{Service}Client.Create{Resource}(ctx, input) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "BadRequestException": + return "", fmt.Errorf("invalid resource configuration: %w", err) + case "ResourceAlreadyExistsException": + return "", fmt.Errorf("resource with name '%s' already exists: %w", resourceName, err) + case "LimitExceededException": + return "", fmt.Errorf("resource limit exceeded: %w", err) + default: + return "", fmt.Errorf("couldn't create resource: %w", err) + } + } + return "", fmt.Errorf("couldn't create resource: %w", err) + } + + resourceId := *result.{ResourceId} + log.Printf("Created resource: %s", resourceId) + + return resourceId, nil +} + +// GetResource retrieves detailed information about a specific resource. +func (actions *{Service}Actions) GetResource(ctx context.Context, resourceId string) (*types.{ResourceType}, error) { + input := &{service}.Get{Resource}Input{ + {ResourceId}: &resourceId, + } + + result, err := actions.{Service}Client.Get{Resource}(ctx, input) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "ResourceNotFoundException": + return nil, fmt.Errorf("resource '%s' not found: %w", resourceId, err) + case "AccessDenied": + return nil, fmt.Errorf("you don't have permission to access resource '%s': %w", resourceId, err) + default: + return nil, fmt.Errorf("couldn't get resource '%s': %w", resourceId, err) + } + } + return nil, fmt.Errorf("couldn't get resource '%s': %w", resourceId, err) + } + + return result.{Resource}, nil +} + +// UpdateResource updates an existing resource. +func (actions *{Service}Actions) UpdateResource(ctx context.Context, resourceId string, updates map[string]interface{}) error { + input := &{service}.Update{Resource}Input{ + {ResourceId}: &resourceId, + // Map updates to appropriate input fields + } + + _, err := actions.{Service}Client.Update{Resource}(ctx, input) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "ResourceNotFoundException": + return fmt.Errorf("resource '%s' not found: %w", resourceId, err) + case "BadRequestException": + return fmt.Errorf("invalid update parameters: %w", err) + case "ConflictException": + return fmt.Errorf("resource '%s' is in a state that cannot be updated: %w", resourceId, err) + default: + return fmt.Errorf("couldn't update resource '%s': %w", resourceId, err) + } + } + return fmt.Errorf("couldn't update resource '%s': %w", resourceId, err) + } + + log.Printf("Updated resource: %s", resourceId) + return nil +} + +// DeleteResource deletes a resource from {AWS Service}. +func (actions *{Service}Actions) DeleteResource(ctx context.Context, resourceId string) error { + input := &{service}.Delete{Resource}Input{ + {ResourceId}: &resourceId, + } + + _, err := actions.{Service}Client.Delete{Resource}(ctx, input) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "ResourceNotFoundException": + return fmt.Errorf("resource '%s' not found: %w", resourceId, err) + case "ConflictException": + return fmt.Errorf("resource '%s' cannot be deleted in its current state: %w", resourceId, err) + case "AccessDenied": + return fmt.Errorf("you don't have permission to delete resource '%s': %w", resourceId, err) + default: + return fmt.Errorf("couldn't delete resource '%s': %w", resourceId, err) + } + } + return fmt.Errorf("couldn't delete resource '%s': %w", resourceId, err) + } + + log.Printf("Deleted resource: %s", resourceId) + return nil +} + +// ProcessData performs data processing operations on the resource. +func (actions *{Service}Actions) ProcessData(ctx context.Context, resourceId string, data []byte) error { + input := &{service}.Process{Data}Input{ + {ResourceId}: &resourceId, + Data: data, + } + + _, err := actions.{Service}Client.Process{Data}(ctx, input) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "ResourceNotFoundException": + return fmt.Errorf("resource '%s' not found: %w", resourceId, err) + case "InvalidDataException": + return fmt.Errorf("invalid data format: %w", err) + case "ThrottlingException": + return fmt.Errorf("request throttled, please retry: %w", err) + default: + return fmt.Errorf("couldn't process data for resource '%s': %w", resourceId, err) + } + } + return fmt.Errorf("couldn't process data for resource '%s': %w", resourceId, err) + } + + log.Printf("Processed data for resource: %s", resourceId) + return nil +} + +// ListDataItems lists data items associated with a resource. +func (actions *{Service}Actions) ListDataItems(ctx context.Context, resourceId string) ([]types.{DataItemType}, error) { + var allItems []types.{DataItemType} + var nextToken *string + + for { + input := &{service}.List{DataItems}Input{ + {ResourceId}: &resourceId, + NextToken: nextToken, + MaxResults: aws.Int32(100), // Reasonable page size + } + + result, err := actions.{Service}Client.List{DataItems}(ctx, input) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "ResourceNotFoundException": + return nil, fmt.Errorf("resource '%s' not found: %w", resourceId, err) + case "AccessDenied": + return nil, fmt.Errorf("you don't have permission to list data items: %w", err) + default: + return nil, fmt.Errorf("couldn't list data items: %w", err) + } + } + return nil, fmt.Errorf("couldn't list data items: %w", err) + } + + allItems = append(allItems, result.{DataItems}...) + + nextToken = result.NextToken + if nextToken == nil { + break + } + } + + log.Printf("Found %d data item(s) for resource %s", len(allItems), resourceId) + return allItems, nil +} + +// GetDataItemDetails retrieves detailed information about specific data items. +func (actions *{Service}Actions) GetDataItemDetails(ctx context.Context, resourceId string, itemIds []string) ([]types.{DetailedDataType}, error) { + var detailedItems []types.{DetailedDataType} + + // Process items in batches if the service supports batch operations + for _, itemId := range itemIds { + input := &{service}.Get{DataItem}Input{ + {ResourceId}: &resourceId, + {ItemId}: &itemId, + } + + result, err := actions.{Service}Client.Get{DataItem}(ctx, input) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "ItemNotFoundException": + log.Printf("Data item '%s' not found, skipping", itemId) + continue + case "AccessDenied": + return nil, fmt.Errorf("you don't have permission to access data item '%s': %w", itemId, err) + default: + return nil, fmt.Errorf("couldn't get data item '%s': %w", itemId, err) + } + } + return nil, fmt.Errorf("couldn't get data item '%s': %w", itemId, err) + } + + detailedItems = append(detailedItems, *result.{DataItem}) + } + + log.Printf("Retrieved details for %d data item(s)", len(detailedItems)) + return detailedItems, nil +} +``` + +## Error Handling Patterns + +### Service-Specific Error Handling +```go +// Handle common AWS service errors with user-friendly messages +func handleServiceError(err error, operation string) error { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "AccessDenied", "UnauthorizedOperation": + return fmt.Errorf("you don't have permission to %s: %w", operation, err) + case "ResourceNotFoundException", "NoSuchResource": + return fmt.Errorf("resource not found: %w", err) + case "BadRequestException", "InvalidParameterValue": + return fmt.Errorf("invalid request parameters: %w", err) + case "LimitExceededException", "ThrottlingException": + return fmt.Errorf("request limit exceeded, please retry: %w", err) + case "InternalServerError", "ServiceUnavailable": + return fmt.Errorf("service temporarily unavailable, please retry: %w", err) + default: + return fmt.Errorf("couldn't %s: %w", operation, err) + } + } + return fmt.Errorf("couldn't %s: %w", operation, err) +} +``` + +### Pagination Handling +```go +// Handle paginated responses properly +func (actions *{Service}Actions) ListAllResources(ctx context.Context) ([]types.{ResourceType}, error) { + var allResources []types.{ResourceType} + var nextToken *string + + for { + input := &{service}.List{Resources}Input{ + NextToken: nextToken, + MaxResults: aws.Int32(100), + } + + result, err := actions.{Service}Client.List{Resources}(ctx, input) + if err != nil { + return nil, handleServiceError(err, "list resources") + } + + allResources = append(allResources, result.{Resources}...) + + nextToken = result.NextToken + if nextToken == nil { + break + } + } + + return allResources, nil +} +``` + +## Context Usage Patterns +```go +// Always accept context as first parameter +func (actions *{Service}Actions) Operation(ctx context.Context, params ...interface{}) error { + // Use context in all AWS SDK calls + result, err := actions.{Service}Client.SomeOperation(ctx, input) + if err != nil { + return err + } + return nil +} + +// For operations that might take time, check context cancellation +func (actions *{Service}Actions) LongRunningOperation(ctx context.Context) error { + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + // Continue operation + } + + // Perform work + time.Sleep(time.Second) + } +} +``` + +## Testing Support +```go +// Define interfaces for testability +type {Service}ClientAPI interface { + List{Resources}(ctx context.Context, params *{service}.List{Resources}Input, optFns ...func(*{service}.Options)) (*{service}.List{Resources}Output, error) + Create{Resource}(ctx context.Context, params *{service}.Create{Resource}Input, optFns ...func(*{service}.Options)) (*{service}.Create{Resource}Output, error) + // Add other methods as needed +} + +// Update actions struct to use interface +type {Service}Actions struct { + {Service}Client {Service}ClientAPI +} +``` + +## Documentation Requirements +- **Package documentation**: Describe the purpose and usage of the actions package +- **Struct documentation**: Explain what the actions struct encapsulates +- **Method documentation**: Document parameters, return values, and error conditions +- **Error documentation**: Describe possible error conditions and their meanings +- **Example usage**: Include usage examples in documentation + +## Actions Requirements +- ✅ **ALWAYS** use context.Context as the first parameter for all methods +- ✅ **ALWAYS** provide enhanced error handling with user-friendly messages +- ✅ **ALWAYS** include comprehensive logging for operations +- ✅ **ALWAYS** handle pagination properly for list operations +- ✅ **ALWAYS** follow Go naming conventions (PascalCase for exported, camelCase for unexported) +- ✅ **ALWAYS** include proper documentation for all exported methods +- ✅ **ALWAYS** design for testability with interfaces +- ✅ **ALWAYS** validate input parameters where appropriate +- ✅ **ALWAYS** use smithy.APIError for AWS-specific error handling + +## Common Patterns +- Encapsulate AWS SDK clients in service-specific structs +- Provide simplified method signatures for common operations +- Handle errors gracefully with informative messages +- Support pagination automatically in list operations +- Include logging for debugging and monitoring +- Design methods to be easily testable +- Follow consistent naming patterns across all actions +- Use context for cancellation and timeouts \ No newline at end of file diff --git a/steering_docs/go-tech/basics.md b/steering_docs/go-tech/basics.md new file mode 100644 index 00000000000..37b91e4f4a3 --- /dev/null +++ b/steering_docs/go-tech/basics.md @@ -0,0 +1,432 @@ +# Go Interactive Scenario Generation + +## MANDATORY: Knowledge Base Consultation (FIRST STEP) +**🚨 CRITICAL - Must be completed BEFORE any code generation** + +```bash +# Step 1: List available knowledge bases +ListKnowledgeBases() + +# Step 2: Query coding standards (REQUIRED) +QueryKnowledgeBases("coding-standards-KB", "Go-code-example-standards") + +# Step 3: Query implementation patterns (REQUIRED) +QueryKnowledgeBases("Go-premium-KB", "Go implementation patterns structure") + +# Step 4: AWS service research (REQUIRED) +search_documentation("What is [AWS Service] and what are its key API operations?") +read_documentation("https://docs.aws.amazon.com/[service]/latest/[relevant-page]") +``` + +**FAILURE TO COMPLETE KNOWLEDGE BASE CONSULTATION WILL RESULT IN INCORRECT CODE STRUCTURE** + +## Purpose +Generate interactive scenarios that demonstrate complete workflows using multiple service operations in a guided, educational manner. Implementation must be based on the service SPECIFICATION.md file. + +## Requirements +- **Specification-Driven**: MUST read the `scenarios/basics/{service}/SPECIFICATION.md` +- **Interactive**: Use fmt.Print and fmt.Scan for user input and guidance +- **Educational**: Break complex workflows into logical phases +- **Comprehensive**: Cover setup, demonstration, examination, and cleanup +- **Error Handling**: Graceful error handling with user-friendly messages +- **Actions Classes**: MUST use service actions structs for all operations +- **Context**: ALWAYS use context.Context for AWS operations + +## File Structure +``` +gov2/{service}/scenarios/ +├── scenario_{name}.go # Main scenario file +├── scenario_{name}_test.go # Unit tests +└── scenario_{name}_integ_test.go # Integration tests +``` + +## MANDATORY Pre-Implementation Steps + +### Step 1: Read Service Specification +**CRITICAL**: Always read `scenarios/basics/{service}/SPECIFICATION.md` first to understand: +- **API Actions Used**: Exact operations to implement +- **Proposed Example Structure**: Setup, demonstration, examination, cleanup phases +- **Error Handling**: Specific error codes and handling requirements +- **Scenario Flow**: Step-by-step workflow description + +### Step 2: Extract Implementation Requirements +From the specification, identify: +- **Setup Phase**: What resources need to be created/configured +- **Demonstration Phase**: What operations to demonstrate +- **Examination Phase**: What data to display and how to filter/analyze +- **Cleanup Phase**: What resources to clean up and user options + +## Scenario Implementation Pattern +### Implementation Pattern Based on SPECIFICATION.md +```go +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package scenarios contains interactive scenarios that demonstrate AWS service capabilities. +package scenarios + +import ( + "context" + "errors" + "fmt" + "log" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/{service}" + "github.com/aws/smithy-go" + "github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools" + "github.com/awsdocs/aws-doc-sdk-examples/gov2/{service}/actions" +) + +// {Service}Scenario contains the state and methods for the interactive {AWS Service} scenario. +type {Service}Scenario struct { + {service}Actions *actions.{Service}Actions + questioner demotools.IQuestioner + resourceId string +} + +// New{Service}Scenario constructs a {Service}Scenario from the provided SDK configuration. +func New{Service}Scenario(sdkConfig aws.Config, questioner demotools.IQuestioner) {Service}Scenario { + {service}Client := {service}.NewFromConfig(sdkConfig) + return {Service}Scenario{ + {service}Actions: &actions.{Service}Actions{{Service}Client: {service}Client}, + questioner: questioner, + } +} + +// Run runs the interactive scenario. +func (scenario *{Service}Scenario) Run(ctx context.Context) { + defer func() { + if r := recover(); r != nil { + log.Printf("Something went wrong with the demo: %v", r) + } + }() + + log.Println(strings.Repeat("-", 88)) + log.Println("Welcome to the {AWS Service} basics scenario!") + log.Println(strings.Repeat("-", 88)) + log.Println("{Service description and what users will learn}") + log.Println() + + err := scenario.runScenario(ctx) + if err != nil { + log.Printf("Scenario failed: %v", err) + } +} + +// runScenario runs the main scenario workflow. +func (scenario *{Service}Scenario) runScenario(ctx context.Context) error { + var err error + + defer func() { + cleanupErr := scenario.cleanupPhase(ctx) + if cleanupErr != nil { + log.Printf("Cleanup failed: %v", cleanupErr) + } + }() + + err = scenario.setupPhase(ctx) + if err != nil { + return fmt.Errorf("setup phase failed: %w", err) + } + + err = scenario.demonstrationPhase(ctx) + if err != nil { + return fmt.Errorf("demonstration phase failed: %w", err) + } + + err = scenario.examinationPhase(ctx) + if err != nil { + return fmt.Errorf("examination phase failed: %w", err) + } + + return nil +} + +// setupPhase implements the setup phase based on specification. +func (scenario *{Service}Scenario) setupPhase(ctx context.Context) error { + log.Println("Setting up {AWS Service}...") + log.Println() + + // Example: Check for existing resources (from specification) + existingResources, err := scenario.{service}Actions.ListResources(ctx) + if err != nil { + return fmt.Errorf("couldn't list existing resources: %w", err) + } + + if len(existingResources) > 0 { + log.Printf("Found %d existing resource(s):", len(existingResources)) + for _, resource := range existingResources { + log.Printf(" - %s", *resource.{ResourceName}) + } + + useExisting := scenario.questioner.AskBool("Would you like to use an existing resource? (y/n)", "y") + if useExisting { + scenario.resourceId = *existingResources[0].{ResourceId} + return nil + } + } + + // Create new resource as specified + log.Println("Creating new resource...") + resourceId, err := scenario.{service}Actions.CreateResource(ctx) + if err != nil { + return fmt.Errorf("couldn't create resource: %w", err) + } + + scenario.resourceId = resourceId + log.Printf("✓ Resource created successfully: %s", resourceId) + return nil +} + +// demonstrationPhase implements the demonstration phase based on specification. +func (scenario *{Service}Scenario) demonstrationPhase(ctx context.Context) error { + log.Println("Demonstrating {AWS Service} capabilities...") + log.Println() + + // Implement specific operations from specification + // Example: Generate sample data if specified + err := scenario.{service}Actions.CreateSampleData(ctx, scenario.resourceId) + if err != nil { + return fmt.Errorf("couldn't create sample data: %w", err) + } + log.Println("✓ Sample data created successfully") + + // Wait if specified in the specification + log.Println("Waiting for data to be processed...") + time.Sleep(5 * time.Second) + + return nil +} + +// examinationPhase implements the examination phase based on specification. +func (scenario *{Service}Scenario) examinationPhase(ctx context.Context) error { + log.Println("Examining {AWS Service} data...") + log.Println() + + // List and examine data as specified + dataItems, err := scenario.{service}Actions.ListData(ctx, scenario.resourceId) + if err != nil { + return fmt.Errorf("couldn't list data: %w", err) + } + + if len(dataItems) == 0 { + log.Println("No data found. Data may take a few minutes to appear.") + return nil + } + + log.Printf("Found %d data item(s)", len(dataItems)) + + // Get detailed information as specified + maxItems := 5 + if len(dataItems) < maxItems { + maxItems = len(dataItems) + } + + detailedData, err := scenario.{service}Actions.GetDataDetails(ctx, scenario.resourceId, dataItems[:maxItems]) + if err != nil { + return fmt.Errorf("couldn't get data details: %w", err) + } + + scenario.displayDataSummary(detailedData) + + // Show detailed view if specified + if len(detailedData) > 0 { + showDetails := scenario.questioner.AskBool("Would you like to see detailed information? (y/n)", "n") + if showDetails { + scenario.displayDataDetails(detailedData[0]) + } + } + + // Filter data as specified + scenario.filterDataByCriteria(dataItems) + + return nil +} + +// cleanupPhase implements the cleanup phase based on specification. +func (scenario *{Service}Scenario) cleanupPhase(ctx context.Context) error { + if scenario.resourceId == "" { + return nil + } + + log.Println("Cleanup options:") + log.Println("Note: Deleting the resource will stop all monitoring/processing.") + + deleteResource := scenario.questioner.AskBool("Would you like to delete the resource? (y/n)", "n") + + if deleteResource { + err := scenario.{service}Actions.DeleteResource(ctx, scenario.resourceId) + if err != nil { + return fmt.Errorf("couldn't delete resource: %w", err) + } + log.Printf("✓ Deleted resource: %s", scenario.resourceId) + } else { + log.Printf("Resource %s will continue running.", scenario.resourceId) + log.Println("You can manage it through the AWS Console or delete it later.") + } + + return nil +} + +// displayDataSummary displays a summary of the data items. +func (scenario *{Service}Scenario) displayDataSummary(detailedData []{DetailedDataType}) { + log.Println("\nData Summary:") + for _, data := range detailedData { + log.Printf(" • %s", *data.{SummaryField}) + } +} + +// displayDataDetails displays detailed information about a data item. +func (scenario *{Service}Scenario) displayDataDetails(data {DetailedDataType}) { + log.Println("\nDetailed Information:") + log.Printf(" ID: %s", *data.{IdField}) + log.Printf(" Status: %s", *data.{StatusField}) + log.Printf(" Created: %s", *data.{CreatedField}) + // Add more fields as specified +} + +// filterDataByCriteria filters data based on criteria from specification. +func (scenario *{Service}Scenario) filterDataByCriteria(dataItems []{DataItemType}) { + log.Println("\nFiltering data by criteria...") + // Implement filtering logic as specified in the specification +} +``` + +## Scenario Phase Structure (Based on Specification) + +### Setup Phase +- **Read specification Setup section** for exact requirements +- Check for existing resources as specified +- Create necessary resources using actions methods +- Configure service settings per specification +- Verify setup completion as described + +### Demonstration Phase +- **Follow specification Demonstration section** exactly +- Perform core service operations using actions methods +- Generate sample data if specified in the specification +- Show service capabilities as outlined +- Provide educational context from specification + +### Examination Phase +- **Implement specification Examination section** requirements +- List and examine results using actions methods +- Filter and analyze data as specified +- Display detailed information per specification format +- Allow user interaction as described in specification + +### Cleanup Phase +- **Follow specification Cleanup section** guidance +- Offer cleanup options with warnings from specification +- Handle cleanup errors gracefully using actions methods +- Provide alternative management options as specified +- Confirm completion per specification + +## User Interaction Patterns + +### Question Types +```go +// Yes/No questions +useExisting := questioner.AskBool("Use existing resource? (y/n)", "y") + +// Text input +resourceName := questioner.Ask("Enter resource name:") + +// Choice selection +choice := questioner.AskChoice("Select an option:", []string{"Option 1", "Option 2"}) +``` + +### Information Display +```go +// Progress indicators +log.Println("✓ Operation completed successfully") +log.Println("⚠ Warning message") +log.Println("✗ Error occurred") + +// Formatted output +log.Println(strings.Repeat("-", 60)) +log.Printf("Found %d items:", len(items)) +for _, item := range items { + log.Printf(" • %s", *item.Name) +} +``` + +## Specification-Based Error Handling + +### Error Handling from Specification +The specification includes an "Errors" section with specific error codes and handling: + +```go +// Example error handling based on specification +func (actions *{Service}Actions) CreateResource(ctx context.Context) (string, error) { + response, err := actions.{Service}Client.CreateResource(ctx, &{service}.CreateResourceInput{ + // Parameters + }) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "BadRequestException": + // Handle as specified: "Validate input parameters and notify user" + return "", fmt.Errorf("invalid configuration, please check your parameters: %w", err) + case "InternalServerErrorException": + // Handle as specified: "Retry operation with exponential backoff" + return "", fmt.Errorf("service temporarily unavailable, please retry: %w", err) + default: + return "", fmt.Errorf("unexpected error: %w", err) + } + } + return "", fmt.Errorf("couldn't create resource: %w", err) + } + + return *response.{ResourceId}, nil +} +``` + +## Scenario Requirements +- ✅ **ALWAYS** read and implement based on `scenarios/basics/{service}/SPECIFICATION.md` +- ✅ **ALWAYS** include descriptive package and function comments explaining scenario steps from specification +- ✅ **ALWAYS** use demotools.IQuestioner for user interaction +- ✅ **ALWAYS** use service actions structs for all AWS operations +- ✅ **ALWAYS** implement proper cleanup in defer block +- ✅ **ALWAYS** break scenario into logical phases per specification +- ✅ **ALWAYS** include error handling per specification's Errors section +- ✅ **ALWAYS** provide educational context and explanations from specification +- ✅ **ALWAYS** handle edge cases (no resources found, etc.) as specified +- ✅ **ALWAYS** use context.Context for all AWS operations + +## Implementation Workflow + +### Step-by-Step Implementation Process +1. **Read Specification**: Study `scenarios/basics/{service}/SPECIFICATION.md` thoroughly +2. **Extract API Actions**: Note all API actions listed in "API Actions Used" section +3. **Map to Actions Methods**: Ensure actions struct has methods for all required actions +4. **Implement Phases**: Follow the "Proposed example structure" section exactly +5. **Add Error Handling**: Implement error handling per the "Errors" section +6. **Test Against Specification**: Verify implementation matches specification requirements + +### Specification Sections to Implement +- **API Actions Used**: All operations must be available in actions struct +- **Proposed example structure**: Direct mapping to scenario phases +- **Setup**: Exact setup steps and resource creation +- **Demonstration**: Specific operations to demonstrate +- **Examination**: Data analysis and filtering requirements +- **Cleanup**: Resource cleanup options and user choices +- **Errors**: Specific error codes and handling strategies + +## Error Handling in Scenarios +- **Follow specification error table**: Implement exact error handling per specification +- Catch and display user-friendly error messages per specification guidance +- Continue scenario execution when possible as specified +- Provide guidance on resolving issues from specification +- Ensure cleanup runs even if errors occur + +## Educational Elements +- **Use specification descriptions**: Explain operations using specification language +- Show before/after states as outlined in specification +- Provide context about service capabilities from specification +- Include tips and best practices mentioned in specification +- Follow the educational flow described in specification structure \ No newline at end of file diff --git a/steering_docs/go-tech/hello.md b/steering_docs/go-tech/hello.md new file mode 100644 index 00000000000..640827e8605 --- /dev/null +++ b/steering_docs/go-tech/hello.md @@ -0,0 +1,201 @@ +# Go Hello Examples Generation + +## MANDATORY: Knowledge Base Consultation (FIRST STEP) +**🚨 CRITICAL - Must be completed BEFORE any code generation** + +```bash +# Step 1: List available knowledge bases +ListKnowledgeBases() + +# Step 2: Query coding standards (REQUIRED) +QueryKnowledgeBases("coding-standards-KB", "Go-code-example-standards") + +# Step 3: Query implementation patterns (REQUIRED) +QueryKnowledgeBases("Go-premium-KB", "Go implementation patterns") + +# Step 4: AWS service research (REQUIRED) +search_documentation("What is [AWS Service] and what are its key API operations?") +read_documentation("https://docs.aws.amazon.com/[service]/latest/[relevant-page]") +``` + +**FAILURE TO COMPLETE KNOWLEDGE BASE CONSULTATION WILL RESULT IN INCORRECT CODE STRUCTURE** + +## Purpose +Generate simple "Hello" examples that demonstrate basic service connectivity and the most fundamental operation using direct AWS SDK for Go v2 client calls. + +## Requirements +- **MANDATORY**: Every AWS service MUST include a "Hello" scenario +- **Simplicity**: Should be the most basic, minimal example possible +- **Standalone**: Must work independently of other examples +- **Direct Client**: Use AWS SDK for Go v2 client directly, no wrapper structs needed +- **Context**: ALWAYS use context.Context for AWS operations + +## File Structure +``` +gov2/{service}/hello/ +├── hello.go # MANDATORY: Hello example file +``` + +## Hello Example Pattern +```go +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package main demonstrates basic {AWS Service} connectivity. +package main + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/{service}" + "github.com/aws/smithy-go" +) + +// main demonstrates basic {AWS Service} connectivity by {basic operation description}. +func main() { + ctx := context.Background() + + // Load AWS configuration + sdkConfig, err := config.LoadDefaultConfig(ctx) + if err != nil { + log.Fatalf("Couldn't load default configuration: %v", err) + } + + // Create service client + {service}Client := {service}.NewFromConfig(sdkConfig) + + // Perform the most basic operation for this service + result, err := {service}Client.{BasicOperation}(ctx, &{service}.{BasicOperationInput}{ + // Add minimal required parameters if any + }) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "UnauthorizedOperation", "AccessDenied": + fmt.Println("You don't have permission to access {AWS Service}.") + default: + fmt.Printf("Couldn't access {AWS Service}. Error: %v\n", err) + } + } else { + fmt.Printf("Couldn't access {AWS Service}. Error: %v\n", err) + } + return + } + + fmt.Println("Hello, {AWS Service}!") + // Display appropriate result information based on service type + +} +``` + +## Hello Examples by Service Type + +### List-Based Services (S3, DynamoDB, etc.) +- **Operation**: List primary resources (buckets, tables, etc.) +- **Message**: Show count and names of resources +- **Example**: +```go +result, err := s3Client.ListBuckets(ctx, &s3.ListBucketsInput{}) +if err != nil { + // Handle error +} + +fmt.Printf("Found %d bucket(s):\n", len(result.Buckets)) +for _, bucket := range result.Buckets { + fmt.Printf(" %s\n", *bucket.Name) +} +``` + +### Status-Based Services (GuardDuty, Config, etc.) +- **Operation**: Check service status or list detectors/configurations +- **Message**: Show service availability and basic status +- **Example**: +```go +result, err := guarddutyClient.ListDetectors(ctx, &guardduty.ListDetectorsInput{}) +if err != nil { + // Handle error +} + +fmt.Printf("Found %d detector(s)\n", len(result.DetectorIds)) +``` + +### Compute Services (EC2, Lambda, etc.) +- **Operation**: List instances/functions or describe regions +- **Message**: Show available resources or regions +- **Example**: +```go +result, err := ec2Client.DescribeRegions(ctx, &ec2.DescribeRegionsInput{}) +if err != nil { + // Handle error +} + +fmt.Printf("Found %d region(s):\n", len(result.Regions)) +for _, region := range result.Regions { + fmt.Printf(" %s\n", *region.RegionName) +} +``` + +## Error Handling Patterns +```go +// Standard error handling for hello examples +if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) { + switch ae.ErrorCode() { + case "UnauthorizedOperation", "AccessDenied": + fmt.Println("You don't have permission to access {AWS Service}.") + case "InvalidUserID.NotFound": + fmt.Println("User credentials not found or invalid.") + default: + fmt.Printf("Couldn't access {AWS Service}. Error: %v\n", err) + } + } else { + fmt.Printf("Couldn't access {AWS Service}. Error: %v\n", err) + } + return +} +``` + +## Context Usage +```go +// Always use context for AWS operations +ctx := context.Background() + +// For operations with timeout (if needed) +ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) +defer cancel() + +result, err := client.Operation(ctx, &service.OperationInput{ + // Parameters +}) +``` + +## Validation Requirements +- ✅ **Must run without errors** (with proper credentials) +- ✅ **Must handle credential issues gracefully** +- ✅ **Must display meaningful output** +- ✅ **Must use direct AWS SDK for Go v2 client calls** +- ✅ **Must include proper package and function documentation** +- ✅ **Must use context.Context for all AWS operations** +- ✅ **Must follow Go naming conventions** + +## Common Patterns +- Always use `{service}.NewFromConfig(sdkConfig)` to create clients +- Include comprehensive error handling with smithy.APIError checking +- Provide user-friendly output messages using fmt.Printf +- Handle both service-specific and general exceptions +- Keep it as simple as possible - no additional structs or complexity +- Use context.Background() for basic operations +- Follow Go naming conventions (camelCase for unexported, PascalCase for exported) + +## File Naming and Structure +- **File location**: `gov2/{service}/hello/hello.go` +- **Package**: `package main` +- **Function structure**: `main()` function as entry point +- **Documentation**: Include package-level and function-level comments +- **Imports**: Only import necessary packages, group standard library, AWS SDK, and third-party imports \ No newline at end of file diff --git a/steering_docs/go-tech/metadata.md b/steering_docs/go-tech/metadata.md new file mode 100644 index 00000000000..889852aa188 --- /dev/null +++ b/steering_docs/go-tech/metadata.md @@ -0,0 +1,407 @@ +# Go Metadata and Module Configuration + +## MANDATORY: Knowledge Base Consultation (FIRST STEP) +**🚨 CRITICAL - Must be completed BEFORE any code generation** + +```bash +# Step 1: List available knowledge bases +ListKnowledgeBases() + +# Step 2: Query coding standards (REQUIRED) +QueryKnowledgeBases("coding-standards-KB", "Go-code-example-standards") + +# Step 3: Query implementation patterns (REQUIRED) +QueryKnowledgeBases("Go-premium-KB", "Go module configuration patterns") + +# Step 4: AWS service research (REQUIRED) +search_documentation("What is [AWS Service] and what are its key API operations?") +read_documentation("https://docs.aws.amazon.com/[service]/latest/[relevant-page]") +``` + +**FAILURE TO COMPLETE KNOWLEDGE BASE CONSULTATION WILL RESULT IN INCORRECT CODE STRUCTURE** + +## Purpose +Generate proper Go module configuration, dependency management, and metadata files for AWS SDK examples in the gov2 directory structure. + +## Requirements +- **Go Modules**: Use go.mod for dependency management +- **Version Compatibility**: Go 1.18+ (recommended Go 1.21+) +- **AWS SDK v2**: Use AWS SDK for Go v2 exclusively +- **Internal Dependencies**: Reference gov2/demotools and gov2/testtools +- **Build Tags**: Use build tags for integration tests + +## File Structure +``` +gov2/{service}/ +├── go.mod # Module definition +├── go.sum # Module checksums (auto-generated) +├── README.md # Service documentation +└── .gitignore # Git ignore patterns +``` + +## Go Module Configuration (go.mod) +```go +module github.com/awsdocs/aws-doc-sdk-examples/gov2/{service} + +go 1.21 + +require ( + github.com/aws/aws-sdk-go-v2 v1.30.5 + github.com/aws/aws-sdk-go-v2/config v1.27.33 + github.com/aws/aws-sdk-go-v2/service/{service} v1.x.x + github.com/aws/smithy-go v1.20.4 + github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools v0.0.0 + github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools v0.0.0 +) + +replace github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools => ../demotools + +replace github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools => ../testtools +``` + +## Common AWS SDK Dependencies + +### Core SDK Dependencies +```go +// Always required +github.com/aws/aws-sdk-go-v2 v1.30.5 +github.com/aws/aws-sdk-go-v2/config v1.27.33 +github.com/aws/smithy-go v1.20.4 + +// Service-specific client +github.com/aws/aws-sdk-go-v2/service/{service} v1.x.x +``` + +### Additional Common Dependencies +```go +// For credential management +github.com/aws/aws-sdk-go-v2/credentials v1.17.32 + +// For AWS configuration +github.com/aws/aws-sdk-go-v2/aws v1.30.5 + +// For feature detection +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 + +// For S3 specific features (if using S3) +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.18 +github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 + +// For DynamoDB specific features (if using DynamoDB) +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.11 +github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.36 +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.9 + +// For STS operations (if needed) +github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 +``` + +### Internal Tool Dependencies +```go +// Demo utilities +github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools v0.0.0 + +// Testing utilities +github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools v0.0.0 +``` + +## Service-Specific go.mod Examples + +### S3 Service Example +```go +module github.com/awsdocs/aws-doc-sdk-examples/gov2/s3 + +go 1.21 + +require ( + github.com/aws/aws-sdk-go-v2 v1.30.5 + github.com/aws/aws-sdk-go-v2/config v1.27.33 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.18 + github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 + github.com/aws/smithy-go v1.20.4 + github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools v0.0.0 + github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools v0.0.0 +) + +replace github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools => ../demotools + +replace github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools => ../testtools +``` + +### DynamoDB Service Example +```go +module github.com/awsdocs/aws-doc-sdk-examples/gov2/dynamodb + +go 1.21 + +require ( + github.com/aws/aws-sdk-go-v2 v1.30.5 + github.com/aws/aws-sdk-go-v2/config v1.27.33 + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.11 + github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.36 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.9 + github.com/aws/smithy-go v1.20.4 + github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools v0.0.0 + github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools v0.0.0 +) + +replace github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools => ../demotools + +replace github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools => ../testtools +``` + +### Lambda Service Example +```go +module github.com/awsdocs/aws-doc-sdk-examples/gov2/lambda + +go 1.21 + +require ( + github.com/aws/aws-sdk-go-v2 v1.30.5 + github.com/aws/aws-sdk-go-v2/config v1.27.33 + github.com/aws/aws-sdk-go-v2/service/lambda v1.58.3 + github.com/aws/smithy-go v1.20.4 + github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools v0.0.0 + github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools v0.0.0 +) + +replace github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools => ../demotools + +replace github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools => ../testtools +``` + +## Git Ignore Configuration (.gitignore) +```gitignore +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Local environment files +.env +.env.local +.env.*.local + +# Temporary files +*.tmp +*.temp +``` + +## README.md Template +```markdown +# AWS SDK for Go V2 {Service Name} examples + +## Purpose + +Shows how to use the AWS SDK for Go V2 to work with {AWS Service Name}. + +## Code examples + +### Scenarios + +* [Get started with {service} basics](scenarios/scenario_basics.go) + +### Actions + +The [actions](actions/) package contains a wrapper that calls {AWS Service} functions. +The wrapper is used in the scenarios and examples to unit test the functions without +calling AWS directly. + +* `Create{Resource}` - Creates a {resource}. +* `Delete{Resource}` - Deletes a {resource}. +* `Get{Resource}` - Gets information about a {resource}. +* `List{Resources}` - Lists {resources}. +* `Update{Resource}` - Updates a {resource}. + +### Hello {Service} + +* [hello](hello/hello.go) - Get started with {AWS Service}. + +## ⚠ Important + +* Running this code might result in charges to your AWS account. +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + +## Prerequisites + +You must have an AWS account, and have configured your default credentials and AWS Region as described in [Getting started with the AWS SDK for Go V2](https://aws.github.io/aws-sdk-go-v2/docs/getting-started/). + +## Running the code + +### Prerequisites + +* You must have an AWS account, and have configured your default credentials and AWS Region as described in [Getting started with the AWS SDK for Go V2](https://aws.github.io/aws-sdk-go-v2/docs/getting-started/). + +### Hello {Service} + +This example shows you how to get started using {AWS Service}. + +``` +go run ./hello +``` + +### Scenarios + +#### Get started with {service} basics + +This interactive scenario runs at a command prompt and shows you how to use {AWS Service} to do the following: + +1. {Step 1 description} +2. {Step 2 description} +3. {Step 3 description} +4. {Step 4 description} + +Start the scenario by running the following at a command prompt: + +``` +go run ./scenarios +``` + +### Tests + +⚠ Running tests might result in charges to your AWS account. + +To find instructions for running these tests, see the [README](../README.md#Tests) +in the `gov2` folder. + +#### Unit tests + +You can run unit tests in this folder with the following: + +``` +go test ./... +``` + +#### Integration tests + +Before running the integration tests, you must set the required resources using the AWS CLI. + +You can run integration tests in this folder with the following: + +``` +go test ./... -tags=integration +``` + +## Additional resources + +* [{AWS Service} User Guide](https://docs.aws.amazon.com/{service}/latest/userguide/) +* [{AWS Service} API Reference](https://docs.aws.amazon.com/{service}/latest/api/) +* [AWS SDK for Go V2 API Reference](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2) +``` + +## Build Tags for Integration Tests +```go +//go:build integration + +// This build tag ensures integration tests only run when explicitly requested +``` + +## Version Management + +### Checking Current Versions +```bash +# Check current Go version +go version + +# Check module dependencies +go list -m all + +# Check for available updates +go list -u -m all +``` + +### Updating Dependencies +```bash +# Update all dependencies to latest compatible versions +go get -u ./... + +# Update specific dependency +go get -u github.com/aws/aws-sdk-go-v2@latest + +# Tidy up dependencies +go mod tidy +``` + +## Module Requirements +- ✅ **ALWAYS** use Go 1.21 or later as the minimum version +- ✅ **ALWAYS** include AWS SDK for Go v2 core dependencies +- ✅ **ALWAYS** include service-specific SDK packages +- ✅ **ALWAYS** reference gov2/demotools and gov2/testtools with replace directives +- ✅ **ALWAYS** use semantic versioning for dependencies +- ✅ **ALWAYS** include .gitignore to exclude build artifacts +- ✅ **ALWAYS** provide comprehensive README.md documentation +- ✅ **ALWAYS** use build tags for integration tests + +## Common Commands +```bash +# Initialize new module +go mod init github.com/awsdocs/aws-doc-sdk-examples/gov2/{service} + +# Add dependencies +go get github.com/aws/aws-sdk-go-v2/service/{service} + +# Clean up dependencies +go mod tidy + +# Verify dependencies +go mod verify + +# Download dependencies +go mod download + +# Build all packages +go build ./... + +# Run tests +go test ./... + +# Run integration tests +go test ./... -tags=integration + +# Run with verbose output +go test -v ./... + +# Run with race detection +go test -race ./... +``` + +## Dependency Management Best Practices +- Keep dependencies up to date but test thoroughly +- Use replace directives for local development dependencies +- Minimize external dependencies beyond AWS SDK +- Use semantic versioning for all dependencies +- Regularly run `go mod tidy` to clean up unused dependencies +- Use `go mod verify` to ensure dependency integrity +- Document any special dependency requirements in README \ No newline at end of file diff --git a/steering_docs/go-tech/readme_writeme.md b/steering_docs/go-tech/readme_writeme.md new file mode 100644 index 00000000000..abdded4681b --- /dev/null +++ b/steering_docs/go-tech/readme_writeme.md @@ -0,0 +1,421 @@ +# Go README Generation + +## MANDATORY: Knowledge Base Consultation (FIRST STEP) +**🚨 CRITICAL - Must be completed BEFORE any code generation** + +```bash +# Step 1: List available knowledge bases +ListKnowledgeBases() + +# Step 2: Query coding standards (REQUIRED) +QueryKnowledgeBases("coding-standards-KB", "Go-code-example-standards") + +# Step 3: Query implementation patterns (REQUIRED) +QueryKnowledgeBases("Go-premium-KB", "Go documentation patterns") + +# Step 4: AWS service research (REQUIRED) +search_documentation("What is [AWS Service] and what are its key API operations?") +read_documentation("https://docs.aws.amazon.com/[service]/latest/[relevant-page]") +``` + +**FAILURE TO COMPLETE KNOWLEDGE BASE CONSULTATION WILL RESULT IN INCORRECT CODE STRUCTURE** + +## Purpose +Generate comprehensive README.md files for Go AWS SDK examples that provide clear documentation, setup instructions, and usage examples. + +## Requirements +- **Service Overview**: Clear description of the AWS service and its purpose +- **Code Examples**: List all available examples with descriptions +- **Prerequisites**: Setup and credential configuration instructions +- **Usage Instructions**: Step-by-step instructions for running examples +- **Testing**: Instructions for running unit and integration tests +- **Resources**: Links to relevant documentation + +## File Structure +``` +gov2/{service}/ +└── README.md # Main service documentation +``` + +## README Template Structure +```markdown +# AWS SDK for Go V2 {Service Name} examples + +## Purpose + +Shows how to use the AWS SDK for Go V2 to work with {AWS Service Name} ({Service Abbreviation}). + +{Brief description of what the service does and why it's useful} + +## Code examples + +### Scenarios + +{List of interactive scenarios with descriptions} + +* [Get started with {service} basics](scenarios/scenario_basics.go) + +### Actions + +The [actions](actions/) package contains a wrapper that calls {AWS Service} functions. +The wrapper is used in the scenarios and examples to unit test the functions without +calling AWS directly. + +{List of available actions with brief descriptions} + +* `Create{Resource}` - Creates a {resource description}. +* `Delete{Resource}` - Deletes a {resource description}. +* `Get{Resource}` - Gets information about a {resource description}. +* `List{Resources}` - Lists {resources description}. +* `Update{Resource}` - Updates a {resource description}. + +### Hello {Service} + +* [hello](hello/hello.go) - Get started with {AWS Service}. + +## ⚠ Important + +* Running this code might result in charges to your AWS account. +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + +## Prerequisites + +You must have an AWS account, and have configured your default credentials and AWS Region as described in [Getting started with the AWS SDK for Go V2](https://aws.github.io/aws-sdk-go-v2/docs/getting-started/). + +## Running the code + +### Hello {Service} + +This example shows you how to get started using {AWS Service}. + +``` +go run ./hello +``` + +### Scenarios + +#### Get started with {service} basics + +This interactive scenario runs at a command prompt and shows you how to use {AWS Service} to do the following: + +{List of scenario steps based on SPECIFICATION.md} + +1. {Step 1 description} +2. {Step 2 description} +3. {Step 3 description} +4. {Step 4 description} + +Start the scenario by running the following at a command prompt: + +``` +go run ./scenarios +``` + +### Tests + +⚠ Running tests might result in charges to your AWS account. + +To find instructions for running these tests, see the [README](../README.md#Tests) +in the `gov2` folder. + +#### Unit tests + +You can run unit tests in this folder with the following: + +``` +go test ./... +``` + +#### Integration tests + +Before running the integration tests, you must set the required resources using the AWS CLI. + +You can run integration tests in this folder with the following: + +``` +go test ./... -tags=integration +``` + +## Additional resources + +* [{AWS Service} User Guide](https://docs.aws.amazon.com/{service}/latest/userguide/) +* [{AWS Service} API Reference](https://docs.aws.amazon.com/{service}/latest/api/) +* [AWS SDK for Go V2 API Reference](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2) +``` + +## Service-Specific README Examples + +### S3 Service README +```markdown +# AWS SDK for Go V2 Amazon S3 examples + +## Purpose + +Shows how to use the AWS SDK for Go V2 to work with Amazon Simple Storage Service (Amazon S3). + +Amazon S3 is an object storage service that offers industry-leading scalability, data availability, security, and performance. + +## Code examples + +### Scenarios + +* [Get started with buckets and objects](scenarios/scenario_basics.go) + +### Actions + +The [actions](actions/) package contains a wrapper that calls Amazon S3 functions. +The wrapper is used in the scenarios and examples to unit test the functions without +calling AWS directly. + +* `CreateBucket` - Creates an S3 bucket. +* `DeleteBucket` - Deletes an S3 bucket. +* `GetObject` - Gets an object from an S3 bucket. +* `ListBuckets` - Lists S3 buckets for your account. +* `ListObjects` - Lists objects in an S3 bucket. +* `PutObject` - Puts an object in an S3 bucket. + +### Hello Amazon S3 + +* [hello](hello/hello.go) - Get started with Amazon S3. + +## ⚠ Important + +* Running this code might result in charges to your AWS account. +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + +## Prerequisites + +You must have an AWS account, and have configured your default credentials and AWS Region as described in [Getting started with the AWS SDK for Go V2](https://aws.github.io/aws-sdk-go-v2/docs/getting-started/). + +## Running the code + +### Hello Amazon S3 + +This example shows you how to get started using Amazon S3. + +``` +go run ./hello +``` + +### Scenarios + +#### Get started with buckets and objects + +This interactive scenario runs at a command prompt and shows you how to use Amazon S3 to do the following: + +1. Create a bucket and upload a file to it. +2. Download an object from a bucket. +3. Copy an object to a subfolder in a bucket. +4. List objects in a bucket. +5. Delete all objects in a bucket. +6. Delete a bucket. + +Start the scenario by running the following at a command prompt: + +``` +go run ./scenarios +``` + +### Tests + +⚠ Running tests might result in charges to your AWS account. + +To find instructions for running these tests, see the [README](../README.md#Tests) +in the `gov2` folder. + +#### Unit tests + +You can run unit tests in this folder with the following: + +``` +go test ./... +``` + +#### Integration tests + +Before running the integration tests, you must set the required resources using the AWS CLI. + +You can run integration tests in this folder with the following: + +``` +go test ./... -tags=integration +``` + +## Additional resources + +* [Amazon S3 User Guide](https://docs.aws.amazon.com/s3/latest/userguide/) +* [Amazon S3 API Reference](https://docs.aws.amazon.com/s3/latest/api/) +* [AWS SDK for Go V2 API Reference](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2) +``` + +### DynamoDB Service README +```markdown +# AWS SDK for Go V2 Amazon DynamoDB examples + +## Purpose + +Shows how to use the AWS SDK for Go V2 to work with Amazon DynamoDB. + +Amazon DynamoDB is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability. + +## Code examples + +### Scenarios + +* [Get started with tables, items, and queries](scenarios/scenario_basics.go) + +### Actions + +The [actions](actions/) package contains a wrapper that calls Amazon DynamoDB functions. +The wrapper is used in the scenarios and examples to unit test the functions without +calling AWS directly. + +* `CreateTable` - Creates a DynamoDB table. +* `DeleteItem` - Deletes an item from a DynamoDB table. +* `DeleteTable` - Deletes a DynamoDB table. +* `GetItem` - Gets an item from a DynamoDB table. +* `ListTables` - Lists DynamoDB tables for your account. +* `PutItem` - Puts an item in a DynamoDB table. +* `Query` - Queries a DynamoDB table. +* `Scan` - Scans a DynamoDB table. +* `UpdateItem` - Updates an item in a DynamoDB table. + +### Hello Amazon DynamoDB + +* [hello](hello/hello.go) - Get started with Amazon DynamoDB. + +## ⚠ Important + +* Running this code might result in charges to your AWS account. +* Running the tests might result in charges to charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + +## Prerequisites + +You must have an AWS account, and have configured your default credentials and AWS Region as described in [Getting started with the AWS SDK for Go V2](https://aws.github.io/aws-sdk-go-v2/docs/getting-started/). + +## Running the code + +### Hello Amazon DynamoDB + +This example shows you how to get started using Amazon DynamoDB. + +``` +go run ./hello +``` + +### Scenarios + +#### Get started with tables, items, and queries + +This interactive scenario runs at a command prompt and shows you how to use Amazon DynamoDB to do the following: + +1. Create a table that can hold movie data. +2. Put, get, and update a single movie in the table. +3. Write movie data to the table from a sample JSON file. +4. Query for movies that were released in a given year. +5. Scan for movies that were released in a range of years. +6. Delete a movie from the table, then delete the table. + +Start the scenario by running the following at a command prompt: + +``` +go run ./scenarios +``` + +### Tests + +⚠ Running tests might result in charges to your AWS account. + +To find instructions for running these tests, see the [README](../README.md#Tests) +in the `gov2` folder. + +#### Unit tests + +You can run unit tests in this folder with the following: + +``` +go test ./... +``` + +#### Integration tests + +Before running the integration tests, you must set the required resources using the AWS CLI. + +You can run integration tests in this folder with the following: + +``` +go test ./... -tags=integration +``` + +## Additional resources + +* [Amazon DynamoDB Developer Guide](https://docs.aws.amazon.com/dynamodb/latest/developerguide/) +* [Amazon DynamoDB API Reference](https://docs.aws.amazon.com/dynamodb/latest/api/) +* [AWS SDK for Go V2 API Reference](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2) +``` + +## README Generation Guidelines + +### Service Description +- Start with the official AWS service name +- Include the service abbreviation if commonly used +- Provide a brief, clear description of what the service does +- Explain the primary use cases or benefits + +### Code Examples Section +- List scenarios first (interactive examples) +- List actions second (wrapper functions) +- List hello examples last (basic connectivity) +- Use consistent formatting and descriptions +- Include file paths for easy navigation + +### Prerequisites Section +- Always reference the official AWS SDK for Go V2 getting started guide +- Mention AWS account requirement +- Emphasize credential and region configuration +- Keep it concise but complete + +### Running Instructions +- Provide exact commands to run each example +- Use code blocks for commands +- Include any special setup requirements +- Mention command-line arguments if needed + +### Testing Section +- Always include the warning about potential charges +- Provide separate instructions for unit and integration tests +- Reference the main gov2 README for detailed testing instructions +- Include build tags information for integration tests + +### Additional Resources +- Always include links to official AWS documentation +- Include both user guide and API reference +- Add AWS SDK for Go V2 API reference +- Use consistent link formatting + +## README Requirements +- ✅ **ALWAYS** include service name and abbreviation in title +- ✅ **ALWAYS** provide clear service description and purpose +- ✅ **ALWAYS** list all available code examples with descriptions +- ✅ **ALWAYS** include prerequisites and setup instructions +- ✅ **ALWAYS** provide exact commands for running examples +- ✅ **ALWAYS** include testing instructions with warnings +- ✅ **ALWAYS** add links to relevant AWS documentation +- ✅ **ALWAYS** use consistent formatting and structure +- ✅ **ALWAYS** include important warnings about charges and permissions +- ✅ **ALWAYS** reference the main gov2 README for additional details + +## Common Patterns +- Use consistent section headers across all service READMEs +- Include the same warning section in all READMEs +- Use code blocks for all commands and file paths +- Maintain consistent link formatting +- Include scenario step descriptions based on SPECIFICATION.md +- Use bullet points for action lists +- Keep descriptions concise but informative \ No newline at end of file diff --git a/steering_docs/go-tech/tests.md b/steering_docs/go-tech/tests.md new file mode 100644 index 00000000000..23c19f45296 --- /dev/null +++ b/steering_docs/go-tech/tests.md @@ -0,0 +1,604 @@ +# Go Testing Standards + +## MANDATORY: Knowledge Base Consultation (FIRST STEP) +**🚨 CRITICAL - Must be completed BEFORE any code generation** + +```bash +# Step 1: List available knowledge bases +ListKnowledgeBases() + +# Step 2: Query coding standards (REQUIRED) +QueryKnowledgeBases("coding-standards-KB", "Go-code-example-standards") + +# Step 3: Query implementation patterns (REQUIRED) +QueryKnowledgeBases("Go-premium-KB", "Go testing patterns") + +# Step 4: AWS service research (REQUIRED) +search_documentation("What is [AWS Service] and what are its key API operations?") +read_documentation("https://docs.aws.amazon.com/[service]/latest/[relevant-page]") +``` + +**FAILURE TO COMPLETE KNOWLEDGE BASE CONSULTATION WILL RESULT IN INCORRECT CODE STRUCTURE** + +## Purpose +Generate comprehensive unit and integration tests for Go AWS SDK examples using the built-in Go testing framework and testtools for mocking. + +## Requirements +- **Unit Tests**: Use `_test.go` suffix, test with mocked/stubbed responses +- **Integration Tests**: Use `_integ_test.go` suffix and `//go:build integration` tag +- **Test Framework**: Use built-in Go testing with `testing` package +- **Mocking**: Use `gov2/testtools` for stubbing AWS calls +- **Context**: ALWAYS use context.Context in tests +- **Table-Driven**: Use subtests with `t.Run()` for multiple test cases + +## File Structure +``` +gov2/{service}/actions/ +├── {service}_basics_test.go # Unit tests +└── {service}_basics_integ_test.go # Integration tests + +gov2/{service}/scenarios/ +├── scenario_{name}_test.go # Unit tests for scenarios +└── scenario_{name}_integ_test.go # Integration tests for scenarios + +gov2/{service}/stubs/ +└── {service}_basics_stubs.go # Test stubs for mocking +``` + +## Unit Test Pattern +```go +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package actions + +import ( + "context" + "errors" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/{service}" + "github.com/aws/aws-sdk-go-v2/service/{service}/types" + "github.com/aws/smithy-go" + "github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools" +) + +func TestListResources(t *testing.T) { + tests := []struct { + name string + stubFunc func(*testtools.AwsmStubber) + expectError bool + expectedCount int + expectedErrMsg string + }{ + { + name: "Success", + stubFunc: func(stubber *testtools.AwsmStubber) { + stubber.Add(testtools.Stub{ + OperationName: "List{Resources}", + Input: &{service}.List{Resources}Input{}, + Output: &{service}.List{Resources}Output{ + {Resources}: []types.{ResourceType}{ + { + {ResourceName}: testtools.GetPtr("test-resource-1"), + {ResourceId}: testtools.GetPtr("resource-1"), + }, + { + {ResourceName}: testtools.GetPtr("test-resource-2"), + {ResourceId}: testtools.GetPtr("resource-2"), + }, + }, + }, + }) + }, + expectError: false, + expectedCount: 2, + }, + { + name: "AccessDenied", + stubFunc: func(stubber *testtools.AwsmStubber) { + stubber.Add(testtools.Stub{ + OperationName: "List{Resources}", + Input: &{service}.List{Resources}Input{}, + Error: &smithy.GenericAPIError{ + Code: "AccessDenied", + Message: "Access denied", + }, + }) + }, + expectError: true, + expectedErrMsg: "you don't have permission to list", + }, + { + name: "InternalServerError", + stubFunc: func(stubber *testtools.AwsmStubber) { + stubber.Add(testtools.Stub{ + OperationName: "List{Resources}", + Input: &{service}.List{Resources}Input{}, + Error: &smithy.GenericAPIError{ + Code: "InternalServerError", + Message: "Internal server error", + }, + }) + }, + expectError: true, + expectedErrMsg: "service temporarily unavailable", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + stubber := testtools.NewStubber() + + tt.stubFunc(stubber) + + actions := &{Service}Actions{ + {Service}Client: {service}.NewFromConfig(aws.Config{}, func(o *{service}.Options) { + o.HTTPClient = stubber + }), + } + + resources, err := actions.ListResources(ctx) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error but got none") + } + if tt.expectedErrMsg != "" && !strings.Contains(err.Error(), tt.expectedErrMsg) { + t.Errorf("Expected error message to contain '%s', got '%s'", tt.expectedErrMsg, err.Error()) + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if len(resources) != tt.expectedCount { + t.Errorf("Expected %d resources, got %d", tt.expectedCount, len(resources)) + } + } + + testtools.VerifyStubsCalled(t, stubber) + }) + } +} + +func TestCreateResource(t *testing.T) { + tests := []struct { + name string + resourceName string + stubFunc func(*testtools.AwsmStubber) + expectError bool + expectedId string + expectedErrMsg string + }{ + { + name: "Success", + resourceName: "test-resource", + stubFunc: func(stubber *testtools.AwsmStubber) { + stubber.Add(testtools.Stub{ + OperationName: "Create{Resource}", + Input: &{service}.Create{Resource}Input{ + {ResourceName}: testtools.GetPtr("test-resource"), + }, + Output: &{service}.Create{Resource}Output{ + {ResourceId}: testtools.GetPtr("resource-123"), + }, + }) + }, + expectError: false, + expectedId: "resource-123", + }, + { + name: "ResourceAlreadyExists", + resourceName: "existing-resource", + stubFunc: func(stubber *testtools.AwsmStubber) { + stubber.Add(testtools.Stub{ + OperationName: "Create{Resource}", + Input: &{service}.Create{Resource}Input{ + {ResourceName}: testtools.GetPtr("existing-resource"), + }, + Error: &smithy.GenericAPIError{ + Code: "ResourceAlreadyExistsException", + Message: "Resource already exists", + }, + }) + }, + expectError: true, + expectedErrMsg: "already exists", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + stubber := testtools.NewStubber() + + tt.stubFunc(stubber) + + actions := &{Service}Actions{ + {Service}Client: {service}.NewFromConfig(aws.Config{}, func(o *{service}.Options) { + o.HTTPClient = stubber + }), + } + + resourceId, err := actions.CreateResource(ctx, tt.resourceName) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error but got none") + } + if tt.expectedErrMsg != "" && !strings.Contains(err.Error(), tt.expectedErrMsg) { + t.Errorf("Expected error message to contain '%s', got '%s'", tt.expectedErrMsg, err.Error()) + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if resourceId != tt.expectedId { + t.Errorf("Expected resource ID '%s', got '%s'", tt.expectedId, resourceId) + } + } + + testtools.VerifyStubsCalled(t, stubber) + }) + } +} + +func TestDeleteResource(t *testing.T) { + tests := []struct { + name string + resourceId string + stubFunc func(*testtools.AwsmStubber) + expectError bool + expectedErrMsg string + }{ + { + name: "Success", + resourceId: "resource-123", + stubFunc: func(stubber *testtools.AwsmStubber) { + stubber.Add(testtools.Stub{ + OperationName: "Delete{Resource}", + Input: &{service}.Delete{Resource}Input{ + {ResourceId}: testtools.GetPtr("resource-123"), + }, + Output: &{service}.Delete{Resource}Output{}, + }) + }, + expectError: false, + }, + { + name: "ResourceNotFound", + resourceId: "nonexistent-resource", + stubFunc: func(stubber *testtools.AwsmStubber) { + stubber.Add(testtools.Stub{ + OperationName: "Delete{Resource}", + Input: &{service}.Delete{Resource}Input{ + {ResourceId}: testtools.GetPtr("nonexistent-resource"), + }, + Error: &smithy.GenericAPIError{ + Code: "ResourceNotFoundException", + Message: "Resource not found", + }, + }) + }, + expectError: true, + expectedErrMsg: "not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + stubber := testtools.NewStubber() + + tt.stubFunc(stubber) + + actions := &{Service}Actions{ + {Service}Client: {service}.NewFromConfig(aws.Config{}, func(o *{service}.Options) { + o.HTTPClient = stubber + }), + } + + err := actions.DeleteResource(ctx, tt.resourceId) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error but got none") + } + if tt.expectedErrMsg != "" && !strings.Contains(err.Error(), tt.expectedErrMsg) { + t.Errorf("Expected error message to contain '%s', got '%s'", tt.expectedErrMsg, err.Error()) + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + + testtools.VerifyStubsCalled(t, stubber) + }) + } +} +``` + +## Integration Test Pattern +```go +//go:build integration + +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package actions + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/{service}" +) + +func TestListResourcesInteg(t *testing.T) { + ctx := context.Background() + + sdkConfig, err := config.LoadDefaultConfig(ctx) + if err != nil { + t.Fatalf("Couldn't load configuration: %v", err) + } + + {service}Client := {service}.NewFromConfig(sdkConfig) + actions := &{Service}Actions{ + {Service}Client: {service}Client, + } + + resources, err := actions.ListResources(ctx) + if err != nil { + t.Errorf("Couldn't list resources: %v", err) + } + + // Verify we can list resources without error + // Don't assert specific counts as they may vary + t.Logf("Found %d resource(s)", len(resources)) +} + +func TestCreateAndDeleteResourceInteg(t *testing.T) { + ctx := context.Background() + + sdkConfig, err := config.LoadDefaultConfig(ctx) + if err != nil { + t.Fatalf("Couldn't load configuration: %v", err) + } + + {service}Client := {service}.NewFromConfig(sdkConfig) + actions := &{Service}Actions{ + {Service}Client: {service}Client, + } + + // Create a test resource + resourceName := fmt.Sprintf("test-resource-%d", time.Now().Unix()) + resourceId, err := actions.CreateResource(ctx, resourceName) + if err != nil { + t.Fatalf("Couldn't create resource: %v", err) + } + + // Ensure cleanup + defer func() { + err := actions.DeleteResource(ctx, resourceId) + if err != nil { + t.Logf("Couldn't delete resource %s: %v", resourceId, err) + } + }() + + // Verify resource was created + resource, err := actions.GetResource(ctx, resourceId) + if err != nil { + t.Errorf("Couldn't get created resource: %v", err) + } + + if *resource.{ResourceName} != resourceName { + t.Errorf("Expected resource name '%s', got '%s'", resourceName, *resource.{ResourceName}) + } + + // Test update if applicable + updates := map[string]interface{}{ + "description": "Updated description", + } + err = actions.UpdateResource(ctx, resourceId, updates) + if err != nil { + t.Errorf("Couldn't update resource: %v", err) + } + + // Verify update + updatedResource, err := actions.GetResource(ctx, resourceId) + if err != nil { + t.Errorf("Couldn't get updated resource: %v", err) + } + + // Verify the update took effect (adjust based on actual service) + if *updatedResource.{DescriptionField} != "Updated description" { + t.Errorf("Resource update didn't take effect") + } +} +``` + +## Scenario Test Pattern +```go +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package scenarios + +import ( + "context" + "strings" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/{service}" + "github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools" + "github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools" +) + +func TestRunScenario(t *testing.T) { + ctx := context.Background() + stubber := testtools.NewStubber() + + // Set up stubs for the entire scenario + setupScenarioStubs(stubber) + + // Create mock questioner with predefined answers + mockQuestioner := &demotools.MockQuestioner{ + Answers: []string{"n", "y", "n"}, // Responses to questions in order + } + + scenario := {Service}Scenario{ + {service}Actions: &actions.{Service}Actions{ + {Service}Client: {service}.NewFromConfig(aws.Config{}, func(o *{service}.Options) { + o.HTTPClient = stubber + }), + }, + questioner: mockQuestioner, + } + + // Run the scenario + scenario.Run(ctx) + + // Verify all stubs were called + testtools.VerifyStubsCalled(t, stubber) +} + +func setupScenarioStubs(stubber *testtools.AwsmStubber) { + // Add stubs for all operations in the scenario + stubber.Add(testtools.Stub{ + OperationName: "List{Resources}", + Input: &{service}.List{Resources}Input{}, + Output: &{service}.List{Resources}Output{ + {Resources}: []types.{ResourceType}{}, + }, + }) + + stubber.Add(testtools.Stub{ + OperationName: "Create{Resource}", + Input: &{service}.Create{Resource}Input{ + {ResourceName}: testtools.GetPtr("test-resource"), + }, + Output: &{service}.Create{Resource}Output{ + {ResourceId}: testtools.GetPtr("test-resource-id"), + }, + }) + + // Add more stubs as needed for the complete scenario +} +``` + +## Test Stubs Pattern +```go +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package stubs defines service operation stubs that are used by unit tests to +// mock service operations. +package stubs + +import ( + "github.com/aws/aws-sdk-go-v2/service/{service}" + "github.com/aws/aws-sdk-go-v2/service/{service}/types" + "github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools" +) + +// StubList{Resources} builds a stub for the List{Resources} operation. +func StubList{Resources}(resources []types.{ResourceType}) testtools.Stub { + return testtools.Stub{ + OperationName: "List{Resources}", + Input: &{service}.List{Resources}Input{}, + Output: &{service}.List{Resources}Output{ + {Resources}: resources, + }, + } +} + +// StubList{Resources}Error builds a stub for the List{Resources} operation that returns an error. +func StubList{Resources}Error(errorCode string, errorMessage string) testtools.Stub { + return testtools.Stub{ + OperationName: "List{Resources}", + Input: &{service}.List{Resources}Input{}, + Error: &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + }, + } +} + +// StubCreate{Resource} builds a stub for the Create{Resource} operation. +func StubCreate{Resource}(resourceName string, resourceId string) testtools.Stub { + return testtools.Stub{ + OperationName: "Create{Resource}", + Input: &{service}.Create{Resource}Input{ + {ResourceName}: testtools.GetPtr(resourceName), + }, + Output: &{service}.Create{Resource}Output{ + {ResourceId}: testtools.GetPtr(resourceId), + }, + } +} + +// StubCreate{Resource}Error builds a stub for the Create{Resource} operation that returns an error. +func StubCreate{Resource}Error(resourceName string, errorCode string, errorMessage string) testtools.Stub { + return testtools.Stub{ + OperationName: "Create{Resource}", + Input: &{service}.Create{Resource}Input{ + {ResourceName}: testtools.GetPtr(resourceName), + }, + Error: &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + }, + } +} + +// StubDelete{Resource} builds a stub for the Delete{Resource} operation. +func StubDelete{Resource}(resourceId string) testtools.Stub { + return testtools.Stub{ + OperationName: "Delete{Resource}", + Input: &{service}.Delete{Resource}Input{ + {ResourceId}: testtools.GetPtr(resourceId), + }, + Output: &{service}.Delete{Resource}Output{}, + } +} + +// StubDelete{Resource}Error builds a stub for the Delete{Resource} operation that returns an error. +func StubDelete{Resource}Error(resourceId string, errorCode string, errorMessage string) testtools.Stub { + return testtools.Stub{ + OperationName: "Delete{Resource}", + Input: &{service}.Delete{Resource}Input{ + {ResourceId}: testtools.GetPtr(resourceId), + }, + Error: &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + }, + } +} +``` + +## Testing Requirements +- ✅ **ALWAYS** use table-driven tests with `t.Run()` for multiple test cases +- ✅ **ALWAYS** test both success and error scenarios +- ✅ **ALWAYS** use `testtools.NewStubber()` for mocking AWS calls in unit tests +- ✅ **ALWAYS** verify stubs were called with `testtools.VerifyStubsCalled()` +- ✅ **ALWAYS** use context.Context in all test functions +- ✅ **ALWAYS** include integration tests with `//go:build integration` tag +- ✅ **ALWAYS** clean up resources in integration tests using defer +- ✅ **ALWAYS** test error handling paths +- ✅ **ALWAYS** use meaningful test names that describe the scenario + +## Common Test Patterns +- Use `testtools.GetPtr()` for creating pointers to values in stubs +- Test all error codes that your actions handle +- Use mock questioner for scenario tests +- Include cleanup in integration tests +- Test pagination in list operations +- Verify error messages contain expected text +- Use subtests for organizing related test cases +- Test context cancellation where applicable \ No newline at end of file