# CDC RCU List API Coverage in Dedicated E2E

## Background

The Dedicated CDC E2E wrapper currently supports create/get/list/scale and fee-related APIs, but does not expose a unified **RCU list** capability across ConsoleAPI and OpenAPI modes.  
For `kafka_smoke.go`, we need a lightweight validation step to ensure the RCU list API is callable and returns non-empty values.

## Goal

1. Add RCU-list retrieval support in `test/e2e/internal/tidbcloud/dedicated/cdcapi/client_wrapper.go` for both API modes.
2. Add one step in `test/e2e/cases/dedicated/changefeed/kafka_smoke.go` to call RCU list and assert success + non-empty result.

## Non-Goals

1. Do not use RCU list results for follow-up scheduling, scaling, or case branching.
2. Do not modify generated OpenAPI/ConsoleAPI client/model files.
3. Do not change existing changefeed create/edit/scale behavior.

## Design

### 1. API surface changes

1. **Console wrapper**
   Add `ListChangefeedRCUs() (*changefeed_instance_type_service.ListChangefeedInstanceTypesOK, error)` in `consoleapi/cdc_client_wrapper.go`, backed by `BizChangefeedClient().ChangefeedInstanceTypeService.ListChangefeedInstanceTypes(...)`.

2. **OpenAPI wrapper**
   Add `ListChangefeedRCUs() (*changefeed_service.ListChangefeedRCUsOK, error)` in `openapi/open_api_client_wrapper.go`, backed by `service.ListChangefeedRCUs(...)`.

3. **Unified CDC wrapper**
   Add `ListChangefeedRCUs(tidbCluster *TiDBDedicatedEntity) (*console_model.DataflowChangefeedInstanceTypes, error)` in `cdcapi/client_wrapper.go`.
   - Console mode: call console wrapper and return `resp.Payload`.
   - OpenAPI mode: call openapi wrapper and map OpenAPI payload (`rcus`) into `console_model.DataflowChangefeedInstanceTypes`.

### 2. Data conversion

OpenAPI response `[]V1beta1ChangefeedRCU` is converted item-by-item:

1. `name -> DataflowChangefeedInstanceType.Name`
2. `rcuNum -> DataflowChangefeedInstanceType.RcuNum`
3. `rpsLimit -> DataflowChangefeedInstanceType.RpsLimit`
4. `total -> len(items)`

`displayName` is not mapped because Console model has no corresponding field.

### 3. E2E case change (`kafka_smoke.go`)

Add one chain step near the existing instance-type TODO area:

1. Call `cdcApiWrapper.ListChangefeedRCUs(tidbCluster)`.
2. Validate:
   - response object exists
   - `Items` exists
   - `len(Items) > 0`
3. Fail fast if empty or call fails.

No downstream dependency on returned list.

## Error handling strategy

1. Keep existing wrapper pattern: return underlying API errors directly.
2. For OpenAPI conversion, treat nil payload as empty list and return a typed, non-nil `DataflowChangefeedInstanceTypes` payload with `Total=0` and empty items, so caller-side non-empty assertion remains the single source of pass/fail.
3. Do not add broad catch/fallback behavior across modes beyond existing mode dispatch.

## Testing plan

1. `cdcapi/client_wrapper_test.go`
   - Console mode test: verifies dispatch to console API and payload passthrough.
   - OpenAPI mode test: verifies dispatch to openapi API and field mapping (`name/rcuNum/rpsLimit/total`).

2. `openapi/open_api_client_wrapper_test.go`
   - Verify `ListChangefeedRCUs` issues request with wrapper context and returns service response.

3. Existing test suites for changefeed wrapper behavior remain unchanged.

## Risks and mitigations

1. **Risk:** OpenAPI/Console payload shape drift.  
   **Mitigation:** Keep conversion minimal and explicit, plus dedicated mapping test.

2. **Risk:** E2E environment returns empty instance types unexpectedly.  
   **Mitigation:** Explicit non-empty assertion surfaces issue immediately as intended by this task.
