@@ -207,6 +207,161 @@ func TestWriteDDLEvent(t *testing.T) {
207207 }` , string (tableSchema ))
208208}
209209
210+ func TestWriteDDLEventWithTableIDAsPath (t * testing.T ) {
211+ parentDir := t .TempDir ()
212+ uri := fmt .Sprintf ("file:///%s?protocol=csv&use-table-id-as-path=true" , parentDir )
213+ sinkURI , err := url .Parse (uri )
214+ require .NoError (t , err )
215+
216+ replicaConfig := config .GetDefaultReplicaConfig ()
217+ err = replicaConfig .ValidateAndAdjust (sinkURI )
218+ require .NoError (t , err )
219+
220+ ctx , cancel := context .WithCancel (context .Background ())
221+ defer cancel ()
222+
223+ mockPDClock := pdutil .NewClock4Test ()
224+ appcontext .SetService (appcontext .DefaultPDClock , mockPDClock )
225+
226+ cloudStorageSink , err := newSinkForTest (ctx , replicaConfig , sinkURI , nil )
227+ require .NoError (t , err )
228+
229+ go cloudStorageSink .Run (ctx )
230+
231+ tableInfo := common .WrapTableInfo ("test" , & timodel.TableInfo {
232+ ID : 20 ,
233+ Name : parser_model .NewCIStr ("table1" ),
234+ Columns : []* timodel.ColumnInfo {
235+ {
236+ Name : parser_model .NewCIStr ("col1" ),
237+ FieldType : * types .NewFieldType (mysql .TypeLong ),
238+ },
239+ {
240+ Name : parser_model .NewCIStr ("col2" ),
241+ FieldType : * types .NewFieldType (mysql .TypeVarchar ),
242+ },
243+ },
244+ })
245+ ddlEvent := & commonEvent.DDLEvent {
246+ Query : "alter table test.table1 add col2 varchar(64)" ,
247+ Type : byte (timodel .ActionAddColumn ),
248+ SchemaName : "test" ,
249+ TableName : "table1" ,
250+ FinishedTs : 100 ,
251+ TableInfo : tableInfo ,
252+ }
253+
254+ err = cloudStorageSink .WriteBlockEvent (ddlEvent )
255+ require .NoError (t , err )
256+
257+ tableDir := path .Join (parentDir , "20/meta/" )
258+ tableSchema , err := os .ReadFile (path .Join (tableDir , "schema_100_4192708364.json" ))
259+ require .NoError (t , err )
260+ require .Contains (t , string (tableSchema ), `"Table": "table1"` )
261+ }
262+
263+ func TestSkipDatabaseSchemaWithTableIDAsPath (t * testing.T ) {
264+ parentDir := t .TempDir ()
265+ uri := fmt .Sprintf ("file:///%s?protocol=csv&use-table-id-as-path=true" , parentDir )
266+ sinkURI , err := url .Parse (uri )
267+ require .NoError (t , err )
268+
269+ replicaConfig := config .GetDefaultReplicaConfig ()
270+ err = replicaConfig .ValidateAndAdjust (sinkURI )
271+ require .NoError (t , err )
272+
273+ ctx , cancel := context .WithCancel (context .Background ())
274+ defer cancel ()
275+
276+ mockPDClock := pdutil .NewClock4Test ()
277+ appcontext .SetService (appcontext .DefaultPDClock , mockPDClock )
278+
279+ cloudStorageSink , err := newSinkForTest (ctx , replicaConfig , sinkURI , nil )
280+ require .NoError (t , err )
281+
282+ go cloudStorageSink .Run (ctx )
283+
284+ ddlEvent := & commonEvent.DDLEvent {
285+ Query : "create database test_db" ,
286+ Type : byte (timodel .ActionCreateSchema ),
287+ SchemaName : "test_db" ,
288+ TableName : "" ,
289+ FinishedTs : 100 ,
290+ TableInfo : nil ,
291+ }
292+
293+ err = cloudStorageSink .WriteBlockEvent (ddlEvent )
294+ require .NoError (t , err )
295+
296+ _ , err = os .Stat (path .Join (parentDir , "test_db" ))
297+ require .Error (t , err )
298+ require .True (t , os .IsNotExist (err ))
299+ }
300+
301+ func TestWriteDDLEventWithInvalidExchangePartitionEvent (t * testing.T ) {
302+ testCases := []struct {
303+ name string
304+ multipleTableInfos []* common.TableInfo
305+ }{
306+ {
307+ name : "nil source table info" ,
308+ multipleTableInfos : []* common.TableInfo {nil },
309+ },
310+ {
311+ name : "short table infos" ,
312+ multipleTableInfos : nil ,
313+ },
314+ }
315+
316+ parentDir := t .TempDir ()
317+ uri := fmt .Sprintf ("file:///%s?protocol=csv&use-table-id-as-path=true" , parentDir )
318+ sinkURI , err := url .Parse (uri )
319+ require .NoError (t , err )
320+
321+ replicaConfig := config .GetDefaultReplicaConfig ()
322+ err = replicaConfig .ValidateAndAdjust (sinkURI )
323+ require .NoError (t , err )
324+
325+ ctx , cancel := context .WithCancel (context .Background ())
326+ defer cancel ()
327+
328+ mockPDClock := pdutil .NewClock4Test ()
329+ appcontext .SetService (appcontext .DefaultPDClock , mockPDClock )
330+
331+ cloudStorageSink , err := newSinkForTest (ctx , replicaConfig , sinkURI , nil )
332+ require .NoError (t , err )
333+
334+ tableInfo := common .WrapTableInfo ("test" , & timodel.TableInfo {
335+ ID : 20 ,
336+ Name : parser_model .NewCIStr ("table1" ),
337+ Columns : []* timodel.ColumnInfo {
338+ {
339+ Name : parser_model .NewCIStr ("col1" ),
340+ FieldType : * types .NewFieldType (mysql .TypeLong ),
341+ },
342+ },
343+ })
344+
345+ for _ , tc := range testCases {
346+ t .Run (tc .name , func (t * testing.T ) {
347+ ddlEvent := & commonEvent.DDLEvent {
348+ Query : "alter table test.table1 exchange partition p0 with table test.table2" ,
349+ Type : byte (timodel .ActionExchangeTablePartition ),
350+ SchemaName : "test" ,
351+ TableName : "table1" ,
352+ ExtraSchemaName : "test" ,
353+ ExtraTableName : "table2" ,
354+ FinishedTs : 100 ,
355+ TableInfo : tableInfo ,
356+ }
357+ ddlEvent .MultipleTableInfos = append ([]* common.TableInfo {tableInfo }, tc .multipleTableInfos ... )
358+
359+ err = cloudStorageSink .WriteBlockEvent (ddlEvent )
360+ require .ErrorContains (t , err , "invalid exchange partition ddl event, source table info is missing" )
361+ })
362+ }
363+ }
364+
210365func TestWriteCheckpointEvent (t * testing.T ) {
211366 parentDir := t .TempDir ()
212367 uri := fmt .Sprintf ("file:///%s?protocol=csv" , parentDir )
0 commit comments