// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.cloud.dialogflow.cx.v3beta1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/dialogflow/cx/v3beta1/flow.proto";
import "google/cloud/dialogflow/cx/v3beta1/intent.proto";
import "google/cloud/dialogflow/cx/v3beta1/page.proto";
import "google/cloud/dialogflow/cx/v3beta1/response_message.proto";
import "google/cloud/dialogflow/cx/v3beta1/session.proto";
import "google/cloud/dialogflow/cx/v3beta1/transition_route_group.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";

option csharp_namespace = "Google.Cloud.Dialogflow.Cx.V3Beta1";
option go_package = "cloud.google.com/go/dialogflow/cx/apiv3beta1/cxpb;cxpb";
option java_multiple_files = true;
option java_outer_classname = "TestCaseProto";
option java_package = "com.google.cloud.dialogflow.cx.v3beta1";
option objc_class_prefix = "DF";
option ruby_package = "Google::Cloud::Dialogflow::CX::V3beta1";

// Service for managing [Test
// Cases][google.cloud.dialogflow.cx.v3beta1.TestCase] and [Test Case
// Results][google.cloud.dialogflow.cx.v3beta1.TestCaseResult].
service TestCases {
  option (google.api.default_host) = "dialogflow.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform,"
      "https://www.googleapis.com/auth/dialogflow";

  // Fetches a list of test cases for a given agent.
  rpc ListTestCases(ListTestCasesRequest) returns (ListTestCasesResponse) {
    option (google.api.http) = {
      get: "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases"
    };
    option (google.api.method_signature) = "parent";
  }

  // Batch deletes test cases.
  rpc BatchDeleteTestCases(BatchDeleteTestCasesRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:batchDelete"
      body: "*"
    };
    option (google.api.method_signature) = "parent";
  }

  // Gets a test case.
  rpc GetTestCase(GetTestCaseRequest) returns (TestCase) {
    option (google.api.http) = {
      get: "/v3beta1/{name=projects/*/locations/*/agents/*/testCases/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a test case for the given agent.
  rpc CreateTestCase(CreateTestCaseRequest) returns (TestCase) {
    option (google.api.http) = {
      post: "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases"
      body: "test_case"
    };
    option (google.api.method_signature) = "parent,test_case";
  }

  // Updates the specified test case.
  rpc UpdateTestCase(UpdateTestCaseRequest) returns (TestCase) {
    option (google.api.http) = {
      patch: "/v3beta1/{test_case.name=projects/*/locations/*/agents/*/testCases/*}"
      body: "test_case"
    };
    option (google.api.method_signature) = "test_case,update_mask";
  }

  // Kicks off a test case run.
  //
  // This method is a [long-running
  // operation](https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation).
  // The returned `Operation` type has the following method-specific fields:
  //
  // - `metadata`:
  // [RunTestCaseMetadata][google.cloud.dialogflow.cx.v3beta1.RunTestCaseMetadata]
  // - `response`:
  // [RunTestCaseResponse][google.cloud.dialogflow.cx.v3beta1.RunTestCaseResponse]
  rpc RunTestCase(RunTestCaseRequest) returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v3beta1/{name=projects/*/locations/*/agents/*/testCases/*}:run"
      body: "*"
    };
    option (google.longrunning.operation_info) = {
      response_type: "RunTestCaseResponse"
      metadata_type: "RunTestCaseMetadata"
    };
  }

  // Kicks off a batch run of test cases.
  //
  // This method is a [long-running
  // operation](https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation).
  // The returned `Operation` type has the following method-specific fields:
  //
  // - `metadata`:
  // [BatchRunTestCasesMetadata][google.cloud.dialogflow.cx.v3beta1.BatchRunTestCasesMetadata]
  // - `response`:
  // [BatchRunTestCasesResponse][google.cloud.dialogflow.cx.v3beta1.BatchRunTestCasesResponse]
  rpc BatchRunTestCases(BatchRunTestCasesRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:batchRun"
      body: "*"
    };
    option (google.longrunning.operation_info) = {
      response_type: "BatchRunTestCasesResponse"
      metadata_type: "BatchRunTestCasesMetadata"
    };
  }

  // Calculates the test coverage for an agent.
  rpc CalculateCoverage(CalculateCoverageRequest)
      returns (CalculateCoverageResponse) {
    option (google.api.http) = {
      get: "/v3beta1/{agent=projects/*/locations/*/agents/*}/testCases:calculateCoverage"
    };
  }

  // Imports the test cases from a Cloud Storage bucket or a local file. It
  // always creates new test cases and won't overwrite any existing ones. The
  // provided ID in the imported test case is neglected.
  //
  // This method is a [long-running
  // operation](https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation).
  // The returned `Operation` type has the following method-specific fields:
  //
  // - `metadata`:
  // [ImportTestCasesMetadata][google.cloud.dialogflow.cx.v3beta1.ImportTestCasesMetadata]
  // - `response`:
  // [ImportTestCasesResponse][google.cloud.dialogflow.cx.v3beta1.ImportTestCasesResponse]
  rpc ImportTestCases(ImportTestCasesRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:import"
      body: "*"
    };
    option (google.longrunning.operation_info) = {
      response_type: "ImportTestCasesResponse"
      metadata_type: "ImportTestCasesMetadata"
    };
  }

  // Exports the test cases under the agent to a Cloud Storage bucket or a local
  // file. Filter can be applied to export a subset of test cases.
  //
  // This method is a [long-running
  // operation](https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation).
  // The returned `Operation` type has the following method-specific fields:
  //
  // - `metadata`:
  // [ExportTestCasesMetadata][google.cloud.dialogflow.cx.v3beta1.ExportTestCasesMetadata]
  // - `response`:
  // [ExportTestCasesResponse][google.cloud.dialogflow.cx.v3beta1.ExportTestCasesResponse]
  rpc ExportTestCases(ExportTestCasesRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:export"
      body: "*"
    };
    option (google.longrunning.operation_info) = {
      response_type: "ExportTestCasesResponse"
      metadata_type: "ExportTestCasesMetadata"
    };
  }

  // Fetches the list of run results for the given test case. A maximum of 100
  // results are kept for each test case.
  rpc ListTestCaseResults(ListTestCaseResultsRequest)
      returns (ListTestCaseResultsResponse) {
    option (google.api.http) = {
      get: "/v3beta1/{parent=projects/*/locations/*/agents/*/testCases/*}/results"
    };
    option (google.api.method_signature) = "parent";
  }

  // Gets a test case result.
  rpc GetTestCaseResult(GetTestCaseResultRequest) returns (TestCaseResult) {
    option (google.api.http) = {
      get: "/v3beta1/{name=projects/*/locations/*/agents/*/testCases/*/results/*}"
    };
    option (google.api.method_signature) = "name";
  }
}

// Represents a test case.
message TestCase {
  option (google.api.resource) = {
    type: "dialogflow.googleapis.com/TestCase"
    pattern: "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}"
  };

  // The unique identifier of the test case.
  // [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.CreateTestCase]
  // will populate the name automatically. Otherwise use format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>`.
  string name = 1;

  // 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.
  repeated string tags = 2;

  // Required. The human-readable name of the test case, unique within the
  // agent. Limit of 200 characters.
  string display_name = 3 [(google.api.field_behavior) = REQUIRED];

  // Additional freeform notes about the test case. Limit of 400 characters.
  string notes = 4;

  // Config for the test case.
  TestConfig test_config = 13;

  // 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.
  repeated ConversationTurn test_case_conversation_turns = 5;

  // Output only. When the test was created.
  google.protobuf.Timestamp creation_time = 10
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // The latest test result.
  TestCaseResult last_test_result = 12;
}

// Represents a result from running a test case in an agent environment.
message TestCaseResult {
  option (google.api.resource) = {
    type: "dialogflow.googleapis.com/TestCaseResult"
    pattern: "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}/results/{result}"
  };

  // The resource name for the test case result. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>/results/<TestCaseResultID>`.
  string name = 1;

  // Environment where the test was run. If not set, it indicates the draft
  // environment.
  string environment = 2 [(google.api.resource_reference) = {
    type: "dialogflow.googleapis.com/Environment"
  }];

  // The conversation turns uttered during the test case replay in chronological
  // order.
  repeated ConversationTurn conversation_turns = 3;

  // Whether the test case passed in the agent environment.
  TestResult test_result = 4;

  // The time that the test was run.
  google.protobuf.Timestamp test_time = 5;
}

// Represents configurations for a test case.
message TestConfig {
  // Session parameters to be compared when calculating differences.
  repeated string tracking_parameters = 1;

  // Flow name to start the test case with.
  // Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/flows/<FlowID>`.
  //
  // 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.
  string flow = 2 [
    (google.api.resource_reference) = { type: "dialogflow.googleapis.com/Flow" }
  ];

  // The [page][google.cloud.dialogflow.cx.v3beta1.Page] to start the test case
  // with. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/flows/<FlowID>/pages/<PageID>`.
  //
  // 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.
  string page = 3 [
    (google.api.resource_reference) = { type: "dialogflow.googleapis.com/Page" }
  ];
}

// One interaction between a human and virtual agent. The human provides some
// input and the virtual agent provides a response.
message ConversationTurn {
  // The input from the human user.
  message UserInput {
    // Supports [text
    // input][google.cloud.dialogflow.cx.v3beta1.QueryInput.text], [event
    // input][google.cloud.dialogflow.cx.v3beta1.QueryInput.event], [dtmf
    // input][google.cloud.dialogflow.cx.v3beta1.QueryInput.dtmf] in the test
    // case.
    QueryInput input = 5;

    // Parameters that need to be injected into the conversation during intent
    // detection.
    google.protobuf.Struct injected_parameters = 2;

    // If webhooks should be allowed to trigger in response to the user
    // utterance. Often if parameters are injected, webhooks should not be
    // enabled.
    bool is_webhook_enabled = 3;

    // Whether sentiment analysis is enabled.
    bool enable_sentiment_analysis = 7;
  }

  // The output from the virtual agent.
  message VirtualAgentOutput {
    // The session parameters available to the bot at this point.
    google.protobuf.Struct session_parameters = 4;

    // Output only. If this is part of a [result conversation
    // turn][TestCaseResult.conversation_turns], the list of differences
    // between the original run and the replay for this output, if any.
    repeated TestRunDifference differences = 5
        [(google.api.field_behavior) = OUTPUT_ONLY];

    // Required. Input only. The diagnostic
    // [info][Session.DetectIntentResponse.QueryResult.diagnostic_info]
    // output for the turn. Required to calculate the testing coverage.
    google.protobuf.Struct diagnostic_info = 6 [
      (google.api.field_behavior) = REQUIRED,
      (google.api.field_behavior) = INPUT_ONLY
    ];

    // The [Intent][google.cloud.dialogflow.cx.v3beta1.Intent] that triggered
    // the response. Only name and displayName will be set.
    Intent triggered_intent = 7;

    // The [Page][google.cloud.dialogflow.cx.v3beta1.Page] on which the
    // utterance was spoken. Only name and displayName will be set.
    Page current_page = 8;

    // The [text][google.cloud.dialogflow.cx.v3beta1.ResponseMessage.Text]
    // responses from the agent for the turn.
    repeated ResponseMessage.Text text_responses = 9;

    // Response error from the agent in the test result. If set, other output
    // is empty.
    google.rpc.Status status = 10;
  }

  // The user input.
  UserInput user_input = 1;

  // The virtual agent output.
  VirtualAgentOutput virtual_agent_output = 2;
}

// The description of differences between original and replayed agent output.
message TestRunDifference {
  // What part of the message replay differs from the test case.
  enum DiffType {
    // Should never be used.
    DIFF_TYPE_UNSPECIFIED = 0;

    // The intent.
    INTENT = 1;

    // The page.
    PAGE = 2;

    // The parameters.
    PARAMETERS = 3;

    // The message utterance.
    UTTERANCE = 4;

    // The flow.
    FLOW = 5;
  }

  // The type of diff.
  DiffType type = 1;

  // A human readable description of the diff, showing the actual output vs
  // expected output.
  string description = 2;
}

// Transition coverage represents the percentage of all possible page
// transitions (page-level transition routes and event handlers, excluding
// transition route groups) present within any of a parent's test cases.
message TransitionCoverage {
  // The source or target of a transition.
  message TransitionNode {
    // A TransitionNode can be either a page or a flow.
    oneof kind {
      // Indicates a transition to a
      // [Page][google.cloud.dialogflow.cx.v3beta1.Page]. Only some fields such
      // as name and displayname will be set.
      Page page = 1;

      // Indicates a transition to a
      // [Flow][google.cloud.dialogflow.cx.v3beta1.Flow]. Only some fields such
      // as name and displayname will be set.
      Flow flow = 2;
    }
  }

  // A transition in a page.
  message Transition {
    // The start node of a transition.
    TransitionNode source = 1;

    // The index of a transition in the transition list. Starting from 0.
    int32 index = 4;

    // The end node of a transition.
    TransitionNode target = 2;

    // Whether the transition is covered by at least one of the
    // agent's test cases.
    bool covered = 3;

    // The detailed transition.
    oneof detail {
      // Intent route or condition route.
      TransitionRoute transition_route = 5;

      // Event handler.
      EventHandler event_handler = 6;
    }
  }

  // The list of Transitions present in the agent.
  repeated Transition transitions = 1;

  // The percent of transitions in the agent that are covered.
  float coverage_score = 2;
}

// Transition route group coverage represents the percentage of all possible
// transition routes present within any of a parent's test cases. The results
// are grouped by the transition route group.
message TransitionRouteGroupCoverage {
  // Coverage result message for one transition route group.
  message Coverage {
    // A transition coverage in a transition route group.
    message Transition {
      // Intent route or condition route.
      TransitionRoute transition_route = 1;

      // Whether the transition route is covered by at least one of the
      // agent's test cases.
      bool covered = 2;
    }

    // Transition route group metadata. Only name and displayName will be set.
    TransitionRouteGroup route_group = 1;

    // The list of transition routes and coverage in the transition route group.
    repeated Transition transitions = 2;

    // The percent of transition routes in the transition route group that are
    // covered.
    float coverage_score = 3;
  }

  // Transition route group coverages.
  repeated Coverage coverages = 1;

  // The percent of transition routes in all the transition route groups that
  // are covered.
  float coverage_score = 2;
}

// Intent coverage represents the percentage of all possible intents in the
// agent that are triggered in any of a parent's test cases.
message IntentCoverage {
  // The agent's intent.
  message Intent {
    // The intent full resource name
    string intent = 1 [(google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Intent"
    }];

    // Whether the intent is covered by at least one of the agent's
    // test cases.
    bool covered = 2;
  }

  // The list of Intents present in the agent
  repeated Intent intents = 1;

  // The percent of intents in the agent that are covered.
  float coverage_score = 2;
}

// The request message for
// [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage].
message CalculateCoverageRequest {
  // The type of coverage score requested.
  enum CoverageType {
    // Should never be used.
    COVERAGE_TYPE_UNSPECIFIED = 0;

    // Intent coverage.
    INTENT = 1;

    // Page transition coverage.
    PAGE_TRANSITION = 2;

    // Transition route group coverage.
    TRANSITION_ROUTE_GROUP = 3;
  }

  // Required. The agent to calculate coverage for.
  // Format: `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>`.
  string agent = 3 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Agent"
    }
  ];

  // Required. The type of coverage requested.
  CoverageType type = 2 [(google.api.field_behavior) = REQUIRED];
}

// The response message for
// [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage].
message CalculateCoverageResponse {
  // The agent to calculate coverage for.
  // Format: `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>`.
  string agent = 5 [(google.api.resource_reference) = {
    type: "dialogflow.googleapis.com/Agent"
  }];

  // The type of coverage requested.
  oneof coverage_type {
    // Intent coverage.
    IntentCoverage intent_coverage = 2;

    // Transition (excluding transition route groups) coverage.
    TransitionCoverage transition_coverage = 4;

    // Transition route group coverage.
    TransitionRouteGroupCoverage route_group_coverage = 6;
  }
}

// The request message for
// [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases].
message ListTestCasesRequest {
  // Specifies how much test case information to include in the response.
  enum TestCaseView {
    // The default / unset value.
    // The API will default to the BASIC view.
    TEST_CASE_VIEW_UNSPECIFIED = 0;

    // Include basic metadata about the test case, but not the conversation
    // turns. This is the default value.
    BASIC = 1;

    // Include everything.
    FULL = 2;
  }

  // Required. The agent to list all pages for.
  // Format: `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/TestCase"
    }
  ];

  // The maximum number of items to return in a single page. By default 20.
  // Note that when TestCaseView = FULL, the maximum page size allowed is 20.
  // When TestCaseView = BASIC, the maximum page size allowed is 500.
  int32 page_size = 2;

  // The next_page_token value returned from a previous list request.
  string page_token = 3;

  // Specifies whether response should include all fields or just the metadata.
  TestCaseView view = 4;
}

// The response message for
// [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases].
message ListTestCasesResponse {
  // The list of test cases. There will be a maximum number of items returned
  // based on the page_size field in the request.
  repeated TestCase test_cases = 1;

  // Token to retrieve the next page of results, or empty if there are no more
  // results in the list.
  string next_page_token = 2;
}

// The request message for
// [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchDeleteTestCases].
message BatchDeleteTestCasesRequest {
  // Required. The agent to delete test cases from.
  // Format: `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/TestCase"
    }
  ];

  // Required. Format of test case names:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>`.
  repeated string names = 3 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/TestCase"
    }
  ];
}

// The request message for
// [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.CreateTestCase].
message CreateTestCaseRequest {
  // Required. The agent to create the test case for.
  // Format: `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/TestCase"
    }
  ];

  // Required. The test case to create.
  TestCase test_case = 2 [(google.api.field_behavior) = REQUIRED];
}

// The request message for
// [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.UpdateTestCase].
message UpdateTestCaseRequest {
  // Required. The test case to update.
  TestCase test_case = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The mask to specify which fields should be updated. The
  // [`creationTime`][google.cloud.dialogflow.cx.v3beta1.TestCase.creation_time]
  // and
  // [`lastTestResult`][google.cloud.dialogflow.cx.v3beta1.TestCase.last_test_result]
  // cannot be updated.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = REQUIRED];
}

// The request message for
// [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.GetTestCase].
message GetTestCaseRequest {
  // Required. The name of the testcase.
  // Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/TestCase"
    }
  ];
}

// The request message for
// [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase].
message RunTestCaseRequest {
  // Required. Format of test case name to run:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/TestCase"
    }
  ];

  // Optional. Environment name. If not set, draft environment is assumed.
  // Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>`.
  string environment = 2 [
    (google.api.field_behavior) = OPTIONAL,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Environment"
    }
  ];
}

// The response message for
// [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase].
message RunTestCaseResponse {
  // The result.
  TestCaseResult result = 2;
}

// Metadata returned for the
// [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase]
// long running operation. This message currently has no fields.
message RunTestCaseMetadata {}

// The request message for
// [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases].
message BatchRunTestCasesRequest {
  // Required. Agent name. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/TestCase"
    }
  ];

  // Optional. If not set, draft environment is assumed. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>`.
  string environment = 2 [
    (google.api.field_behavior) = OPTIONAL,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Environment"
    }
  ];

  // Required. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>`.
  repeated string test_cases = 3 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/TestCase"
    }
  ];
}

// The response message for
// [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases].
message BatchRunTestCasesResponse {
  // The test case results. The detailed
  // [conversation
  // turns][google.cloud.dialogflow.cx.v3beta1.TestCaseResult.conversation_turns]
  // are empty in this response.
  repeated TestCaseResult results = 1;
}

// Metadata returned for the
// [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases]
// long running operation.
message BatchRunTestCasesMetadata {
  // The test errors.
  repeated TestError errors = 1;
}

// Error info for running a test.
message TestError {
  // The test case resource name.
  string test_case = 1 [(google.api.resource_reference) = {
    type: "dialogflow.googleapis.com/TestCase"
  }];

  // The status associated with the test.
  google.rpc.Status status = 2;

  // The timestamp when the test was completed.
  google.protobuf.Timestamp test_time = 3;
}

// The request message for
// [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases].
message ImportTestCasesRequest {
  // Required. The agent to import test cases to.
  // Format: `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/TestCase"
    }
  ];

  // Required. The source to import.
  oneof source {
    // The [Google Cloud Storage](https://cloud.google.com/storage/docs/) URI
    // to import test cases from. The format of this URI must be
    // `gs://<bucket-name>/<object-name>`.
    //
    // Dialogflow performs a read operation for the Cloud Storage object
    // on the caller's behalf, so your request authentication must
    // have read permissions for the object. For more information, see
    // [Dialogflow access
    // control](https://cloud.google.com/dialogflow/cx/docs/concept/access-control#storage).
    string gcs_uri = 2;

    // Uncompressed raw byte content for test cases.
    bytes content = 3;
  }
}

// The response message for
// [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases].
message ImportTestCasesResponse {
  // The unique identifiers of the new test cases.
  // Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>`.
  repeated string names = 1 [(google.api.resource_reference) = {
    type: "dialogflow.googleapis.com/TestCase"
  }];
}

// Metadata returned for the
// [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases]
// long running operation.
message ImportTestCasesMetadata {
  // Errors for failed test cases.
  repeated TestCaseError errors = 1;
}

// Error info for importing a test.
message TestCaseError {
  // The test case.
  TestCase test_case = 1;

  // The status associated with the test case.
  google.rpc.Status status = 2;
}

// The request message for
// [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases].
message ExportTestCasesRequest {
  // Data format of the exported test cases.
  enum DataFormat {
    // Unspecified format.
    DATA_FORMAT_UNSPECIFIED = 0;

    // Raw bytes.
    BLOB = 1;

    // JSON format.
    JSON = 2;
  }

  // Required. The agent where to export test cases from.
  // Format: `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/TestCase"
    }
  ];

  // The destination to export.
  oneof destination {
    // The [Google Cloud Storage](https://cloud.google.com/storage/docs/) URI to
    // export the test cases to. The format of this URI must be
    // `gs://<bucket-name>/<object-name>`. If unspecified, the serialized test
    // cases is returned inline.
    //
    // Dialogflow performs a write operation for the Cloud Storage object
    // on the caller's behalf, so your request authentication must
    // have write permissions for the object. For more information, see
    // [Dialogflow access
    // control](https://cloud.google.com/dialogflow/cx/docs/concept/access-control#storage).
    string gcs_uri = 2;
  }

  // The data format of the exported test cases. If not specified, `BLOB` is
  // assumed.
  DataFormat data_format = 3;

  // The filter expression used to filter exported test cases, see
  // [API Filtering](https://aip.dev/160). The expression is case insensitive
  // and supports the following syntax:
  //
  //   name = <value> [OR name = <value>] ...
  //
  // For example:
  //
  // *   "name = t1 OR name = t2" matches the test case with the exact resource
  //     name "t1" or "t2".
  string filter = 4;
}

// The response message for
// [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases].
message ExportTestCasesResponse {
  // The exported test cases.
  oneof destination {
    // The URI to a file containing the exported test cases. This field is
    //  populated only if `gcs_uri` is specified in
    // [ExportTestCasesRequest][google.cloud.dialogflow.cx.v3beta1.ExportTestCasesRequest].
    string gcs_uri = 1;

    // Uncompressed raw byte content for test cases.
    bytes content = 2;
  }
}

// Metadata returned for the
// [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases]
// long running operation. This message currently has no fields.
message ExportTestCasesMetadata {}

// The request message for
// [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults].
message ListTestCaseResultsRequest {
  // Required. The test case to list results for.
  // Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>`.
  // Specify a `-` as a wildcard for TestCase ID to
  //  list results across multiple test cases.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/TestCaseResult"
    }
  ];

  // The maximum number of items to return in a single page. By default 100 and
  // at most 1000.
  int32 page_size = 2;

  // The next_page_token value returned from a previous list request.
  string page_token = 3;

  // The filter expression used to filter test case results. See
  // [API Filtering](https://aip.dev/160).
  //
  // The expression is case insensitive. Only 'AND' is supported for logical
  // operators. The supported syntax is listed below in detail:
  //
  //   <field> <operator> <value> [AND <field> <operator> <value>] ...
  //   [AND latest]
  //
  // The supported fields and operators are:
  // field                 operator
  // `environment`         `=`, `IN`  (Use value `draft` for draft environment)
  // `test_time`           `>`, `<`
  //
  // `latest` only returns the latest test result in all results for each test
  // case.
  //
  // Examples:
  // *   "environment=draft AND latest" matches the latest test result for each
  //     test case in the draft environment.
  // *   "environment IN (e1,e2)" matches any test case results with an
  //     environment resource name of either "e1" or "e2".
  // *   "test_time > 1602540713" matches any test case results with test time
  //     later than a unix timestamp in seconds 1602540713.
  string filter = 4;
}

// The response message for
// [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults].
message ListTestCaseResultsResponse {
  // The list of test case results.
  repeated TestCaseResult test_case_results = 1;

  // Token to retrieve the next page of results, or empty if there are no more
  // results in the list.
  string next_page_token = 2;
}

// The request message for
// [TestCases.GetTestCaseResult][google.cloud.dialogflow.cx.v3beta1.TestCases.GetTestCaseResult].
message GetTestCaseResultRequest {
  // Required. The name of the testcase.
  // Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/testCases/<TestCaseID>/results/<TestCaseResultID>`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/TestCaseResult"
    }
  ];
}

// The test result for a test case and an agent environment.
enum TestResult {
  // Not specified. Should never be used.
  TEST_RESULT_UNSPECIFIED = 0;

  // The test passed.
  PASSED = 1;

  // The test did not pass.
  FAILED = 2;
}
