|
| 1 | +## ADDED Requirements |
| 2 | + |
| 3 | +### Requirement: Resource manages GA2 endpoint group lifecycle |
| 4 | +The provider SHALL expose a resource `tencentcloud_ga2_endpoint_group` that manages a Tencent Cloud Global Accelerator 2 endpoint group via `CreateEndpointGroup`, `DescribeEndpointGroups`, `ModifyEndpointGroup`, and `DeleteEndpointGroups` APIs in the `ga2/v20250115` SDK namespace. |
| 5 | + |
| 6 | +#### Scenario: Create provisions and waits for task success |
| 7 | +- **WHEN** a user defines the resource with `global_accelerator_id`, `listener_id`, `endpoint_group_type`, and `endpoint_group_configuration` |
| 8 | +- **THEN** the provider SHALL call `CreateEndpointGroup`, capture the returned `EndpointGroupId` and `TaskId`, poll `DescribeTaskResult` until `Status == "SUCCESS"`, and set the resource ID to `<global_accelerator_id>#<listener_id>#<endpoint_group_id>` |
| 9 | + |
| 10 | +#### Scenario: Read reflects current cloud state |
| 11 | +- **WHEN** the provider reads the resource |
| 12 | +- **THEN** it SHALL split the resource ID into three parts, call `DescribeEndpointGroups` filtered by `endpoint-group-id`, and map every non-nil response field into Terraform state |
| 13 | + |
| 14 | +#### Scenario: Read clears state when not found |
| 15 | +- **WHEN** `DescribeEndpointGroups` returns no record matching the endpoint group ID |
| 16 | +- **THEN** the provider SHALL call `d.SetId("")` and return nil |
| 17 | + |
| 18 | +#### Scenario: Update modifies mutable fields and waits |
| 19 | +- **WHEN** any mutable attribute under `endpoint_group_configuration` (or top-level `endpoint_configurations`/`port_overrides`/health-check fields) changes |
| 20 | +- **THEN** the provider SHALL build a `ModifyEndpointGroup` request from the new state, call the API, and poll `DescribeTaskResult` until `Status == "SUCCESS"` |
| 21 | + |
| 22 | +#### Scenario: Delete removes the group and waits |
| 23 | +- **WHEN** the resource is destroyed |
| 24 | +- **THEN** the provider SHALL call `DeleteEndpointGroups` with the single-element `EndpointGroupIds` slice and poll `DescribeTaskResult` until `Status == "SUCCESS"` |
| 25 | + |
| 26 | +### Requirement: Schema mirrors CreateEndpointGroup parameters |
| 27 | +The resource schema SHALL contain fields corresponding to every parameter in `CreateEndpointGroupRequestParams`. |
| 28 | + |
| 29 | +#### Scenario: Top-level required fields enforced |
| 30 | +- **WHEN** a user omits `global_accelerator_id`, `listener_id`, `endpoint_group_type`, or `endpoint_group_configuration` |
| 31 | +- **THEN** Terraform SHALL return a validation error before any API call |
| 32 | + |
| 33 | +#### Scenario: Nested endpoint_group_configuration mirrors SDK struct |
| 34 | +- **WHEN** the user provides an `endpoint_group_configuration` block |
| 35 | +- **THEN** every field inside (`name`, `endpoint_group_region`, `endpoint_configurations`, `check_type`, `description`, `check_port`, `context_type`, `check_send_context`, `check_recv_context`, `enable_health_check`, `connect_timeout`, `health_check_interval`, `unhealthy_threshold`, `healthy_threshold`, `forward_protocol`, `check_domain`, `check_path`, `check_method`, `status_mask`, `port_overrides`, `isp_type`, `cipher_policy_id`) SHALL map 1:1 onto the SDK request |
| 36 | + |
| 37 | +#### Scenario: ForceNew on identifying and immutable fields |
| 38 | +- **WHEN** the user changes `global_accelerator_id`, `listener_id`, or `endpoint_group_type` |
| 39 | +- **THEN** Terraform SHALL plan a destroy-and-recreate, since `ModifyEndpointGroup` does not accept these fields |
| 40 | + |
| 41 | +### Requirement: All SDK invocations are wrapped with retry logic |
| 42 | +Every SDK API call (Create, Read, Update, Delete, DescribeTaskResult) SHALL be invoked inside `resource.Retry(...)` using project timeout constants. |
| 43 | + |
| 44 | +#### Scenario: Read uses ReadRetryTimeout |
| 45 | +- **WHEN** `DescribeEndpointGroups` is invoked from `Read` or the helper |
| 46 | +- **THEN** the call SHALL be wrapped in `resource.Retry(tccommon.ReadRetryTimeout, ...)` and use `tccommon.RetryError` for retryable errors |
| 47 | + |
| 48 | +#### Scenario: Mutating calls use WriteRetryTimeout |
| 49 | +- **WHEN** `CreateEndpointGroup`, `ModifyEndpointGroup`, or `DeleteEndpointGroups` is invoked |
| 50 | +- **THEN** the call SHALL be wrapped in `resource.Retry(tccommon.WriteRetryTimeout, ...)` |
| 51 | + |
| 52 | +#### Scenario: Task polling tolerates transient failures |
| 53 | +- **WHEN** `DescribeTaskResult` returns a transient error or non-`SUCCESS` status |
| 54 | +- **THEN** the helper SHALL return `resource.RetryableError` so the polling loop continues until `WriteRetryTimeout*2` elapses |
| 55 | + |
| 56 | +### Requirement: Async task polling via DescribeTaskResult |
| 57 | +After every mutating API call, the provider SHALL block until the task associated with the returned `TaskId` reaches terminal `SUCCESS` state via `DescribeTaskResult`. |
| 58 | + |
| 59 | +#### Scenario: Task succeeds |
| 60 | +- **WHEN** `DescribeTaskResult` returns `Status == "SUCCESS"` |
| 61 | +- **THEN** polling SHALL stop and the operation SHALL be considered complete |
| 62 | + |
| 63 | +#### Scenario: Task remains in progress |
| 64 | +- **WHEN** `DescribeTaskResult` returns any non-`SUCCESS` status |
| 65 | +- **THEN** polling SHALL continue until the timeout elapses; on timeout the operation SHALL fail with the last observed status |
| 66 | + |
| 67 | +### Requirement: Pagination uses API maximum page size |
| 68 | +List/query API calls SHALL use the documented maximum `Limit` to minimize round trips. |
| 69 | + |
| 70 | +#### Scenario: DescribeEndpointGroups uses Limit=100 |
| 71 | +- **WHEN** the service helper queries endpoint groups |
| 72 | +- **THEN** it SHALL pass `Limit=100` (the API maximum) and iterate with `Offset` until results are exhausted |
| 73 | + |
| 74 | +### Requirement: Defensive nil-pointer handling |
| 75 | +The provider SHALL guard against nil pointer dereferences when reading SDK response fields. |
| 76 | + |
| 77 | +#### Scenario: Nil response is non-retryable |
| 78 | +- **WHEN** any SDK call returns `result == nil` or `result.Response == nil` |
| 79 | +- **THEN** the call SHALL return `resource.NonRetryableError` with a clear message |
| 80 | + |
| 81 | +#### Scenario: Nil field is skipped, not dereferenced |
| 82 | +- **WHEN** the read function processes a response field that is nil |
| 83 | +- **THEN** it SHALL skip the corresponding `d.Set(...)` call rather than dereferencing the pointer |
| 84 | + |
| 85 | +### Requirement: Composite resource ID |
| 86 | +The resource ID SHALL be the string `<global_accelerator_id>#<listener_id>#<endpoint_group_id>`. |
| 87 | + |
| 88 | +#### Scenario: ID is set on successful create |
| 89 | +- **WHEN** `CreateEndpointGroup` succeeds and the task reaches `SUCCESS` |
| 90 | +- **THEN** `d.SetId` SHALL be called with the three IDs joined by `#` |
| 91 | + |
| 92 | +#### Scenario: ID is parsed on subsequent operations |
| 93 | +- **WHEN** Read, Update, or Delete is invoked |
| 94 | +- **THEN** the provider SHALL split `d.Id()` on `#`, validate exactly 3 segments, and use the segments for API parameters; an invalid ID format SHALL return an error |
0 commit comments