From e55c13c6c6be4156d27907f2ecaa4240f205620f Mon Sep 17 00:00:00 2001 From: Jack Bruno Date: Sun, 27 Sep 2020 14:20:27 -0600 Subject: [PATCH 1/3] Rebase on add_aws_lex_intent_resource branch and first pass to address review comments, still need to expand on resource tests --- aws/data_source_aws_lex_bot.go | 137 +++++++ aws/data_source_aws_lex_bot_test.go | 99 +++++ aws/internal/service/lex/waiter/status.go | 20 + aws/internal/service/lex/waiter/waiter.go | 19 +- aws/provider.go | 2 + aws/resource_aws_lex_bot.go | 426 ++++++++++++++++++++++ aws/resource_aws_lex_bot_test.go | 241 ++++++++++++ website/docs/d/lex_bot.html.markdown | 41 +++ website/docs/r/lex_bot.html.markdown | 142 ++++++++ 9 files changed, 1126 insertions(+), 1 deletion(-) create mode 100644 aws/data_source_aws_lex_bot.go create mode 100644 aws/data_source_aws_lex_bot_test.go create mode 100644 aws/resource_aws_lex_bot.go create mode 100644 aws/resource_aws_lex_bot_test.go create mode 100644 website/docs/d/lex_bot.html.markdown create mode 100644 website/docs/r/lex_bot.html.markdown diff --git a/aws/data_source_aws_lex_bot.go b/aws/data_source_aws_lex_bot.go new file mode 100644 index 00000000000..53c412fc404 --- /dev/null +++ b/aws/data_source_aws_lex_bot.go @@ -0,0 +1,137 @@ +package aws + +import ( + "fmt" + "regexp" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func dataSourceAwsLexBot() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsLexBotRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "checksum": { + Type: schema.TypeString, + Computed: true, + }, + "child_directed": { + Type: schema.TypeBool, + Computed: true, + }, + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "detect_sentiment": { + Type: schema.TypeBool, + Computed: true, + }, + "enable_model_improvements": { + Type: schema.TypeBool, + Computed: true, + }, + "failure_reason": { + Type: schema.TypeString, + Computed: true, + }, + "idle_session_ttl_in_seconds": { + Type: schema.TypeInt, + Computed: true, + }, + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + "locale": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 100), + validation.StringMatch(regexp.MustCompile(`^([A-Za-z]_?)+$`), ""), + ), + }, + "nlu_intent_confidence_threshold": { + Type: schema.TypeFloat, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "version": { + Type: schema.TypeString, + Optional: true, + Default: LexBotVersionLatest, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + validation.StringMatch(regexp.MustCompile(`\$LATEST|[0-9]+`), ""), + ), + }, + "voice_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceAwsLexBotRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lexmodelconn + + botName := d.Get("name").(string) + resp, err := conn.GetBot(&lexmodelbuildingservice.GetBotInput{ + Name: aws.String(botName), + VersionOrAlias: aws.String(d.Get("version").(string)), + }) + if err != nil { + return fmt.Errorf("error getting bot %s: %s", botName, err) + } + + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Service: "lex", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("bot:%s", d.Get("name").(string)), + } + d.Set("arn", arn.String()) + + d.Set("checksum", resp.Checksum) + d.Set("child_directed", resp.ChildDirected) + d.Set("created_date", resp.CreatedDate.Format(time.RFC3339)) + d.Set("description", resp.Description) + d.Set("detect_sentiment", resp.DetectSentiment) + d.Set("enable_model_improvements", resp.EnableModelImprovements) + d.Set("failure_reason", resp.FailureReason) + d.Set("idle_session_ttl_in_seconds", resp.IdleSessionTTLInSeconds) + d.Set("last_updated_date", resp.LastUpdatedDate.Format(time.RFC3339)) + d.Set("locale", resp.Locale) + d.Set("name", resp.Name) + d.Set("nlu_intent_confidence_threshold", resp.NluIntentConfidenceThreshold) + d.Set("status", resp.Status) + d.Set("version", resp.Version) + d.Set("voice_id", resp.VoiceId) + + d.SetId(botName) + + return nil +} diff --git a/aws/data_source_aws_lex_bot_test.go b/aws/data_source_aws_lex_bot_test.go new file mode 100644 index 00000000000..079f0b14ce8 --- /dev/null +++ b/aws/data_source_aws_lex_bot_test.go @@ -0,0 +1,99 @@ +package aws + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceAwsLexBot_basic(t *testing.T) { + rName := acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + dataSourceName := "data.aws_lex_bot.test" + resourceName := "aws_lex_bot.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(rName), + testAccAwsLexBotConfig_basic(rName), + testAccDataSourceAwsLexBotConfig_basic(), + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "checksum", resourceName, "checksum"), + resource.TestCheckResourceAttrPair(dataSourceName, "child_directed", resourceName, "child_directed"), + resource.TestCheckResourceAttrPair(dataSourceName, "created_date", resourceName, "created_date"), + resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"), + resource.TestCheckResourceAttrPair(dataSourceName, "detect_sentiment", resourceName, "detect_sentiment"), + resource.TestCheckResourceAttrPair(dataSourceName, "enable_model_improvements", resourceName, "enable_model_improvements"), + resource.TestCheckResourceAttrPair(dataSourceName, "failure_reason", resourceName, "failure_reason"), + resource.TestCheckResourceAttrPair(dataSourceName, "idle_session_ttl_in_seconds", resourceName, "idle_session_ttl_in_seconds"), + resource.TestCheckResourceAttrPair(dataSourceName, "last_updated_date", resourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(dataSourceName, "locale", resourceName, "locale"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "nlu_intent_confidence_threshold", resourceName, "nlu_intent_confidence_threshold"), + resource.TestCheckResourceAttrPair(dataSourceName, "status", resourceName, "status"), + resource.TestCheckResourceAttrPair(dataSourceName, "version", resourceName, "version"), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsLexBot_withVersion(t *testing.T) { + rName := acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + dataSourceName := "data.aws_lex_bot.test" + resourceName := "aws_lex_bot.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(rName), + testAccAwsLexBotConfig_createVersion(rName), + testAccDataSourceAwsLexBotConfig_withVersion(), + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "checksum", resourceName, "checksum"), + resource.TestCheckResourceAttrPair(dataSourceName, "child_directed", resourceName, "child_directed"), + resource.TestCheckResourceAttrPair(dataSourceName, "created_date", resourceName, "created_date"), + resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"), + resource.TestCheckResourceAttrPair(dataSourceName, "detect_sentiment", resourceName, "detect_sentiment"), + resource.TestCheckResourceAttrPair(dataSourceName, "enable_model_improvements", resourceName, "enable_model_improvements"), + resource.TestCheckResourceAttrPair(dataSourceName, "failure_reason", resourceName, "failure_reason"), + resource.TestCheckResourceAttrPair(dataSourceName, "idle_session_ttl_in_seconds", resourceName, "idle_session_ttl_in_seconds"), + resource.TestCheckResourceAttrPair(dataSourceName, "last_updated_date", resourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(dataSourceName, "locale", resourceName, "locale"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "nlu_intent_confidence_threshold", resourceName, "nlu_intent_confidence_threshold"), + resource.TestCheckResourceAttrPair(dataSourceName, "status", resourceName, "status"), + resource.TestCheckResourceAttrPair(dataSourceName, "version", resourceName, "version"), + ), + }, + }, + }) +} + +func testAccDataSourceAwsLexBotConfig_basic() string { + return ` +data "aws_lex_bot" "test" { + name = aws_lex_bot.test.name +} +` +} + +func testAccDataSourceAwsLexBotConfig_withVersion() string { + return ` +data "aws_lex_bot" "test" { + name = aws_lex_bot.test.name + version = "1" +} +` +} diff --git a/aws/internal/service/lex/waiter/status.go b/aws/internal/service/lex/waiter/status.go index 7c0b09703ec..448c14d9e5b 100644 --- a/aws/internal/service/lex/waiter/status.go +++ b/aws/internal/service/lex/waiter/status.go @@ -52,3 +52,23 @@ func LexIntentStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id s return output, LexModelBuildingServiceStatusCreated, nil } } + +func LexBotStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := conn.GetBotVersions(&lexmodelbuildingservice.GetBotVersionsInput{ + Name: aws.String(id), + }) + if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { + return nil, LexModelBuildingServiceStatusNotFound, nil + } + if err != nil { + return nil, LexModelBuildingServiceStatusUnknown, err + } + + if output == nil || len(output.Bots) == 0 { + return nil, LexModelBuildingServiceStatusNotFound, nil + } + + return output, LexModelBuildingServiceStatusCreated, nil + } +} diff --git a/aws/internal/service/lex/waiter/waiter.go b/aws/internal/service/lex/waiter/waiter.go index 0689ce49666..28932e9a9ce 100644 --- a/aws/internal/service/lex/waiter/waiter.go +++ b/aws/internal/service/lex/waiter/waiter.go @@ -8,10 +8,27 @@ import ( ) const ( - LexSlotTypeDeleteTimeout = 5 * time.Minute + LexBotDeleteTimeout = 5 * time.Minute LexIntentDeleteTimeout = 5 * time.Minute + LexSlotTypeDeleteTimeout = 5 * time.Minute ) +func LexBotDeleted(conn *lexmodelbuildingservice.LexModelBuildingService, botId string) (*lexmodelbuildingservice.GetBotVersionsOutput, error) { + stateChangeConf := &resource.StateChangeConf{ + Pending: []string{LexModelBuildingServiceStatusCreated}, + Target: []string{}, // An empty slice indicates that the resource is gone + Refresh: LexBotStatus(conn, botId), + Timeout: LexBotDeleteTimeout, + } + outputRaw, err := stateChangeConf.WaitForState() + + if v, ok := outputRaw.(*lexmodelbuildingservice.GetBotVersionsOutput); ok { + return v, err + } + + return nil, err +} + func LexIntentDeleted(conn *lexmodelbuildingservice.LexModelBuildingService, intentId string) (*lexmodelbuildingservice.GetIntentVersionsOutput, error) { stateChangeConf := &resource.StateChangeConf{ Pending: []string{LexModelBuildingServiceStatusCreated}, diff --git a/aws/provider.go b/aws/provider.go index 4069b4045a4..c919b4f544c 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -281,6 +281,7 @@ func Provider() *schema.Provider { "aws_lambda_layer_version": dataSourceAwsLambdaLayerVersion(), "aws_launch_configuration": dataSourceAwsLaunchConfiguration(), "aws_launch_template": dataSourceAwsLaunchTemplate(), + "aws_lex_bot": dataSourceAwsLexBot(), "aws_lex_intent": dataSourceAwsLexIntent(), "aws_lex_slot_type": dataSourceAwsLexSlotType(), "aws_mq_broker": dataSourceAwsMqBroker(), @@ -700,6 +701,7 @@ func Provider() *schema.Provider { "aws_lambda_provisioned_concurrency_config": resourceAwsLambdaProvisionedConcurrencyConfig(), "aws_launch_configuration": resourceAwsLaunchConfiguration(), "aws_launch_template": resourceAwsLaunchTemplate(), + "aws_lex_bot": resourceAwsLexBot(), "aws_lex_intent": resourceAwsLexIntent(), "aws_lex_slot_type": resourceAwsLexSlotType(), "aws_licensemanager_association": resourceAwsLicenseManagerAssociation(), diff --git a/aws/resource_aws_lex_bot.go b/aws/resource_aws_lex_bot.go new file mode 100644 index 00000000000..f55a947e03e --- /dev/null +++ b/aws/resource_aws_lex_bot.go @@ -0,0 +1,426 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex/waiter" +) + +const ( + LexBotCreateTimeout = 1 * time.Minute + LexBotUpdateTimeout = 1 * time.Minute + LexBotDeleteTimeout = 5 * time.Minute + LexBotVersionLatest = "$LATEST" +) + +func resourceAwsLexBot() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsLexBotCreate, + Read: resourceAwsLexBotRead, + Update: resourceAwsLexBotUpdate, + Delete: resourceAwsLexBotDelete, + + // TODO add to other lex resources + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + if _, ok := d.GetOk("create_version"); !ok { + d.Set("create_version", false) + } + return []*schema.ResourceData{d}, nil + }, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(LexBotCreateTimeout), + Update: schema.DefaultTimeout(LexBotUpdateTimeout), + Delete: schema.DefaultTimeout(LexBotDeleteTimeout), + }, + + Schema: map[string]*schema.Schema{ + "abort_statement": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: lexStatementResource, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "checksum": { + Type: schema.TypeString, + Computed: true, + }, + "child_directed": { + Type: schema.TypeBool, + Required: true, + }, + "clarification_prompt": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: lexPromptResource, + }, + "create_version": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Default: "", + ValidateFunc: validation.StringLenBetween(0, 200), + }, + "detect_sentiment": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "enable_model_improvements": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "failure_reason": { + Type: schema.TypeString, + Computed: true, + }, + "idle_session_ttl_in_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: 300, + ValidateFunc: validation.IntBetween(60, 86400), + }, + "intent": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + MaxItems: 100, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "intent_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 100), + validation.StringMatch(regexp.MustCompile(`^([A-Za-z]_?)+$`), ""), + ), + }, + "intent_version": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + validation.StringMatch(regexp.MustCompile(`\$LATEST|[0-9]+`), ""), + ), + }, + }, + }, + }, + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + "locale": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: lexmodelbuildingservice.LocaleEnUs, + ValidateFunc: validation.StringInSlice(lexmodelbuildingservice.Locale_Values(), false), + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(2, 50), + validation.StringMatch(regexp.MustCompile(`^([A-Za-z]_?)+$`), ""), + ), + }, + "nlu_intent_confidence_threshold": { + Type: schema.TypeFloat, + Optional: true, + Default: 0, + ValidateFunc: validation.FloatBetween(0, 1), + }, + "process_behavior": { + Type: schema.TypeString, + Optional: true, + Default: lexmodelbuildingservice.ProcessBehaviorSave, + ValidateFunc: validation.StringInSlice(lexmodelbuildingservice.ProcessBehavior_Values(), false), + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "version": { + Type: schema.TypeString, + Computed: true, + }, + "voice_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + } +} + +func resourceAwsLexBotCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lexmodelconn + name := d.Get("name").(string) + + input := &lexmodelbuildingservice.PutBotInput{ + AbortStatement: expandLexStatement(d.Get("abort_statement")), + ChildDirected: aws.Bool(d.Get("child_directed").(bool)), + ClarificationPrompt: expandLexPrompt(d.Get("clarification_prompt")), + CreateVersion: aws.Bool(d.Get("create_version").(bool)), + Description: aws.String(d.Get("description").(string)), + IdleSessionTTLInSeconds: aws.Int64(int64(d.Get("idle_session_ttl_in_seconds").(int))), + Intents: expandLexIntents(d.Get("intent").(*schema.Set).List()), + Locale: aws.String(d.Get("locale").(string)), + Name: aws.String(name), + ProcessBehavior: aws.String(d.Get("process_behavior").(string)), + } + + if v, ok := d.GetOk("voice_id"); ok { + input.VoiceId = aws.String(v.(string)) + } + + err := resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { + output, err := conn.PutBot(input) + + if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeConflictException) { + input.Checksum = output.Checksum + return resource.RetryableError(fmt.Errorf("%q bot still creating, another operation is pending: %s", d.Id(), err)) + } + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + if err != nil { + return fmt.Errorf("error creating bot %s: %w", name, err) + } + + d.SetId(name) + + return resourceAwsLexBotRead(d, meta) +} + +func resourceAwsLexBotRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lexmodelconn + + resp, err := conn.GetBot(&lexmodelbuildingservice.GetBotInput{ + Name: aws.String(d.Id()), + VersionOrAlias: aws.String("$LATEST"), + }) + if isAWSErr(err, lexmodelbuildingservice.ErrCodeNotFoundException, "") { + log.Printf("[WARN] Bot (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error getting intent %s: %w", d.Id(), err) + } + + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Service: "lex", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("bot:%s", d.Id()), + } + d.Set("arn", arn.String()) + + // Process behavior is not returned from the API but is used for create and update. + // Manually write to state file to avoid un-expected diffs. + processBehavior := lexmodelbuildingservice.ProcessBehaviorSave + if v, ok := d.GetOk("process_behavior"); ok { + processBehavior = v.(string) + } + + d.Set("abort_statement", flattenLexStatement(resp.AbortStatement)) + d.Set("checksum", resp.Checksum) + d.Set("child_directed", resp.ChildDirected) + d.Set("clarification_prompt", flattenLexPrompt(resp.ClarificationPrompt)) + d.Set("created_date", resp.CreatedDate.Format(time.RFC3339)) + d.Set("description", resp.Description) + d.Set("detect_sentiment", resp.DetectSentiment) + d.Set("enable_model_improvements", resp.EnableModelImprovements) + d.Set("failure_reason", resp.FailureReason) + d.Set("idle_session_ttl_in_seconds", resp.IdleSessionTTLInSeconds) + d.Set("intent", flattenLexIntents(resp.Intents)) + d.Set("last_updated_date", resp.LastUpdatedDate.Format(time.RFC3339)) + d.Set("locale", resp.Locale) + d.Set("name", resp.Name) + d.Set("nlu_intent_confidence_threshold", resp.NluIntentConfidenceThreshold) + d.Set("process_behavior", processBehavior) + d.Set("status", resp.Status) + + version, err := getLatestLexBotVersion(conn, &lexmodelbuildingservice.GetBotVersionsInput{ + Name: aws.String(d.Id()), + }) + if err != nil { + return err + } + d.Set("version", version) + + if resp.VoiceId != nil { + d.Set("voice_id", resp.VoiceId) + } + + return nil +} + +func resourceAwsLexBotUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lexmodelconn + + input := &lexmodelbuildingservice.PutBotInput{ + AbortStatement: expandLexStatement(d.Get("abort_statement")), + Checksum: aws.String(d.Get("checksum").(string)), + ChildDirected: aws.Bool(d.Get("child_directed").(bool)), + ClarificationPrompt: expandLexPrompt(d.Get("clarification_prompt")), + CreateVersion: aws.Bool(d.Get("create_version").(bool)), + Description: aws.String(d.Get("description").(string)), + DetectSentiment: aws.Bool(d.Get("detect_sentiment").(bool)), + EnableModelImprovements: aws.Bool(d.Get("enable_model_improvements").(bool)), + IdleSessionTTLInSeconds: aws.Int64(int64(d.Get("idle_session_ttl_in_seconds").(int))), + Intents: expandLexIntents(d.Get("intent").(*schema.Set).List()), + Locale: aws.String(d.Get("locale").(string)), + Name: aws.String(d.Id()), + NluIntentConfidenceThreshold: aws.Float64(d.Get("nlu_intent_confidence_threshold").(float64)), + ProcessBehavior: aws.String(d.Get("process_behavior").(string)), + } + + if v, ok := d.GetOk("voice_id"); ok { + input.VoiceId = aws.String(v.(string)) + } + + err := resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + _, err := conn.PutBot(input) + + if isAWSErr(err, lexmodelbuildingservice.ErrCodeConflictException, "") { + return resource.RetryableError(fmt.Errorf("%q: bot still updating", d.Id())) + } + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + if err != nil { + return fmt.Errorf("error updating bot %s: %w", d.Id(), err) + } + + return resourceAwsLexBotRead(d, meta) +} + +func resourceAwsLexBotDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lexmodelconn + + err := resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError { + _, err := conn.DeleteBot(&lexmodelbuildingservice.DeleteBotInput{ + Name: aws.String(d.Id()), + }) + + if isAWSErr(err, lexmodelbuildingservice.ErrCodeConflictException, "") { + return resource.RetryableError(fmt.Errorf("%q: there is a pending operation, bot still deleting", d.Id())) + } + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if err != nil { + return fmt.Errorf("error deleting bot %s: %w", d.Id(), err) + } + + _, err = waiter.LexBotDeleted(conn, d.Id()) + + return err +} + +func getLatestLexBotVersion(conn *lexmodelbuildingservice.LexModelBuildingService, input *lexmodelbuildingservice.GetBotVersionsInput) (string, error) { + version := LexBotVersionLatest + + for { + page, err := conn.GetBotVersions(input) + if err != nil { + return "", err + } + + // At least 1 version will always be returned. + if len(page.Bots) == 1 { + break + } + + for _, bot := range page.Bots { + if *bot.Version == LexBotVersionLatest { + continue + } + if *bot.Version > version { + version = *bot.Version + } + } + + if page.NextToken == nil { + break + } + input.NextToken = page.NextToken + } + + return version, nil +} + +func flattenLexIntents(intents []*lexmodelbuildingservice.Intent) (flattenedIntents []map[string]interface{}) { + for _, intent := range intents { + flattenedIntents = append(flattenedIntents, map[string]interface{}{ + "intent_name": aws.StringValue(intent.IntentName), + "intent_version": aws.StringValue(intent.IntentVersion), + }) + } + + return +} + +// Expects a slice of maps representing the Lex objects. +// The value passed into this function should have been run through the expandLexSet function. +// Example: []map[intent_name: OrderFlowers intent_version: $LATEST] +func expandLexIntents(rawValues []interface{}) []*lexmodelbuildingservice.Intent { + intents := make([]*lexmodelbuildingservice.Intent, 0, len(rawValues)) + + for _, rawValue := range rawValues { + value, ok := rawValue.(map[string]interface{}) + if !ok { + continue + } + + intents = append(intents, &lexmodelbuildingservice.Intent{ + IntentName: aws.String(value["intent_name"].(string)), + IntentVersion: aws.String(value["intent_version"].(string)), + }) + } + + return intents +} diff --git a/aws/resource_aws_lex_bot_test.go b/aws/resource_aws_lex_bot_test.go new file mode 100644 index 00000000000..cf83b1923de --- /dev/null +++ b/aws/resource_aws_lex_bot_test.go @@ -0,0 +1,241 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccAwsLexBot_basic(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + testAccCheckAwsLexBotNotExists(testBotID, "1"), + + resource.TestCheckNoResourceAttr(rName, "abort_statement"), + resource.TestCheckResourceAttrSet(rName, "arn"), + resource.TestCheckResourceAttrSet(rName, "checksum"), + resource.TestCheckResourceAttr(rName, "child_directed", "false"), + resource.TestCheckNoResourceAttr(rName, "clarification_prompt"), + resource.TestCheckResourceAttr(rName, "create_version", "false"), + testAccCheckResourceAttrRfc3339(rName, "created_date"), + resource.TestCheckResourceAttr(rName, "description", "Bot to order flowers on the behalf of a user"), + resource.TestCheckResourceAttr(rName, "detect_sentiment", "false"), + resource.TestCheckResourceAttr(rName, "enable_model_improvements", "false"), + resource.TestCheckResourceAttr(rName, "failure_reason", ""), + resource.TestCheckResourceAttr(rName, "idle_session_ttl_in_seconds", "300"), + resource.TestCheckNoResourceAttr(rName, "intent"), + testAccCheckResourceAttrRfc3339(rName, "last_updated_date"), + resource.TestCheckResourceAttr(rName, "locale", "en-US"), + resource.TestCheckResourceAttr(rName, "name", testBotID), + resource.TestCheckResourceAttr(rName, "nlu_intent_confidence_threshold", "0"), + resource.TestCheckResourceAttr(rName, "process_behavior", "SAVE"), + resource.TestCheckResourceAttr(rName, "status", "NOT_BUILT"), + resource.TestCheckResourceAttr(rName, "version", LexBotVersionLatest), + resource.TestCheckNoResourceAttr(rName, "voice_id"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"create_version"}, + }, + }, + }) +} + +func TestAccAwsLexBot_disappears(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsLexBot(), rName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAwsLexBotExistsWithVersion(rName, botVersion string, output *lexmodelbuildingservice.GetBotOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rName] + if !ok { + return fmt.Errorf("Not found: %s", rName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Lex bot ID is set") + } + + var err error + conn := testAccProvider.Meta().(*AWSClient).lexmodelconn + + output, err = conn.GetBot(&lexmodelbuildingservice.GetBotInput{ + Name: aws.String(rs.Primary.ID), + VersionOrAlias: aws.String(botVersion), + }) + if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { + return fmt.Errorf("error bot %q version %s not found", rs.Primary.ID, botVersion) + } + if err != nil { + return fmt.Errorf("error getting bot %q version %s: %w", rs.Primary.ID, botVersion, err) + } + + return nil + } +} + +func testAccCheckAwsLexBotExists(rName string, output *lexmodelbuildingservice.GetBotOutput) resource.TestCheckFunc { + return testAccCheckAwsLexBotExistsWithVersion(rName, LexBotVersionLatest, output) +} + +func testAccCheckAwsLexBotNotExists(botName, botVersion string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).lexmodelconn + + _, err := conn.GetBot(&lexmodelbuildingservice.GetBotInput{ + Name: aws.String(botName), + VersionOrAlias: aws.String(botVersion), + }) + if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { + return nil + } + if err != nil { + return fmt.Errorf("error getting bot %s version %s: %s", botName, botVersion, err) + } + + return fmt.Errorf("error bot %s version %s exists", botName, botVersion) + } +} + +func testAccCheckAwsLexBotDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).lexmodelconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_lex_bot" { + continue + } + + output, err := conn.GetBotVersions(&lexmodelbuildingservice.GetBotVersionsInput{ + Name: aws.String(rs.Primary.ID), + }) + if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { + continue + } + if err != nil { + return err + } + + if output == nil || len(output.Bots) == 0 { + return nil + } + + return fmt.Errorf("Lex bot %q still exists", rs.Primary.ID) + } + + return nil +} + +func testAccAwsLexBotConfig_intent(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_intent" "test" { + name = "%s" + create_version = true + fulfillment_activity { + type = "ReturnIntent" + } + sample_utterances = [ + "I would like to pick up flowers", + ] +} +`, rName) +} + +func testAccAwsLexBotConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + clarification_prompt { + max_attempts = 2 + message { + content = "I didn't understand you, what would you like to do?" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_createVersion(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + create_version = true + process_behavior = "BUILD" + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + clarification_prompt { + max_attempts = 2 + message { + content = "I didn't understand you, what would you like to do?" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} diff --git a/website/docs/d/lex_bot.html.markdown b/website/docs/d/lex_bot.html.markdown new file mode 100644 index 00000000000..21164d40aa5 --- /dev/null +++ b/website/docs/d/lex_bot.html.markdown @@ -0,0 +1,41 @@ +--- +layout: "aws" +page_title: "AWS: aws_lex_bot" +sidebar_current: "docs-aws-lex-bot" +description: |- + Provides details about a specific Lex Bot +--- + +# Data Source: aws_lex_bot + +Provides details about a specific Amazon Lex Bot. + +## Example Usage + +```hcl +data "aws_lex_bot" "order_flowers_bot" { + name = "OrderFlowers" + version = "$LATEST" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the bot. The name is case sensitive. +* `version` - (Optional) The version or alias of the bot. + +## Attributes Reference + +The following attributes are exported. + +* `child_directed` - Specifies if this Amazon Lex Bot is related to a website, program, or other application that is directed or targeted, in whole or in part, to children under age 13 and subject to COPPA. +* `description` - A description of the bot. +* `detect_sentiment` - When set to true user utterances are sent to Amazon Comprehend for sentiment analysis. +* `enable_model_improvements` - Set to true if natural language understanding improvements are enabled. +* `idle_session_ttl_in_seconds` - The maximum time in seconds that Amazon Lex retains the data gathered in a conversation. +* `locale` - Specifies the target locale for the bot. Any intent used in the bot must be compatible with the locale of the bot. +* `name` - The name of the bot, case sensitive. +* `nlu_intent_confidence_threshold` - The threshold where Amazon Lex will insert the AMAZON.FallbackIntent, AMAZON.KendraSearchIntent, or both when returning alternative intents in a PostContent or PostText response. AMAZON.FallbackIntent and AMAZON.KendraSearchIntent are only inserted if they are configured for the bot. +* `voice_id` - The Amazon Polly voice ID that the Amazon Lex Bot uses for voice interactions with the user. diff --git a/website/docs/r/lex_bot.html.markdown b/website/docs/r/lex_bot.html.markdown new file mode 100644 index 00000000000..c001216fa27 --- /dev/null +++ b/website/docs/r/lex_bot.html.markdown @@ -0,0 +1,142 @@ +--- +layout: "aws" +page_title: "AWS: aws_lex_bot" +sidebar_current: "docs-aws-resource-lex-bot" +description: |- + Provides an Amazon Lex bot resource. +--- + +# Resource: aws_lex_bot + +Provides an Amazon Lex Bot resource. For more information see +[Amazon Lex: How It Works](https://docs.aws.amazon.com/lex/latest/dg/how-it-works.html) + +## Example Usage + +```hcl +resource "aws_lex_bot" "order_flowers_bot" { + abort_statement { + message { + content = "Sorry, I am not able to assist at this time" + content_type = "PlainText" + } + } + + child_directed = false + + clarification_prompt { + max_attempts = 2 + + message { + content = "I didn't understand you, what would you like to do?" + content_type = "PlainText" + } + } + + create_version = false + description = "Bot to order flowers on the behalf of a user" + idle_session_ttl_in_seconds = 600 + + intent { + intent_name = "OrderFlowers" + intent_version = "1" + } + + locale = "en-US" + name = "OrderFlowers" + process_behavior = "BUILD" + voice_id = "Salli" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `abort_statement` - (Required) The message that Amazon Lex uses to abort a conversation. Attributes are documented under [statement](#statement). +* `child_directed` - (Required) By specifying true, you confirm that your use of Amazon Lex is related to a website, program, or other application that is directed or targeted, in whole or in part, to children under age 13 and subject to COPPA. For more information see the [Amazon Lex FAQ](https://aws.amazon.com/lex/faqs#data-security) and the [Amazon Lex PutBot API Docs](https://docs.aws.amazon.com/lex/latest/dg/API_PutBot.html#lex-PutBot-request-childDirected). +* `clarification_prompt` - (Required) The message that Amazon Lex uses when it doesn't understand the user's request. Attributes are documented under [prompt](#prompt). +* `create_version` - (Optional) Determines if a new bot version is created when the initial resource is created and on each update. Defaults to `false`. +* `description` - (Optional) A description of the bot. +* `detect_sentiment` - (Optional) When set to true user utterances are sent to Amazon Comprehend for sentiment analysis. If you don't specify detectSentiment, the default is `false`. +* `enable_model_improvements` - (Optional) Set to `true` to enable access to natural language understanding improvements. When you set the `enable_model_improvements` parameter to true you can use the `nlu_intent_confidence_threshold` parameter to configure confidence scores. For more information, see [Confidence Scores](https://docs.aws.amazon.com/lex/latest/dg/confidence-scores.html). You can only set the `enable_model_improvements` parameter in certain Regions. If you set the parameter to true, your bot has access to accuracy improvements. For more information see the [Amazon Lex Bot PutBot API Docs](https://docs.aws.amazon.com/lex/latest/dg/API_PutBot.html#lex-PutBot-request-enableModelImprovements). +* `idle_session_ttl_in_seconds` - (Optional) The maximum time in seconds that Amazon Lex retains the data gathered in a conversation. Default is `300`. +* `locale` - (Optional) Specifies the target locale for the bot. Any intent used in the bot must be compatible with the locale of the bot. For available locales, see [Amazon Lex Bot PutBot API Docs](https://docs.aws.amazon.com/lex/latest/dg/API_PutBot.html#lex-PutBot-request-locale). Default is `en-US`. +* `intent` - (Required) A set of Intent objects. Each intent represents a command that a user can express. Attributes are documented under [intent](#intent-1). +* `name` - (Required) The name of the bot that you want to create, case sensitive. +* `nlu_intent_confidence_threshold` - (Optional) Determines the threshold where Amazon Lex will insert the AMAZON.FallbackIntent, AMAZON.KendraSearchIntent, or both when returning alternative intents in a PostContent or PostText response. AMAZON.FallbackIntent and AMAZON.KendraSearchIntent are only inserted if they are configured for the bot. For more information see [Amazon Lex Bot PutBot API Docs](https://docs.aws.amazon.com/lex/latest/dg/API_PutBot.html#lex-PutBot-request-nluIntentConfidenceThreshold) This value requires `enable_model_improvements` to be set to `true` and the default is `0`. +* `process_behavior` - (Optional) If you set the `process_behavior` element to `BUILD`, Amazon Lex builds the bot so that it can be run. If you set the element to `SAVE` Amazon Lex saves the bot, but doesn't build it. Default is `SAVE`. +* `voice_id` - (Optional) The Amazon Polly voice ID that you want Amazon Lex to use for voice interactions with the user. The locale configured for the voice must match the locale of the bot. For more information, see [Available Voices](http://docs.aws.amazon.com/polly/latest/dg/voicelist.html) in the Amazon Polly Developer Guide. + +### intent + +Identifies the specific version of an intent. + +* `intent_name` - (Required) The name of the intent. +* `intent_version` - (Required) The version of the intent. + +### message + +The message object that provides the message text and its type. + +* `content` - (Required) The text of the message. +* `content_type` - (Required) The content type of the message string. +* `group_number` - (Optional) Identifies the message group that the message belongs to. When a group +is assigned to a message, Amazon Lex returns one message from each group in the response. + +### prompt + +Obtains information from the user. To define a prompt, provide one or more messages and specify the +number of attempts to get information from the user. If you provide more than one message, Amazon +Lex chooses one of the messages to use to prompt the user. + +* `max_attempts` - (Required) The number of times to prompt the user for information. +* `message` - (Required) A set of messages, each of which provides a message string and its type. +You can specify the message string in plain text or in Speech Synthesis Markup Language (SSML). +Attributes are documented under [message](#message-2). +* `response_card` - (Optional) The response card. Amazon Lex will substitute session attributes and +slot values into the response card. For more information, see +[Example: Using a Response Card](https://docs.aws.amazon.com/lex/latest/dg/ex-resp-card.html). + +### statement + +A statement is a map with a set of message maps and an optional response card string. Messages +convey information to the user. At runtime, Amazon Lex selects the message to convey. + +* `message` - (Required) A set of messages, each of which provides a message string and its type. You +can specify the message string in plain text or in Speech Synthesis Markup Language (SSML). Attributes +are documented under [message](#message-2). +* `response_card` - (Optional) The response card. Amazon Lex will substitute session attributes and +slot values into the response card. For more information, see +[Example: Using a Response Card](https://docs.aws.amazon.com/lex/latest/dg/ex-resp-card.html). + +### Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 1 mins) Used when creating the bot +* `update` - (Defaults to 1 mins) Used when updating the bot +* `delete` - (Defaults to 5 mins) Used when deleting the bot + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `checksum` - Checksum identifying the version of the bot that was created. The checksum is not +included as an argument because the resource will add it automatically when updating the bot. +* `created_date` - The date when the bot version was created. +* `failure_reason` - If status is FAILED, Amazon Lex provides the reason that it failed to build the bot. +* `last_updated_date` - The date when the $LATEST version of this bot was updated. +* `status` - When you send a request to create or update a bot, Amazon Lex sets the status response +element to BUILDING. After Amazon Lex builds the bot, it sets status to READY. If Amazon Lex can't +build the bot, it sets status to FAILED. Amazon Lex returns the reason for the failure in the +failure_reason response element. +* `version` - The version of the bot. + +## Import + +Bots can be imported using their name. + +``` +$ terraform import aws_lex_bot.order_flowers_bot OrderFlowers +``` From e68a995c0057a9a2f52db8454ab81eb4b9985d39 Mon Sep 17 00:00:00 2001 From: Jack Bruno Date: Sun, 27 Sep 2020 14:32:25 -0600 Subject: [PATCH 2/3] Fix github check tf format and website format --- aws/data_source_aws_lex_bot_test.go | 2 +- website/docs/d/lex_bot.html.markdown | 4 ++-- website/docs/r/lex_bot.html.markdown | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/data_source_aws_lex_bot_test.go b/aws/data_source_aws_lex_bot_test.go index 079f0b14ce8..5f4ed50de8d 100644 --- a/aws/data_source_aws_lex_bot_test.go +++ b/aws/data_source_aws_lex_bot_test.go @@ -84,7 +84,7 @@ func TestAccDataSourceAwsLexBot_withVersion(t *testing.T) { func testAccDataSourceAwsLexBotConfig_basic() string { return ` data "aws_lex_bot" "test" { - name = aws_lex_bot.test.name + name = aws_lex_bot.test.name } ` } diff --git a/website/docs/d/lex_bot.html.markdown b/website/docs/d/lex_bot.html.markdown index 21164d40aa5..eafbd4a75e5 100644 --- a/website/docs/d/lex_bot.html.markdown +++ b/website/docs/d/lex_bot.html.markdown @@ -1,9 +1,9 @@ --- +subcategory: "Lex" layout: "aws" page_title: "AWS: aws_lex_bot" -sidebar_current: "docs-aws-lex-bot" description: |- - Provides details about a specific Lex Bot + Provides details about a specific Lex Bot --- # Data Source: aws_lex_bot diff --git a/website/docs/r/lex_bot.html.markdown b/website/docs/r/lex_bot.html.markdown index c001216fa27..04d7401909f 100644 --- a/website/docs/r/lex_bot.html.markdown +++ b/website/docs/r/lex_bot.html.markdown @@ -1,7 +1,7 @@ --- +subcategory: "Lex" layout: "aws" page_title: "AWS: aws_lex_bot" -sidebar_current: "docs-aws-resource-lex-bot" description: |- Provides an Amazon Lex bot resource. --- From 55c4db89145948663c9eef13443536776c7f509e Mon Sep 17 00:00:00 2001 From: Jack Bruno Date: Sun, 27 Sep 2020 18:23:05 -0600 Subject: [PATCH 3/3] Add more bot resource tests --- aws/resource_aws_lex_bot.go | 38 +- aws/resource_aws_lex_bot_test.go | 812 ++++++++++++++++++++++++++++++- 2 files changed, 830 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_lex_bot.go b/aws/resource_aws_lex_bot.go index f55a947e03e..dadbd03d1b3 100644 --- a/aws/resource_aws_lex_bot.go +++ b/aws/resource_aws_lex_bot.go @@ -68,7 +68,7 @@ func resourceAwsLexBot() *schema.Resource { }, "clarification_prompt": { Type: schema.TypeList, - Required: true, + Optional: true, MinItems: 1, MaxItems: 1, Elem: lexPromptResource, @@ -190,14 +190,24 @@ func resourceAwsLexBotCreate(d *schema.ResourceData, meta interface{}) error { input := &lexmodelbuildingservice.PutBotInput{ AbortStatement: expandLexStatement(d.Get("abort_statement")), ChildDirected: aws.Bool(d.Get("child_directed").(bool)), - ClarificationPrompt: expandLexPrompt(d.Get("clarification_prompt")), CreateVersion: aws.Bool(d.Get("create_version").(bool)), Description: aws.String(d.Get("description").(string)), + EnableModelImprovements: aws.Bool(d.Get("enable_model_improvements").(bool)), IdleSessionTTLInSeconds: aws.Int64(int64(d.Get("idle_session_ttl_in_seconds").(int))), Intents: expandLexIntents(d.Get("intent").(*schema.Set).List()), - Locale: aws.String(d.Get("locale").(string)), Name: aws.String(name), - ProcessBehavior: aws.String(d.Get("process_behavior").(string)), + } + + if v, ok := d.GetOk("clarification_prompt"); ok { + input.ClarificationPrompt = expandLexPrompt(v) + } + + if v, ok := d.GetOk("locale"); ok { + input.Locale = aws.String(v.(string)) + } + + if v, ok := d.GetOk("process_behavior"); ok { + input.ProcessBehavior = aws.String(v.(string)) } if v, ok := d.GetOk("voice_id"); ok { @@ -258,10 +268,8 @@ func resourceAwsLexBotRead(d *schema.ResourceData, meta interface{}) error { processBehavior = v.(string) } - d.Set("abort_statement", flattenLexStatement(resp.AbortStatement)) d.Set("checksum", resp.Checksum) d.Set("child_directed", resp.ChildDirected) - d.Set("clarification_prompt", flattenLexPrompt(resp.ClarificationPrompt)) d.Set("created_date", resp.CreatedDate.Format(time.RFC3339)) d.Set("description", resp.Description) d.Set("detect_sentiment", resp.DetectSentiment) @@ -276,6 +284,14 @@ func resourceAwsLexBotRead(d *schema.ResourceData, meta interface{}) error { d.Set("process_behavior", processBehavior) d.Set("status", resp.Status) + if resp.AbortStatement != nil { + d.Set("abort_statement", flattenLexStatement(resp.AbortStatement)) + } + + if resp.ClarificationPrompt != nil { + d.Set("clarification_prompt", flattenLexPrompt(resp.ClarificationPrompt)) + } + version, err := getLatestLexBotVersion(conn, &lexmodelbuildingservice.GetBotVersionsInput{ Name: aws.String(d.Id()), }) @@ -295,10 +311,8 @@ func resourceAwsLexBotUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lexmodelconn input := &lexmodelbuildingservice.PutBotInput{ - AbortStatement: expandLexStatement(d.Get("abort_statement")), Checksum: aws.String(d.Get("checksum").(string)), ChildDirected: aws.Bool(d.Get("child_directed").(bool)), - ClarificationPrompt: expandLexPrompt(d.Get("clarification_prompt")), CreateVersion: aws.Bool(d.Get("create_version").(bool)), Description: aws.String(d.Get("description").(string)), DetectSentiment: aws.Bool(d.Get("detect_sentiment").(bool)), @@ -311,6 +325,14 @@ func resourceAwsLexBotUpdate(d *schema.ResourceData, meta interface{}) error { ProcessBehavior: aws.String(d.Get("process_behavior").(string)), } + if v, ok := d.GetOk("abort_statement"); ok { + input.AbortStatement = expandLexStatement(v) + } + + if v, ok := d.GetOk("clarification_prompt"); ok { + input.ClarificationPrompt = expandLexPrompt(v) + } + if v, ok := d.GetOk("voice_id"); ok { input.VoiceId = aws.String(v.(string)) } diff --git a/aws/resource_aws_lex_bot_test.go b/aws/resource_aws_lex_bot_test.go index cf83b1923de..3ef5f7e26cd 100644 --- a/aws/resource_aws_lex_bot_test.go +++ b/aws/resource_aws_lex_bot_test.go @@ -55,10 +55,507 @@ func TestAccAwsLexBot_basic(t *testing.T) { ), }, { - ResourceName: rName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"create_version"}, + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_createVersion(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + testAccCheckAwsLexBotNotExists(testBotID, "1"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_createVersion(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + testAccCheckAwsLexBotExistsWithVersion(rName, "1", &v), + resource.TestCheckResourceAttr(rName, "version", "1"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_abortStatement(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_abortStatement(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "abort_statement.#", "1"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.#", "1"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.0.content", "Sorry, I'm not able to assist at this time"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.0.content_type", "PlainText"), + resource.TestCheckNoResourceAttr(rName, "abort_statement.0.message.0.group_number"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.response_card", ""), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_abortStatementUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.#", "2"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.0.content", "Sorry, I'm not able to assist at this time"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.0.content_type", "PlainText"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.0.group_number", "1"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.1.content", "Sorry, I'm not able to assist at this time. Good bye."), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.1.content_type", "PlainText"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.message.1.group_number", "1"), + resource.TestCheckResourceAttr(rName, "abort_statement.0.response_card", "Sorry, I'm not able to assist at this time"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_clarificationPrompt(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_clarificationPrompt(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "clarification_prompt.#", "1"), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.max_attempts", "2"), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.message.#", "1"), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.message.#", "1"), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.message.0.content", "I didn't understand you, what would you like to do?"), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.message.0.content_type", "PlainText"), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.response_card", ""), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_clarificationPromptUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.max_attempts", "3"), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.message.#", "2"), + resource.TestCheckResourceAttr(rName, "clarification_prompt.0.response_card", "I didn't understand you, what would you like to do?"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_childDirected(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_childDirectedUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "child_directed", "true"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_description(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_descriptionUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "description", "Bot to order flowers"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_detectSentiment(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_detectSentimentUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "detect_sentiment", "true"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_enableModelImprovements(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_enableModelImprovementsUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "enable_model_improvements", "true"), + resource.TestCheckResourceAttr(rName, "nlu_intent_confidence_threshold", "0.5"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_idleSessionTtlInSeconds(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_idleSessionTtlInSecondsUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "idle_session_ttl_in_seconds", "600"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_intents(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intentMultiple(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intentMultiple(testBotID), + testAccAwsLexBotConfig_intentsUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "intent.#", "2"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_locale(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_localeUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "locale", "en-GB"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsLexBot_voiceId(t *testing.T) { + var v lexmodelbuildingservice.GetBotOutput + rName := "aws_lex_bot.test" + testBotID := "test_bot_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsLexBotDestroy, + Steps: []resource.TestStep{ + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_basic(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: composeConfig( + testAccAwsLexBotConfig_intent(testBotID), + testAccAwsLexBotConfig_voiceIdUpdate(testBotID), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsLexBotExists(rName, &v), + resource.TestCheckResourceAttr(rName, "voice_id", "Justin"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -169,10 +666,36 @@ func testAccCheckAwsLexBotDestroy(s *terraform.State) error { return nil } -func testAccAwsLexBotConfig_intent(rName string) string { +func testAccAwsLexBotConfig_intent(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_intent" "test" { + name = "%s" + create_version = true + fulfillment_activity { + type = "ReturnIntent" + } + sample_utterances = [ + "I would like to pick up flowers", + ] +} +`, rName) +} + +func testAccAwsLexBotConfig_intentMultiple(rName string) string { return fmt.Sprintf(` resource "aws_lex_intent" "test" { - name = "%s" + name = "%[1]s" + create_version = true + fulfillment_activity { + type = "ReturnIntent" + } + sample_utterances = [ + "I would like to pick up flowers", + ] +} + +resource "aws_lex_intent" "test_2" { + name = "%[1]stwo" create_version = true fulfillment_activity { type = "ReturnIntent" @@ -186,6 +709,95 @@ resource "aws_lex_intent" "test" { func testAccAwsLexBotConfig_basic(rName string) string { return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_createVersion(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + create_version = true + process_behavior = "BUILD" + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_abortStatement(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_abortStatementUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + group_number = 1 + } + message { + content = "Sorry, I'm not able to assist at this time. Good bye." + content_type = "PlainText" + group_number = 1 + } + response_card = "Sorry, I'm not able to assist at this time" + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_clarificationPrompt(rName string) string { + return fmt.Sprintf(` resource "aws_lex_bot" "test" { name = "%s" description = "Bot to order flowers on the behalf of a user" @@ -211,24 +823,200 @@ resource "aws_lex_bot" "test" { `, rName) } -func testAccAwsLexBotConfig_createVersion(rName string) string { +func testAccAwsLexBotConfig_clarificationPromptUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + clarification_prompt { + max_attempts = 3 + message { + content = "I didn't understand you, what would you like to do?" + content_type = "PlainText" + group_number = 1 + } + message { + content = "I didn't understand you, can you re-phrase your request, please?" + content_type = "PlainText" + group_number = 1 + } + response_card = "I didn't understand you, what would you like to do?" + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_childDirectedUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = true + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_descriptionUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers" + child_directed = false + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_detectSentimentUpdate(rName string) string { return fmt.Sprintf(` resource "aws_lex_bot" "test" { name = "%s" description = "Bot to order flowers on the behalf of a user" child_directed = false - create_version = true - process_behavior = "BUILD" + detect_sentiment = true abort_statement { message { content = "Sorry, I'm not able to assist at this time" content_type = "PlainText" } } - clarification_prompt { - max_attempts = 2 + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_enableModelImprovementsUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + enable_model_improvements = true + nlu_intent_confidence_threshold = 0.5 + abort_statement { message { - content = "I didn't understand you, what would you like to do?" + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_idleSessionTtlInSecondsUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + idle_session_ttl_in_seconds = 600 + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_intentsUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } + intent { + intent_name = aws_lex_intent.test_2.name + intent_version = aws_lex_intent.test_2.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_localeUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + enable_model_improvements = true + locale = "en-GB" + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" + content_type = "PlainText" + } + } + intent { + intent_name = aws_lex_intent.test.name + intent_version = aws_lex_intent.test.version + } +} +`, rName) +} + +func testAccAwsLexBotConfig_voiceIdUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_lex_bot" "test" { + name = "%s" + description = "Bot to order flowers on the behalf of a user" + child_directed = false + voice_id = "Justin" + abort_statement { + message { + content = "Sorry, I'm not able to assist at this time" content_type = "PlainText" } }