From 802f50bf7a9aaf6a7bc3527ac55c4e8f5d7ceb22 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Tue, 12 Sep 2023 16:25:37 +0000 Subject: [PATCH] Adding dialogflow_cx_test_case resource (#8879) * Adding dialogflow_cx_test_case resource * Making displayName output-only * Using %parent instead of custom import code * Adding comment clarifying why intent + audio are missing * Making tests exercise updating more fields Signed-off-by: Modular Magician --- .changelog/8879.txt | 3 + google/provider/provider.go | 5 +- .../resource_dialogflow_cx_test_case.go | 1987 +++++++++++++++++ ..._dialogflow_cx_test_case_generated_test.go | 225 ++ .../resource_dialogflow_cx_test_case_test.go | 257 +++ .../r/dialogflow_cx_test_case.html.markdown | 581 +++++ 6 files changed, 3056 insertions(+), 2 deletions(-) create mode 100644 .changelog/8879.txt create mode 100644 google/services/dialogflowcx/resource_dialogflow_cx_test_case.go create mode 100644 google/services/dialogflowcx/resource_dialogflow_cx_test_case_generated_test.go create mode 100644 google/services/dialogflowcx/resource_dialogflow_cx_test_case_test.go create mode 100644 website/docs/r/dialogflow_cx_test_case.html.markdown diff --git a/.changelog/8879.txt b/.changelog/8879.txt new file mode 100644 index 00000000000..5c43e7cd538 --- /dev/null +++ b/.changelog/8879.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_dialogflow_cx_test_case` +``` diff --git a/google/provider/provider.go b/google/provider/provider.go index 891f9b84dc2..67dbf95a4b1 100644 --- a/google/provider/provider.go +++ b/google/provider/provider.go @@ -980,9 +980,9 @@ func DatasourceMapWithErrors() (map[string]*schema.Resource, error) { }) } -// Generated resources: 319 +// Generated resources: 320 // Generated IAM resources: 207 -// Total generated resources: 526 +// Total generated resources: 527 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1290,6 +1290,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_dialogflow_cx_flow": dialogflowcx.ResourceDialogflowCXFlow(), "google_dialogflow_cx_intent": dialogflowcx.ResourceDialogflowCXIntent(), "google_dialogflow_cx_page": dialogflowcx.ResourceDialogflowCXPage(), + "google_dialogflow_cx_test_case": dialogflowcx.ResourceDialogflowCXTestCase(), "google_dialogflow_cx_webhook": dialogflowcx.ResourceDialogflowCXWebhook(), "google_dns_managed_zone": dns.ResourceDNSManagedZone(), "google_dns_managed_zone_iam_binding": tpgiamresource.ResourceIamBinding(dns.DNSManagedZoneIamSchema, dns.DNSManagedZoneIamUpdaterProducer, dns.DNSManagedZoneIdParseFunc), diff --git a/google/services/dialogflowcx/resource_dialogflow_cx_test_case.go b/google/services/dialogflowcx/resource_dialogflow_cx_test_case.go new file mode 100644 index 00000000000..c3cf37732a7 --- /dev/null +++ b/google/services/dialogflowcx/resource_dialogflow_cx_test_case.go @@ -0,0 +1,1987 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package dialogflowcx + +import ( + "encoding/json" + "fmt" + "log" + "reflect" + "regexp" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" + "github.com/hashicorp/terraform-provider-google/google/verify" +) + +func ResourceDialogflowCXTestCase() *schema.Resource { + return &schema.Resource{ + Create: resourceDialogflowCXTestCaseCreate, + Read: resourceDialogflowCXTestCaseRead, + Update: resourceDialogflowCXTestCaseUpdate, + Delete: resourceDialogflowCXTestCaseDelete, + + Importer: &schema.ResourceImporter{ + State: resourceDialogflowCXTestCaseImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(40 * time.Minute), + Update: schema.DefaultTimeout(40 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "display_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 200), + Description: `The human-readable name of the test case, unique within the agent. Limit of 200 characters.`, + }, + "notes": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 400), + Description: `Additional freeform notes about the test case. Limit of 400 characters.`, + }, + "parent": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `The agent to create the test case for. +Format: projects//locations//agents/.`, + }, + "tags": { + Type: schema.TypeList, + Optional: true, + Description: `Tags are short descriptions that users may apply to test cases for organizational and filtering purposes. +Each tag should start with "#" and has a limit of 30 characters`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "test_case_conversation_turns": { + Type: schema.TypeList, + Optional: true, + Description: `The conversation turns uttered when the test case was created, in chronological order. These include the canonical set of agent utterances that should occur when the agent is working properly.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "user_input": { + Type: schema.TypeList, + Optional: true, + Description: `The user input.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable_sentiment_analysis": { + Type: schema.TypeBool, + Optional: true, + Description: `Whether sentiment analysis is enabled.`, + }, + "injected_parameters": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + StateFunc: func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s }, + Description: `Parameters that need to be injected into the conversation during intent detection.`, + }, + "input": { + Type: schema.TypeList, + Optional: true, + Description: `User input. Supports text input, event input, dtmf input in the test case.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dtmf": { + Type: schema.TypeList, + Optional: true, + Description: `The DTMF event to be handled.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "digits": { + Type: schema.TypeString, + Optional: true, + Description: `The dtmf digits.`, + }, + "finish_digit": { + Type: schema.TypeString, + Optional: true, + Description: `The finish digit (if any).`, + }, + }, + }, + }, + "event": { + Type: schema.TypeList, + Optional: true, + Description: `The event to be triggered.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "event": { + Type: schema.TypeString, + Required: true, + Description: `Name of the event.`, + }, + }, + }, + }, + "language_code": { + Type: schema.TypeString, + Optional: true, + Description: `The language of the input. See [Language Support](https://cloud.google.com/dialogflow/cx/docs/reference/language) for a list of the currently supported language codes. +Note that queries in the same session do not necessarily need to specify the same language.`, + }, + "text": { + Type: schema.TypeList, + Optional: true, + Description: `The natural language text to be processed.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "text": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 256), + Description: `The natural language text to be processed. Text length must not exceed 256 characters.`, + }, + }, + }, + }, + }, + }, + }, + "is_webhook_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: `If webhooks should be allowed to trigger in response to the user utterance. Often if parameters are injected, webhooks should not be enabled.`, + }, + }, + }, + }, + "virtual_agent_output": { + Type: schema.TypeList, + Optional: true, + Description: `The virtual agent output.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "current_page": { + Type: schema.TypeList, + Optional: true, + Description: `The [Page](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.flows.pages#Page) on which the utterance was spoken.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: `The unique identifier of the page. +Format: projects//locations//agents//flows//pages/.`, + }, + "display_name": { + Type: schema.TypeString, + Computed: true, + Description: `The human-readable name of the page, unique within the flow.`, + }, + }, + }, + }, + "session_parameters": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + StateFunc: func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s }, + Description: `The session parameters available to the bot at this point.`, + }, + "text_responses": { + Type: schema.TypeList, + Optional: true, + Description: `The text responses from the agent for the turn.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "text": { + Type: schema.TypeList, + Optional: true, + Description: `A collection of text responses.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "triggered_intent": { + Type: schema.TypeList, + Optional: true, + Description: `The [Intent](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.intents#Intent) that triggered the response.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: `The unique identifier of the intent. +Format: projects//locations//agents//intents/.`, + }, + "display_name": { + Type: schema.TypeString, + Computed: true, + Description: `The human-readable name of the intent, unique within the agent.`, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "test_config": { + Type: schema.TypeList, + Optional: true, + Description: `Config for the test case.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "flow": { + Type: schema.TypeString, + Optional: true, + Description: `Flow name to start the test case with. +Format: projects//locations//agents//flows/. +Only one of flow and page should be set to indicate the starting point of the test case. If neither is set, the test case will start with start page on the default start flow.`, + ConflictsWith: []string{"test_config.0.page"}, + }, + "page": { + Type: schema.TypeString, + Optional: true, + Description: `The page to start the test case with. +Format: projects//locations//agents//flows//pages/. +Only one of flow and page should be set to indicate the starting point of the test case. If neither is set, the test case will start with start page on the default start flow.`, + ConflictsWith: []string{"test_config.0.flow"}, + }, + "tracking_parameters": { + Type: schema.TypeList, + Optional: true, + Description: `Session parameters to be compared when calculating differences.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + Description: `When the test was created. A timestamp in RFC3339 text format.`, + }, + "last_test_result": { + Type: schema.TypeList, + Computed: true, + Description: `The latest test result.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "conversation_turns": { + Type: schema.TypeList, + Optional: true, + Description: `The conversation turns uttered during the test case replay in chronological order.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "user_input": { + Type: schema.TypeList, + Optional: true, + Description: `The user input.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable_sentiment_analysis": { + Type: schema.TypeBool, + Optional: true, + Description: `Whether sentiment analysis is enabled.`, + }, + "injected_parameters": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + StateFunc: func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s }, + Description: `Parameters that need to be injected into the conversation during intent detection.`, + }, + "input": { + Type: schema.TypeList, + Optional: true, + Description: `User input. Supports text input, event input, dtmf input in the test case.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dtmf": { + Type: schema.TypeList, + Optional: true, + Description: `The DTMF event to be handled.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "digits": { + Type: schema.TypeString, + Optional: true, + Description: `The dtmf digits.`, + }, + "finish_digit": { + Type: schema.TypeString, + Optional: true, + Description: `The finish digit (if any).`, + }, + }, + }, + }, + "event": { + Type: schema.TypeList, + Optional: true, + Description: `The event to be triggered.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "event": { + Type: schema.TypeString, + Required: true, + Description: `Name of the event.`, + }, + }, + }, + }, + "language_code": { + Type: schema.TypeString, + Optional: true, + Description: `The language of the input. See [Language Support](https://cloud.google.com/dialogflow/cx/docs/reference/language) for a list of the currently supported language codes. +Note that queries in the same session do not necessarily need to specify the same language.`, + }, + "text": { + Type: schema.TypeList, + Optional: true, + Description: `The natural language text to be processed.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "text": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 256), + Description: `The natural language text to be processed. Text length must not exceed 256 characters.`, + }, + }, + }, + }, + }, + }, + }, + "is_webhook_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: `If webhooks should be allowed to trigger in response to the user utterance. Often if parameters are injected, webhooks should not be enabled.`, + }, + }, + }, + }, + "virtual_agent_output": { + Type: schema.TypeList, + Optional: true, + Description: `The virtual agent output.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "current_page": { + Type: schema.TypeList, + Optional: true, + Description: `The [Page](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.flows.pages#Page) on which the utterance was spoken.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "display_name": { + Type: schema.TypeString, + Optional: true, + Description: `The human-readable name of the page, unique within the flow.`, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: `The unique identifier of the page. +Format: projects//locations//agents//flows//pages/.`, + }, + }, + }, + }, + "differences": { + Type: schema.TypeList, + Optional: true, + Description: `The list of differences between the original run and the replay for this output, if any.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Optional: true, + Description: `A human readable description of the diff, showing the actual output vs expected output.`, + }, + "type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidateEnum([]string{"INTENT", "PAGE", "PARAMETERS", "UTTERANCE", "FLOW", ""}), + Description: `The type of diff. +* INTENT: The intent. +* PAGE: The page. +* PARAMETERS: The parameters. +* UTTERANCE: The message utterance. +* FLOW: The flow. Possible values: ["INTENT", "PAGE", "PARAMETERS", "UTTERANCE", "FLOW"]`, + }, + }, + }, + }, + "session_parameters": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + StateFunc: func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s }, + Description: `The session parameters available to the bot at this point.`, + }, + "status": { + Type: schema.TypeList, + Optional: true, + Description: `Response error from the agent in the test result. If set, other output is empty.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeInt, + Optional: true, + Description: `The status code, which should be an enum value of google.rpc.Code.`, + }, + "details": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + StateFunc: func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s }, + Description: `A JSON encoded list of messages that carry the error details.`, + }, + "message": { + Type: schema.TypeString, + Optional: true, + Description: `A developer-facing error message.`, + }, + }, + }, + }, + "text_responses": { + Type: schema.TypeList, + Optional: true, + Description: `The text responses from the agent for the turn.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "text": { + Type: schema.TypeList, + Optional: true, + Description: `A collection of text responses.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "triggered_intent": { + Type: schema.TypeList, + Optional: true, + Description: `The [Intent](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.intents#Intent) that triggered the response.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "display_name": { + Type: schema.TypeString, + Optional: true, + Description: `The human-readable name of the intent, unique within the agent.`, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: `The unique identifier of the intent. +Format: projects//locations//agents//intents/.`, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "environment": { + Type: schema.TypeString, + Optional: true, + Description: `Environment where the test was run. If not set, it indicates the draft environment.`, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: `The resource name for the test case result. +Format: projects//locations//agents//testCases//results/.`, + }, + "test_result": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidateEnum([]string{"PASSED", "FAILED", ""}), + Description: `Whether the test case passed in the agent environment. +* PASSED: The test passed. +* FAILED: The test did not pass. Possible values: ["PASSED", "FAILED"]`, + }, + "test_time": { + Type: schema.TypeString, + Optional: true, + Description: `The time that the test was run. A timestamp in RFC3339 text format.`, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The unique identifier of the test case. +Format: projects//locations//agents//testCases/.`, + }, + }, + UseJSONNumber: true, + } +} + +func resourceDialogflowCXTestCaseCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + tagsProp, err := expandDialogflowCXTestCaseTags(d.Get("tags"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("tags"); !tpgresource.IsEmptyValue(reflect.ValueOf(tagsProp)) && (ok || !reflect.DeepEqual(v, tagsProp)) { + obj["tags"] = tagsProp + } + displayNameProp, err := expandDialogflowCXTestCaseDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + notesProp, err := expandDialogflowCXTestCaseNotes(d.Get("notes"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("notes"); !tpgresource.IsEmptyValue(reflect.ValueOf(notesProp)) && (ok || !reflect.DeepEqual(v, notesProp)) { + obj["notes"] = notesProp + } + testConfigProp, err := expandDialogflowCXTestCaseTestConfig(d.Get("test_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("test_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(testConfigProp)) && (ok || !reflect.DeepEqual(v, testConfigProp)) { + obj["testConfig"] = testConfigProp + } + testCaseConversationTurnsProp, err := expandDialogflowCXTestCaseTestCaseConversationTurns(d.Get("test_case_conversation_turns"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("test_case_conversation_turns"); !tpgresource.IsEmptyValue(reflect.ValueOf(testCaseConversationTurnsProp)) && (ok || !reflect.DeepEqual(v, testCaseConversationTurnsProp)) { + obj["testCaseConversationTurns"] = testCaseConversationTurnsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DialogflowCXBasePath}}{{parent}}/testCases") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new TestCase: %#v", obj) + billingProject := "" + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + // extract location from the parent + location := "" + + if parts := regexp.MustCompile(`locations\/([^\/]*)\/`).FindStringSubmatch(d.Get("parent").(string)); parts != nil { + location = parts[1] + } else { + return fmt.Errorf( + "Saw %s when the parent is expected to contains location %s", + d.Get("parent"), + "projects/{{project}}/locations/{{location}}/...", + ) + } + + url = strings.Replace(url, "-dialogflow", fmt.Sprintf("%s-dialogflow", location), 1) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + }) + if err != nil { + return fmt.Errorf("Error creating TestCase: %s", err) + } + if err := d.Set("name", flattenDialogflowCXTestCaseName(res["name"], d, config)); err != nil { + return fmt.Errorf(`Error setting computed identity field "name": %s`, err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "{{parent}}/testCases/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating TestCase %q: %#v", d.Id(), res) + + return resourceDialogflowCXTestCaseRead(d, meta) +} + +func resourceDialogflowCXTestCaseRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DialogflowCXBasePath}}{{parent}}/testCases/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + // extract location from the parent + location := "" + + if parts := regexp.MustCompile(`locations\/([^\/]*)\/`).FindStringSubmatch(d.Get("parent").(string)); parts != nil { + location = parts[1] + } else { + return fmt.Errorf( + "Saw %s when the parent is expected to contains location %s", + d.Get("parent"), + "projects/{{project}}/locations/{{location}}/...", + ) + } + + url = strings.Replace(url, "-dialogflow", fmt.Sprintf("%s-dialogflow", location), 1) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("DialogflowCXTestCase %q", d.Id())) + } + + if err := d.Set("name", flattenDialogflowCXTestCaseName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading TestCase: %s", err) + } + if err := d.Set("tags", flattenDialogflowCXTestCaseTags(res["tags"], d, config)); err != nil { + return fmt.Errorf("Error reading TestCase: %s", err) + } + if err := d.Set("display_name", flattenDialogflowCXTestCaseDisplayName(res["displayName"], d, config)); err != nil { + return fmt.Errorf("Error reading TestCase: %s", err) + } + if err := d.Set("notes", flattenDialogflowCXTestCaseNotes(res["notes"], d, config)); err != nil { + return fmt.Errorf("Error reading TestCase: %s", err) + } + if err := d.Set("test_config", flattenDialogflowCXTestCaseTestConfig(res["testConfig"], d, config)); err != nil { + return fmt.Errorf("Error reading TestCase: %s", err) + } + if err := d.Set("test_case_conversation_turns", flattenDialogflowCXTestCaseTestCaseConversationTurns(res["testCaseConversationTurns"], d, config)); err != nil { + return fmt.Errorf("Error reading TestCase: %s", err) + } + if err := d.Set("creation_time", flattenDialogflowCXTestCaseCreationTime(res["creationTime"], d, config)); err != nil { + return fmt.Errorf("Error reading TestCase: %s", err) + } + if err := d.Set("last_test_result", flattenDialogflowCXTestCaseLastTestResult(res["lastTestResult"], d, config)); err != nil { + return fmt.Errorf("Error reading TestCase: %s", err) + } + + return nil +} + +func resourceDialogflowCXTestCaseUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + obj := make(map[string]interface{}) + tagsProp, err := expandDialogflowCXTestCaseTags(d.Get("tags"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("tags"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, tagsProp)) { + obj["tags"] = tagsProp + } + displayNameProp, err := expandDialogflowCXTestCaseDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + notesProp, err := expandDialogflowCXTestCaseNotes(d.Get("notes"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("notes"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, notesProp)) { + obj["notes"] = notesProp + } + testConfigProp, err := expandDialogflowCXTestCaseTestConfig(d.Get("test_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("test_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, testConfigProp)) { + obj["testConfig"] = testConfigProp + } + testCaseConversationTurnsProp, err := expandDialogflowCXTestCaseTestCaseConversationTurns(d.Get("test_case_conversation_turns"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("test_case_conversation_turns"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, testCaseConversationTurnsProp)) { + obj["testCaseConversationTurns"] = testCaseConversationTurnsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DialogflowCXBasePath}}{{parent}}/testCases/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating TestCase %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("tags") { + updateMask = append(updateMask, "tags") + } + + if d.HasChange("display_name") { + updateMask = append(updateMask, "displayName") + } + + if d.HasChange("notes") { + updateMask = append(updateMask, "notes") + } + + if d.HasChange("test_config") { + updateMask = append(updateMask, "testConfig") + } + + if d.HasChange("test_case_conversation_turns") { + updateMask = append(updateMask, "testCaseConversationTurns") + } + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // extract location from the parent + location := "" + + if parts := regexp.MustCompile(`locations\/([^\/]*)\/`).FindStringSubmatch(d.Get("parent").(string)); parts != nil { + location = parts[1] + } else { + return fmt.Errorf( + "Saw %s when the parent is expected to contains location %s", + d.Get("parent"), + "projects/{{project}}/locations/{{location}}/...", + ) + } + + url = strings.Replace(url, "-dialogflow", fmt.Sprintf("%s-dialogflow", location), 1) + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + + if err != nil { + return fmt.Errorf("Error updating TestCase %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating TestCase %q: %#v", d.Id(), res) + } + + return resourceDialogflowCXTestCaseRead(d, meta) +} + +func resourceDialogflowCXTestCaseDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + url, err := tpgresource.ReplaceVars(d, config, "{{DialogflowCXBasePath}}{{parent}}/testCases/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + + // extract location from the parent + location := "" + + if parts := regexp.MustCompile(`locations\/([^\/]*)\/`).FindStringSubmatch(d.Get("parent").(string)); parts != nil { + location = parts[1] + } else { + return fmt.Errorf( + "Saw %s when the parent is expected to contains location %s", + d.Get("parent"), + "projects/{{project}}/locations/{{location}}/...", + ) + } + + url = strings.Replace(url, "-dialogflow", fmt.Sprintf("%s-dialogflow", location), 1) + log.Printf("[DEBUG] Deleting TestCase %q", d.Id()) + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "TestCase") + } + + log.Printf("[DEBUG] Finished deleting TestCase %q: %#v", d.Id(), res) + return nil +} + +func resourceDialogflowCXTestCaseImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "(?P.+)/testCases/(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "{{parent}}/testCases/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenDialogflowCXTestCaseName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + return tpgresource.NameFromSelfLinkStateFunc(v) +} + +func flattenDialogflowCXTestCaseTags(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseDisplayName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseNotes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["tracking_parameters"] = + flattenDialogflowCXTestCaseTestConfigTrackingParameters(original["trackingParameters"], d, config) + transformed["flow"] = + flattenDialogflowCXTestCaseTestConfigFlow(original["flow"], d, config) + transformed["page"] = + flattenDialogflowCXTestCaseTestConfigPage(original["page"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestConfigTrackingParameters(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestConfigFlow(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestConfigPage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurns(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "user_input": flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInput(original["userInput"], d, config), + "virtual_agent_output": flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutput(original["virtualAgentOutput"], d, config), + }) + } + return transformed +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInput(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["input"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInput(original["input"], d, config) + transformed["injected_parameters"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInjectedParameters(original["injectedParameters"], d, config) + transformed["is_webhook_enabled"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputIsWebhookEnabled(original["isWebhookEnabled"], d, config) + transformed["enable_sentiment_analysis"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputEnableSentimentAnalysis(original["enableSentimentAnalysis"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInput(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["language_code"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputLanguageCode(original["languageCode"], d, config) + transformed["text"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputText(original["text"], d, config) + transformed["event"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputEvent(original["event"], d, config) + transformed["dtmf"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmf(original["dtmf"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputLanguageCode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputText(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["text"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputTextText(original["text"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputTextText(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputEvent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["event"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputEventEvent(original["event"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputEventEvent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmf(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["digits"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmfDigits(original["digits"], d, config) + transformed["finish_digit"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmfFinishDigit(original["finishDigit"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmfDigits(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmfFinishDigit(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputInjectedParameters(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + b, err := json.Marshal(v) + if err != nil { + // TODO: return error once https://github.com/GoogleCloudPlatform/magic-modules/issues/3257 is fixed. + log.Printf("[ERROR] failed to marshal schema to JSON: %v", err) + } + return string(b) +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputIsWebhookEnabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsUserInputEnableSentimentAnalysis(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutput(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["session_parameters"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputSessionParameters(original["sessionParameters"], d, config) + transformed["triggered_intent"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntent(original["triggeredIntent"], d, config) + transformed["current_page"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPage(original["currentPage"], d, config) + transformed["text_responses"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTextResponses(original["textResponses"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputSessionParameters(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + b, err := json.Marshal(v) + if err != nil { + // TODO: return error once https://github.com/GoogleCloudPlatform/magic-modules/issues/3257 is fixed. + log.Printf("[ERROR] failed to marshal schema to JSON: %v", err) + } + return string(b) +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntentName(original["name"], d, config) + transformed["display_name"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntentDisplayName(original["displayName"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntentName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntentDisplayName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPageName(original["name"], d, config) + transformed["display_name"] = + flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPageDisplayName(original["displayName"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPageName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPageDisplayName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTextResponses(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "text": flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTextResponsesText(original["text"], d, config), + }) + } + return transformed +} +func flattenDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTextResponsesText(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseCreationTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResult(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenDialogflowCXTestCaseLastTestResultName(original["name"], d, config) + transformed["environment"] = + flattenDialogflowCXTestCaseLastTestResultEnvironment(original["environment"], d, config) + transformed["conversation_turns"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurns(original["conversationTurns"], d, config) + transformed["test_result"] = + flattenDialogflowCXTestCaseLastTestResultTestResult(original["testResult"], d, config) + transformed["test_time"] = + flattenDialogflowCXTestCaseLastTestResultTestTime(original["testTime"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultEnvironment(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurns(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "user_input": flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInput(original["userInput"], d, config), + "virtual_agent_output": flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutput(original["virtualAgentOutput"], d, config), + }) + } + return transformed +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInput(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["input"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInput(original["input"], d, config) + transformed["injected_parameters"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInjectedParameters(original["injectedParameters"], d, config) + transformed["is_webhook_enabled"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputIsWebhookEnabled(original["isWebhookEnabled"], d, config) + transformed["enable_sentiment_analysis"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputEnableSentimentAnalysis(original["enableSentimentAnalysis"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInput(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["language_code"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputLanguageCode(original["languageCode"], d, config) + transformed["text"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputText(original["text"], d, config) + transformed["event"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputEvent(original["event"], d, config) + transformed["dtmf"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputDtmf(original["dtmf"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputLanguageCode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputText(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["text"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputTextText(original["text"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputTextText(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputEvent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["event"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputEventEvent(original["event"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputEventEvent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputDtmf(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["digits"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputDtmfDigits(original["digits"], d, config) + transformed["finish_digit"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputDtmfFinishDigit(original["finishDigit"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputDtmfDigits(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInputDtmfFinishDigit(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputInjectedParameters(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + b, err := json.Marshal(v) + if err != nil { + // TODO: return error once https://github.com/GoogleCloudPlatform/magic-modules/issues/3257 is fixed. + log.Printf("[ERROR] failed to marshal schema to JSON: %v", err) + } + return string(b) +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputIsWebhookEnabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsUserInputEnableSentimentAnalysis(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutput(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["session_parameters"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputSessionParameters(original["sessionParameters"], d, config) + transformed["differences"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputDifferences(original["differences"], d, config) + transformed["triggered_intent"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTriggeredIntent(original["triggeredIntent"], d, config) + transformed["current_page"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputCurrentPage(original["currentPage"], d, config) + transformed["text_responses"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTextResponses(original["textResponses"], d, config) + transformed["status"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputStatus(original["status"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputSessionParameters(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + b, err := json.Marshal(v) + if err != nil { + // TODO: return error once https://github.com/GoogleCloudPlatform/magic-modules/issues/3257 is fixed. + log.Printf("[ERROR] failed to marshal schema to JSON: %v", err) + } + return string(b) +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputDifferences(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "type": flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputDifferencesType(original["type"], d, config), + "description": flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputDifferencesDescription(original["description"], d, config), + }) + } + return transformed +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputDifferencesType(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputDifferencesDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTriggeredIntent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTriggeredIntentName(original["name"], d, config) + transformed["display_name"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTriggeredIntentDisplayName(original["displayName"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTriggeredIntentName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTriggeredIntentDisplayName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputCurrentPage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputCurrentPageName(original["name"], d, config) + transformed["display_name"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputCurrentPageDisplayName(original["displayName"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputCurrentPageName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputCurrentPageDisplayName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTextResponses(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "text": flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTextResponsesText(original["text"], d, config), + }) + } + return transformed +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputTextResponsesText(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputStatus(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["code"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputStatusCode(original["code"], d, config) + transformed["message"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputStatusMessage(original["message"], d, config) + transformed["details"] = + flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputStatusDetails(original["details"], d, config) + return []interface{}{transformed} +} +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputStatusCode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputStatusMessage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultConversationTurnsVirtualAgentOutputStatusDetails(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + b, err := json.Marshal(v) + if err != nil { + // TODO: return error once https://github.com/GoogleCloudPlatform/magic-modules/issues/3257 is fixed. + log.Printf("[ERROR] failed to marshal schema to JSON: %v", err) + } + return string(b) +} + +func flattenDialogflowCXTestCaseLastTestResultTestResult(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDialogflowCXTestCaseLastTestResultTestTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandDialogflowCXTestCaseTags(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseNotes(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedTrackingParameters, err := expandDialogflowCXTestCaseTestConfigTrackingParameters(original["tracking_parameters"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTrackingParameters); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["trackingParameters"] = transformedTrackingParameters + } + + transformedFlow, err := expandDialogflowCXTestCaseTestConfigFlow(original["flow"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedFlow); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["flow"] = transformedFlow + } + + transformedPage, err := expandDialogflowCXTestCaseTestConfigPage(original["page"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPage); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["page"] = transformedPage + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestConfigTrackingParameters(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestConfigFlow(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestConfigPage(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurns(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedUserInput, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInput(original["user_input"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedUserInput); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["userInput"] = transformedUserInput + } + + transformedVirtualAgentOutput, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutput(original["virtual_agent_output"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedVirtualAgentOutput); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["virtualAgentOutput"] = transformedVirtualAgentOutput + } + + req = append(req, transformed) + } + return req, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInput(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedInput, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInput(original["input"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedInput); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["input"] = transformedInput + } + + transformedInjectedParameters, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInjectedParameters(original["injected_parameters"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedInjectedParameters); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["injectedParameters"] = transformedInjectedParameters + } + + transformedIsWebhookEnabled, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputIsWebhookEnabled(original["is_webhook_enabled"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIsWebhookEnabled); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["isWebhookEnabled"] = transformedIsWebhookEnabled + } + + transformedEnableSentimentAnalysis, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputEnableSentimentAnalysis(original["enable_sentiment_analysis"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEnableSentimentAnalysis); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["enableSentimentAnalysis"] = transformedEnableSentimentAnalysis + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInput(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedLanguageCode, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputLanguageCode(original["language_code"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLanguageCode); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["languageCode"] = transformedLanguageCode + } + + transformedText, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputText(original["text"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedText); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["text"] = transformedText + } + + transformedEvent, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputEvent(original["event"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEvent); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["event"] = transformedEvent + } + + transformedDtmf, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmf(original["dtmf"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDtmf); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["dtmf"] = transformedDtmf + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputLanguageCode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputText(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedText, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputTextText(original["text"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedText); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["text"] = transformedText + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputTextText(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputEvent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedEvent, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputEventEvent(original["event"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEvent); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["event"] = transformedEvent + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputEventEvent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmf(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDigits, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmfDigits(original["digits"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDigits); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["digits"] = transformedDigits + } + + transformedFinishDigit, err := expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmfFinishDigit(original["finish_digit"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedFinishDigit); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["finishDigit"] = transformedFinishDigit + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmfDigits(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInputDtmfFinishDigit(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputInjectedParameters(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + b := []byte(v.(string)) + if len(b) == 0 { + return nil, nil + } + m := make(map[string]interface{}) + if err := json.Unmarshal(b, &m); err != nil { + return nil, err + } + return m, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputIsWebhookEnabled(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsUserInputEnableSentimentAnalysis(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutput(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSessionParameters, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputSessionParameters(original["session_parameters"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSessionParameters); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["sessionParameters"] = transformedSessionParameters + } + + transformedTriggeredIntent, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntent(original["triggered_intent"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTriggeredIntent); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["triggeredIntent"] = transformedTriggeredIntent + } + + transformedCurrentPage, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPage(original["current_page"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCurrentPage); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["currentPage"] = transformedCurrentPage + } + + transformedTextResponses, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTextResponses(original["text_responses"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTextResponses); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["textResponses"] = transformedTextResponses + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputSessionParameters(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + b := []byte(v.(string)) + if len(b) == 0 { + return nil, nil + } + m := make(map[string]interface{}) + if err := json.Unmarshal(b, &m); err != nil { + return nil, err + } + return m, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedName, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntentName(original["name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedName); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["name"] = transformedName + } + + transformedDisplayName, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntentDisplayName(original["display_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDisplayName); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["displayName"] = transformedDisplayName + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntentName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTriggeredIntentDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPage(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedName, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPageName(original["name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedName); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["name"] = transformedName + } + + transformedDisplayName, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPageDisplayName(original["display_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDisplayName); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["displayName"] = transformedDisplayName + } + + return transformed, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPageName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputCurrentPageDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTextResponses(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedText, err := expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTextResponsesText(original["text"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedText); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["text"] = transformedText + } + + req = append(req, transformed) + } + return req, nil +} + +func expandDialogflowCXTestCaseTestCaseConversationTurnsVirtualAgentOutputTextResponsesText(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/google/services/dialogflowcx/resource_dialogflow_cx_test_case_generated_test.go b/google/services/dialogflowcx/resource_dialogflow_cx_test_case_generated_test.go new file mode 100644 index 00000000000..c0973a40b9f --- /dev/null +++ b/google/services/dialogflowcx/resource_dialogflow_cx_test_case_generated_test.go @@ -0,0 +1,225 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package dialogflowcx_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func TestAccDialogflowCXTestCase_dialogflowcxTestCaseFullExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckDialogflowCXTestCaseDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDialogflowCXTestCase_dialogflowcxTestCaseFullExample(context), + }, + { + ResourceName: "google_dialogflow_cx_test_case.basic_test_case", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"parent"}, + }, + }, + }) +} + +func testAccDialogflowCXTestCase_dialogflowcxTestCaseFullExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dialogflow_cx_agent" "agent" { + display_name = "tf-test-dialogflowcx-agent%{random_suffix}" + location = "global" + default_language_code = "en" + supported_language_codes = ["fr", "de", "es"] + time_zone = "America/New_York" + description = "Example description." + avatar_uri = "https://storage.cloud.google.com/dialogflow-test-host-image/cloud-logo.png" + enable_stackdriver_logging = true + enable_spell_correction = true + speech_to_text_settings { + enable_speech_adaptation = true + } +} + +resource "google_dialogflow_cx_page" "page" { + parent = google_dialogflow_cx_agent.agent.start_flow + display_name = "MyPage" + + transition_routes { + intent = google_dialogflow_cx_intent.intent.id + trigger_fulfillment { + messages { + text { + text = ["Training phrase response"] + } + } + } + } + + event_handlers { + event = "some-event" + trigger_fulfillment { + messages { + text { + text = ["Handling some event"] + } + } + } + } +} + +resource "google_dialogflow_cx_intent" "intent" { + parent = google_dialogflow_cx_agent.agent.id + display_name = "MyIntent" + priority = 1 + training_phrases { + parts { + text = "training phrase" + } + repeat_count = 1 + } +} + +resource "google_dialogflow_cx_test_case" "basic_test_case" { + parent = google_dialogflow_cx_agent.agent.id + display_name = "MyTestCase" + tags = ["#tag1"] + notes = "demonstrates a simple training phrase response" + + test_config { + tracking_parameters = ["some_param"] + page = google_dialogflow_cx_page.page.id + } + + test_case_conversation_turns { + user_input { + input { + language_code = "en" + text { + text = "training phrase" + } + } + injected_parameters = jsonencode({ some_param = "1" }) + is_webhook_enabled = true + enable_sentiment_analysis = true + } + virtual_agent_output { + session_parameters = jsonencode({ some_param = "1" }) + triggered_intent { + name = google_dialogflow_cx_intent.intent.id + } + current_page { + name = google_dialogflow_cx_page.page.id + } + text_responses { + text = ["Training phrase response"] + } + } + } + + test_case_conversation_turns { + user_input { + input { + event { + event = "some-event" + } + } + } + virtual_agent_output { + current_page { + name = google_dialogflow_cx_page.page.id + } + text_responses { + text = ["Handling some event"] + } + } + } + + test_case_conversation_turns { + user_input { + input { + dtmf { + digits = "12" + finish_digit = "3" + } + } + } + virtual_agent_output { + text_responses { + text = ["I didn't get that. Can you say it again?"] + } + } + } +} +`, context) +} + +func testAccCheckDialogflowCXTestCaseDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_dialogflow_cx_test_case" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{DialogflowCXBasePath}}{{parent}}/testCases/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("DialogflowCXTestCase still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/services/dialogflowcx/resource_dialogflow_cx_test_case_test.go b/google/services/dialogflowcx/resource_dialogflow_cx_test_case_test.go new file mode 100644 index 00000000000..d0552caf489 --- /dev/null +++ b/google/services/dialogflowcx/resource_dialogflow_cx_test_case_test.go @@ -0,0 +1,257 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package dialogflowcx_test + +import ( + "testing" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDialogflowCXTestCase_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "billing_account": envvar.GetTestBillingAccountFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDialogflowCXTestCase_full(context), + }, + { + ResourceName: "google_dialogflow_cx_test_case.basic_test_case", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccDialogflowCXTestCase_update(context), + }, + { + ResourceName: "google_dialogflow_cx_test_case.basic_test_case", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccDialogflowCXTestCase_full(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dialogflow_cx_agent" "agent" { + display_name = "tf-test-dialogflowcx-agent%{random_suffix}" + location = "global" + default_language_code = "en" + supported_language_codes = ["fr", "de", "es"] + time_zone = "America/New_York" + description = "Example description." + avatar_uri = "https://storage.cloud.google.com/dialogflow-test-host-image/cloud-logo.png" + enable_stackdriver_logging = true + enable_spell_correction = true + speech_to_text_settings { + enable_speech_adaptation = true + } +} + +resource "google_dialogflow_cx_page" "page" { + parent = google_dialogflow_cx_agent.agent.start_flow + display_name = "MyPage" + + transition_routes { + intent = google_dialogflow_cx_intent.intent.id + trigger_fulfillment { + messages { + text { + text = ["Training phrase response"] + } + } + } + } + + event_handlers { + event = "some-event" + trigger_fulfillment { + messages { + text { + text = ["Handling some event"] + } + } + } + } +} + +resource "google_dialogflow_cx_intent" "intent" { + parent = google_dialogflow_cx_agent.agent.id + display_name = "MyIntent" + priority = 1 + training_phrases { + parts { + text = "training phrase" + } + repeat_count = 1 + } +} + +resource "google_dialogflow_cx_test_case" "basic_test_case" { + parent = google_dialogflow_cx_agent.agent.id + display_name = "MyTestCase" + + test_config { + tracking_parameters = [] + flow = google_dialogflow_cx_agent.agent.start_flow + } + + test_case_conversation_turns { + user_input { + input { + language_code = "en" + text { + text = "some phrase" + } + } + } + virtual_agent_output { + text_responses { + text = ["Some response"] + } + } + } +}`, context) +} + +func testAccDialogflowCXTestCase_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dialogflow_cx_agent" "agent" { + display_name = "tf-test-dialogflowcx-agent%{random_suffix}" + location = "global" + default_language_code = "en" + supported_language_codes = ["fr", "de", "es"] + time_zone = "America/New_York" + description = "Example description." + avatar_uri = "https://storage.cloud.google.com/dialogflow-test-host-image/cloud-logo.png" + enable_stackdriver_logging = true + enable_spell_correction = true + speech_to_text_settings { + enable_speech_adaptation = true + } +} + +resource "google_dialogflow_cx_page" "page" { + parent = google_dialogflow_cx_agent.agent.start_flow + display_name = "MyPage" + + transition_routes { + intent = google_dialogflow_cx_intent.intent.id + trigger_fulfillment { + messages { + text { + text = ["Training phrase response"] + } + } + } + } + + event_handlers { + event = "some-event" + trigger_fulfillment { + messages { + text { + text = ["Handling some event"] + } + } + } + } +} + +resource "google_dialogflow_cx_intent" "intent" { + parent = google_dialogflow_cx_agent.agent.id + display_name = "MyIntent" + priority = 1 + training_phrases { + parts { + text = "training phrase" + } + repeat_count = 1 + } +} + +resource "google_dialogflow_cx_test_case" "basic_test_case" { + parent = google_dialogflow_cx_agent.agent.id + display_name = "MyTestCase" + tags = ["#tag1"] + notes = "demonstrates a simple training phrase response" + + test_config { + tracking_parameters = ["some_param"] + page = google_dialogflow_cx_page.page.id + } + + test_case_conversation_turns { + user_input { + input { + language_code = "en" + text { + text = "training phrase" + } + } + injected_parameters = jsonencode({ some_param = "1" }) + is_webhook_enabled = true + enable_sentiment_analysis = true + } + virtual_agent_output { + session_parameters = jsonencode({ some_param = "1" }) + triggered_intent { + name = google_dialogflow_cx_intent.intent.id + } + current_page { + name = google_dialogflow_cx_page.page.id + } + text_responses { + text = ["Training phrase response"] + } + } + } + + test_case_conversation_turns { + user_input { + input { + event { + event = "some-event" + } + } + } + virtual_agent_output { + current_page { + name = google_dialogflow_cx_page.page.id + } + text_responses { + text = ["Handling some event"] + } + } + } + + test_case_conversation_turns { + user_input { + input { + dtmf { + digits = "12" + finish_digit = "3" + } + } + } + virtual_agent_output { + text_responses { + text = ["I didn't get that. Can you say it again?"] + } + } + } +}`, context) +} diff --git a/website/docs/r/dialogflow_cx_test_case.html.markdown b/website/docs/r/dialogflow_cx_test_case.html.markdown new file mode 100644 index 00000000000..1020a298dbc --- /dev/null +++ b/website/docs/r/dialogflow_cx_test_case.html.markdown @@ -0,0 +1,581 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Dialogflow CX" +description: |- + You can use the built-in test feature to uncover bugs and prevent regressions. +--- + +# google\_dialogflow\_cx\_test\_case + +You can use the built-in test feature to uncover bugs and prevent regressions. A test execution verifies that agent responses have not changed for end-user inputs defined in the test case. + + +To get more information about TestCase, see: + +* [API documentation](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.testCases) +* How-to Guides + * [Official Documentation](https://cloud.google.com/dialogflow/cx/docs) + + +## Example Usage - Dialogflowcx Test Case Full + + +```hcl +resource "google_dialogflow_cx_agent" "agent" { + display_name = "dialogflowcx-agent" + location = "global" + default_language_code = "en" + supported_language_codes = ["fr", "de", "es"] + time_zone = "America/New_York" + description = "Example description." + avatar_uri = "https://storage.cloud.google.com/dialogflow-test-host-image/cloud-logo.png" + enable_stackdriver_logging = true + enable_spell_correction = true + speech_to_text_settings { + enable_speech_adaptation = true + } +} + +resource "google_dialogflow_cx_page" "page" { + parent = google_dialogflow_cx_agent.agent.start_flow + display_name = "MyPage" + + transition_routes { + intent = google_dialogflow_cx_intent.intent.id + trigger_fulfillment { + messages { + text { + text = ["Training phrase response"] + } + } + } + } + + event_handlers { + event = "some-event" + trigger_fulfillment { + messages { + text { + text = ["Handling some event"] + } + } + } + } +} + +resource "google_dialogflow_cx_intent" "intent" { + parent = google_dialogflow_cx_agent.agent.id + display_name = "MyIntent" + priority = 1 + training_phrases { + parts { + text = "training phrase" + } + repeat_count = 1 + } +} + +resource "google_dialogflow_cx_test_case" "basic_test_case" { + parent = google_dialogflow_cx_agent.agent.id + display_name = "MyTestCase" + tags = ["#tag1"] + notes = "demonstrates a simple training phrase response" + + test_config { + tracking_parameters = ["some_param"] + page = google_dialogflow_cx_page.page.id + } + + test_case_conversation_turns { + user_input { + input { + language_code = "en" + text { + text = "training phrase" + } + } + injected_parameters = jsonencode({ some_param = "1" }) + is_webhook_enabled = true + enable_sentiment_analysis = true + } + virtual_agent_output { + session_parameters = jsonencode({ some_param = "1" }) + triggered_intent { + name = google_dialogflow_cx_intent.intent.id + } + current_page { + name = google_dialogflow_cx_page.page.id + } + text_responses { + text = ["Training phrase response"] + } + } + } + + test_case_conversation_turns { + user_input { + input { + event { + event = "some-event" + } + } + } + virtual_agent_output { + current_page { + name = google_dialogflow_cx_page.page.id + } + text_responses { + text = ["Handling some event"] + } + } + } + + test_case_conversation_turns { + user_input { + input { + dtmf { + digits = "12" + finish_digit = "3" + } + } + } + virtual_agent_output { + text_responses { + text = ["I didn't get that. Can you say it again?"] + } + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `display_name` - + (Required) + The human-readable name of the test case, unique within the agent. Limit of 200 characters. + + +- - - + + +* `tags` - + (Optional) + Tags are short descriptions that users may apply to test cases for organizational and filtering purposes. + Each tag should start with "#" and has a limit of 30 characters + +* `notes` - + (Optional) + Additional freeform notes about the test case. Limit of 400 characters. + +* `test_config` - + (Optional) + Config for the test case. + Structure is [documented below](#nested_test_config). + +* `test_case_conversation_turns` - + (Optional) + The conversation turns uttered when the test case was created, in chronological order. These include the canonical set of agent utterances that should occur when the agent is working properly. + Structure is [documented below](#nested_test_case_conversation_turns). + +* `parent` - + (Optional) + The agent to create the test case for. + Format: projects//locations//agents/. + + +The `test_config` block supports: + +* `tracking_parameters` - + (Optional) + Session parameters to be compared when calculating differences. + +* `flow` - + (Optional) + Flow name to start the test case with. + Format: projects//locations//agents//flows/. + Only one of flow and page should be set to indicate the starting point of the test case. If neither is set, the test case will start with start page on the default start flow. + +* `page` - + (Optional) + The page to start the test case with. + Format: projects//locations//agents//flows//pages/. + Only one of flow and page should be set to indicate the starting point of the test case. If neither is set, the test case will start with start page on the default start flow. + +The `test_case_conversation_turns` block supports: + +* `user_input` - + (Optional) + The user input. + Structure is [documented below](#nested_user_input). + +* `virtual_agent_output` - + (Optional) + The virtual agent output. + Structure is [documented below](#nested_virtual_agent_output). + + +The `user_input` block supports: + +* `input` - + (Optional) + User input. Supports text input, event input, dtmf input in the test case. + Structure is [documented below](#nested_input). + +* `injected_parameters` - + (Optional) + Parameters that need to be injected into the conversation during intent detection. + +* `is_webhook_enabled` - + (Optional) + If webhooks should be allowed to trigger in response to the user utterance. Often if parameters are injected, webhooks should not be enabled. + +* `enable_sentiment_analysis` - + (Optional) + Whether sentiment analysis is enabled. + + +The `input` block supports: + +* `language_code` - + (Optional) + The language of the input. See [Language Support](https://cloud.google.com/dialogflow/cx/docs/reference/language) for a list of the currently supported language codes. + Note that queries in the same session do not necessarily need to specify the same language. + +* `text` - + (Optional) + The natural language text to be processed. + Structure is [documented below](#nested_text). + +* `event` - + (Optional) + The event to be triggered. + Structure is [documented below](#nested_event). + +* `dtmf` - + (Optional) + The DTMF event to be handled. + Structure is [documented below](#nested_dtmf). + + +The `text` block supports: + +* `text` - + (Required) + The natural language text to be processed. Text length must not exceed 256 characters. + +The `event` block supports: + +* `event` - + (Required) + Name of the event. + +The `dtmf` block supports: + +* `digits` - + (Optional) + The dtmf digits. + +* `finish_digit` - + (Optional) + The finish digit (if any). + +The `virtual_agent_output` block supports: + +* `session_parameters` - + (Optional) + The session parameters available to the bot at this point. + +* `triggered_intent` - + (Optional) + The [Intent](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.intents#Intent) that triggered the response. + Structure is [documented below](#nested_triggered_intent). + +* `current_page` - + (Optional) + The [Page](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.flows.pages#Page) on which the utterance was spoken. + Structure is [documented below](#nested_current_page). + +* `text_responses` - + (Optional) + The text responses from the agent for the turn. + Structure is [documented below](#nested_text_responses). + + +The `triggered_intent` block supports: + +* `name` - + (Optional) + The unique identifier of the intent. + Format: projects//locations//agents//intents/. + +* `display_name` - + (Output) + The human-readable name of the intent, unique within the agent. + +The `current_page` block supports: + +* `name` - + (Optional) + The unique identifier of the page. + Format: projects//locations//agents//flows//pages/. + +* `display_name` - + (Output) + The human-readable name of the page, unique within the flow. + +The `text_responses` block supports: + +* `text` - + (Optional) + A collection of text responses. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `{{parent}}/testCases/{{name}}` + +* `name` - + The unique identifier of the test case. + Format: projects//locations//agents//testCases/. + +* `creation_time` - + When the test was created. A timestamp in RFC3339 text format. + +* `last_test_result` - + The latest test result. + Structure is [documented below](#nested_last_test_result). + + +The `last_test_result` block contains: + +* `name` - + (Optional) + The resource name for the test case result. + Format: projects//locations//agents//testCases//results/. + +* `environment` - + (Optional) + Environment where the test was run. If not set, it indicates the draft environment. + +* `conversation_turns` - + (Optional) + The conversation turns uttered during the test case replay in chronological order. + Structure is [documented below](#nested_conversation_turns). + +* `test_result` - + (Optional) + Whether the test case passed in the agent environment. + * PASSED: The test passed. + * FAILED: The test did not pass. + Possible values are: `PASSED`, `FAILED`. + +* `test_time` - + (Optional) + The time that the test was run. A timestamp in RFC3339 text format. + + +The `conversation_turns` block supports: + +* `user_input` - + (Optional) + The user input. + Structure is [documented below](#nested_user_input). + +* `virtual_agent_output` - + (Optional) + The virtual agent output. + Structure is [documented below](#nested_virtual_agent_output). + + +The `user_input` block supports: + +* `input` - + (Optional) + User input. Supports text input, event input, dtmf input in the test case. + Structure is [documented below](#nested_input). + +* `injected_parameters` - + (Optional) + Parameters that need to be injected into the conversation during intent detection. + +* `is_webhook_enabled` - + (Optional) + If webhooks should be allowed to trigger in response to the user utterance. Often if parameters are injected, webhooks should not be enabled. + +* `enable_sentiment_analysis` - + (Optional) + Whether sentiment analysis is enabled. + + +The `input` block supports: + +* `language_code` - + (Optional) + The language of the input. See [Language Support](https://cloud.google.com/dialogflow/cx/docs/reference/language) for a list of the currently supported language codes. + Note that queries in the same session do not necessarily need to specify the same language. + +* `text` - + (Optional) + The natural language text to be processed. + Structure is [documented below](#nested_text). + +* `event` - + (Optional) + The event to be triggered. + Structure is [documented below](#nested_event). + +* `dtmf` - + (Optional) + The DTMF event to be handled. + Structure is [documented below](#nested_dtmf). + + +The `text` block supports: + +* `text` - + (Required) + The natural language text to be processed. Text length must not exceed 256 characters. + +The `event` block supports: + +* `event` - + (Required) + Name of the event. + +The `dtmf` block supports: + +* `digits` - + (Optional) + The dtmf digits. + +* `finish_digit` - + (Optional) + The finish digit (if any). + +The `virtual_agent_output` block supports: + +* `session_parameters` - + (Optional) + The session parameters available to the bot at this point. + +* `differences` - + (Optional) + The list of differences between the original run and the replay for this output, if any. + Structure is [documented below](#nested_differences). + +* `triggered_intent` - + (Optional) + The [Intent](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.intents#Intent) that triggered the response. + Structure is [documented below](#nested_triggered_intent). + +* `current_page` - + (Optional) + The [Page](https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/projects.locations.agents.flows.pages#Page) on which the utterance was spoken. + Structure is [documented below](#nested_current_page). + +* `text_responses` - + (Optional) + The text responses from the agent for the turn. + Structure is [documented below](#nested_text_responses). + +* `status` - + (Optional) + Response error from the agent in the test result. If set, other output is empty. + Structure is [documented below](#nested_status). + + +The `differences` block supports: + +* `type` - + (Optional) + The type of diff. + * INTENT: The intent. + * PAGE: The page. + * PARAMETERS: The parameters. + * UTTERANCE: The message utterance. + * FLOW: The flow. + Possible values are: `INTENT`, `PAGE`, `PARAMETERS`, `UTTERANCE`, `FLOW`. + +* `description` - + (Optional) + A human readable description of the diff, showing the actual output vs expected output. + +The `triggered_intent` block supports: + +* `name` - + (Optional) + The unique identifier of the intent. + Format: projects//locations//agents//intents/. + +* `display_name` - + (Optional) + The human-readable name of the intent, unique within the agent. + +The `current_page` block supports: + +* `name` - + (Optional) + The unique identifier of the page. + Format: projects//locations//agents//flows//pages/. + +* `display_name` - + (Optional) + The human-readable name of the page, unique within the flow. + +The `text_responses` block supports: + +* `text` - + (Optional) + A collection of text responses. + +The `status` block supports: + +* `code` - + (Optional) + The status code, which should be an enum value of google.rpc.Code. + +* `message` - + (Optional) + A developer-facing error message. + +* `details` - + (Optional) + A JSON encoded list of messages that carry the error details. + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 40 minutes. +- `update` - Default is 40 minutes. +- `delete` - Default is 20 minutes. + +## Import + + +TestCase can be imported using any of these accepted formats: + +``` +$ terraform import google_dialogflow_cx_test_case.default {{parent}}/testCases/{{name}} +```