# Dedicated E2E: MySQL PrivateLink Changefeed Design

## 1. Objective

Add a new **Dedicated CDC E2E case** for **MySQL PrivateLink** by referencing the existing `kafka_private_link.go` flow, and include it in the **`weeklyRegression`** case group.

The new case must create a changefeed with payload semantics equivalent to:

1. `connector_type=MYSQL`
2. `mysql_info.connection` from dependency entity
3. `mysql_info.table_config` using `filter_rule=["*.*"]`, `mode=FORCE_SYNC`, `event_filter_rule=[]`, `case_sensitive=false`
4. `mysql_info.start_position.mode=FROM_NOW`
5. `network_info` using `network_type=NetworkType_Private_Link`, `ports=[3306]` (from dependency), and dynamic `sink_endpoint_id`
6. `name=case.Name()`
7. `changefeed_instance_type=2rcu`

## 2. User-Confirmed Decisions

1. Product line: **Dedicated**.
2. Cloud coverage: **AWS + GCP + Azure**.
3. Case naming: dynamic via `case.Name()`, not fixed string.
4. MySQL credentials source: from **MySQL dependency entity**, not hardcoded.
5. `sink_endpoint_id`: dynamically created during the case run, not fixed.
6. Strategy: add a **new standalone case file** (not fold into `mysql_smoke.go`).
7. MySQL PrivateLink requirement matching: **strict cloud-provider match**.

## 3. Scope

### In Scope

1. Add new case file under Dedicated changefeed cases.
2. Register AWS/GCP/Azure variants of this case in `cases_registry_dedicated.go`.
3. Include the case in `awsWeeklyRegression`, `gcpWeeklyRegression`, and `azureWeeklyRegression`.
4. Add required Dedicated console API wrapper support for **MySQL + PrivateLink test connection**.

### Out of Scope

1. Premium case implementation.
2. Refactoring existing `mysql_smoke.go`.
3. Adding new dependency provisioning logic (reuse existing dependency framework/config).

## 4. Current-State Findings

1. Existing Dedicated private-link case exists only for Kafka:
   - `test/e2e/cases/dedicated/changefeed/kafka_private_link.go`
2. Existing MySQL CDC case is public-network smoke:
   - `test/e2e/cases/dedicated/changefeed/mysql_smoke.go`
3. Dedicated test-connection assembly currently supports:
   - Kafka: public / vpc peering / private link
   - MySQL: **public only**
   - file: `test/e2e/internal/tidbcloud/dedicated/consoleapi/cdc_client_wrapper.go`
4. Dedicated registry already has `weeklyRegression` split by cloud provider and then merged.

## 5. Target Design

### 5.1 New Case File

Add:

`test/e2e/cases/dedicated/changefeed/mysql_private_link.go`

Case type:

`mysqlPrivateLinkCase` with constructor:

`NewMySQLPrivateLinkCase(cloudProvider CloudProviderType) E2ECase`

Name format:

`{CloudProvider}MySQLPrivateLink`

### 5.2 Dependency Requirements

Declare:

1. `tidb`: `TiDBDedicatedRequirement` with case cloud provider + default region.
2. `mysql`: `MySQLRequirement` with:
   - `NetworkType: DataflowNetworkTypeNetworkTypePrivateLink`
   - `CloudProvider: case cloud provider` (strict matching)

### 5.3 Runtime Flow

1. Resolve dependencies (`tidb`, `mysql`).
2. Initialize wrappers/validator:
   - `cdcapi.CDCClientWrapper`
   - `consoleapi.SinkEndpointClientWrapper`
   - `common.ChangfeedValidator`
3. Create sink endpoint using MySQL PrivateLink service name:
   - endpoint name: `<clusterID>-mysql-pl-e2e`
   - provider/region from TiDB cluster
   - endpoint service name from MySQL dependency
4. Wait until sink endpoint status is `AVAILABLE`.
5. Execute private-link test connection using dynamic `sink_endpoint_id`.
6. Create MySQL changefeed with exact payload semantics from Section 1.
7. Verify changefeed exists and reaches running status.
8. Cleanup in `defer`:
   - delete changefeed by name
   - verify not in list
   - delete sink endpoint

### 5.4 Payload Construction

The create request builder in the new case will explicitly set:

1. `ConnectorType = MYSQL`
2. `ChangefeedInstanceType = "2rcu"`
3. `Name = case.Name()`
4. `MysqlInfo.Connection.Username/Password` from dependency
5. `MysqlInfo.TableConfig`:
   - `FilterRule = []string{"*.*"}`
   - `Mode = FORCESYNC`
   - `EventFilterRule = []*model.DataflowEventFilterRule{}`
   - `CaseSensitive = false`
6. `MysqlInfo.StartPosition.Mode = FROMNOW`
7. `NetworkInfo`:
   - `NetworkType = NetworkTypePrivateLink`
   - `Ports = downstream.Ports` (expected `3306`)
   - `SinkEndpointID = created endpoint ID`

## 6. Supporting Wrapper Change

File:

`test/e2e/internal/tidbcloud/dedicated/consoleapi/cdc_client_wrapper.go`

Change:

1. Extend `assembleMySQLTestConnectorParams` to support `NetworkType_Private_Link`.
2. Add a helper for MySQL private-link test body (same style as Kafka private-link body helper).

Expected behavior:

1. Keep current MySQL public path unchanged.
2. For MySQL private-link path, construct body with:
   - `connector_type=MYSQL`
   - `mysql_info.connection.username/password`
   - `network_info.network_type=NetworkType_Private_Link`
   - `network_info.ports=downstream.Ports`
3. `TestConnectionWithPrivateLink` will then inject `sink_endpoint_id` as it already does.

## 7. Registry & Case Group Changes

File:

`test/e2e/internal/case_driver/cases_registry_dedicated.go`

Add case registrations:

1. `awsMySQLPrivateLinkCase`
2. `gcpMySQLPrivateLinkCase`
3. `azureMySQLPrivateLinkCase`

Add them to:

1. `awsWeeklyRegression`
2. `gcpWeeklyRegression`
3. `azureWeeklyRegression`

Result:

`weeklyRegression` aggregate automatically includes the new cases via existing merge logic.

## 8. Validation Plan

### 8.1 Code-Level Validation

In `test/e2e` module, run targeted package validation for:

1. Dedicated changefeed cases package
2. Dedicated console API wrapper package
3. Dedicated case registry package

### 8.2 Environment-Level Validation

Run Dedicated `weeklyRegression` and verify:

1. New MySQL PrivateLink cases are selected for AWS/GCP/Azure.
2. Dependency resolution succeeds for each cloud-specific MySQL PrivateLink requirement.
3. Each case completes endpoint creation, test connection, changefeed creation, and running-state checks.

## 9. Risks and Prerequisites

1. Strict cloud-provider matching requires each environment config to contain cloud-aligned MySQL PrivateLink entities for AWS/GCP/Azure.
2. If a cloud-specific MySQL PrivateLink entity is missing, dependency provisioning for that case will fail before case execution (expected fail-fast behavior).
3. No generated files are modified in this design.

## 10. Definition of Done

1. New Dedicated MySQL PrivateLink case file exists and compiles.
2. Dedicated wrapper supports MySQL PrivateLink test-connection assembly.
3. AWS/GCP/Azure MySQL PrivateLink cases are registered.
4. Cases are included in each cloud `*WeeklyRegression` group.
5. Aggregated `weeklyRegression` includes the new cases.
