@@ -23,7 +23,12 @@ import (
2323
2424 "github.com/stretchr/testify/suite"
2525
26- "github.com/tikv/pd/pkg/mcs/utils/constant"
26+ "github.com/pingcap/failpoint"
27+ "github.com/pingcap/kvproto/pkg/keyspacepb"
28+
29+ "github.com/tikv/pd/pkg/keyspace"
30+ kgconstant "github.com/tikv/pd/pkg/keyspace/constant"
31+ mcsconstant "github.com/tikv/pd/pkg/mcs/utils/constant"
2732 "github.com/tikv/pd/pkg/storage/endpoint"
2833 "github.com/tikv/pd/server/apiv2/handlers"
2934 "github.com/tikv/pd/tests"
@@ -100,7 +105,7 @@ func (suite *keyspaceGroupTestSuite) TestCreateKeyspaceGroups() {
100105 // invalid ID.
101106 kgs = & handlers.CreateKeyspaceGroupParams {KeyspaceGroups : []* endpoint.KeyspaceGroup {
102107 {
103- ID : constant .MaxKeyspaceGroupCount + 1 ,
108+ ID : mcsconstant .MaxKeyspaceGroupCount + 1 ,
104109 UserKind : endpoint .Standard .String (),
105110 },
106111 }}
@@ -141,7 +146,7 @@ func (suite *keyspaceGroupTestSuite) TestSplitKeyspaceGroup() {
141146 ID : uint32 (1 ),
142147 UserKind : endpoint .Standard .String (),
143148 Keyspaces : []uint32 {111 , 222 , 333 },
144- Members : make ([]endpoint.KeyspaceGroupMember , constant .DefaultKeyspaceGroupReplicaCount ),
149+ Members : make ([]endpoint.KeyspaceGroupMember , mcsconstant .DefaultKeyspaceGroupReplicaCount ),
145150 },
146151 }}
147152
@@ -248,7 +253,6 @@ func (suite *keyspaceGroupTestSuite) TestKeyspaceGroupErrorMessage() {
248253 re .NoError (json .NewDecoder (resp .Body ).Decode (& errorMsg ))
249254 re .NotEmpty (errorMsg , "Error message should not be empty" )
250255 re .Contains (errorMsg , "invalid" , "Error message should indicate invalid input" )
251-
252256 // Test SetPriorityForKeyspaceGroup with invalid JSON
253257 httpReq , err = http .NewRequest (
254258 http .MethodPatch ,
@@ -266,3 +270,108 @@ func (suite *keyspaceGroupTestSuite) TestKeyspaceGroupErrorMessage() {
266270 re .NotEmpty (errorMsg , "Error message should not be empty" )
267271 re .Contains (errorMsg , "invalid" , "Error message should indicate invalid input" )
268272}
273+
274+ func (suite * keyspaceGroupTestSuite ) TestRemoveKeyspacesFromGroup () {
275+ re := suite .Require ()
276+ re .NoError (failpoint .Enable ("github.com/tikv/pd/server/delayStartServerLoop" , `return(true)` ))
277+ re .NoError (failpoint .Enable ("github.com/tikv/pd/pkg/keyspace/skipSplitRegion" , "return(true)" ))
278+
279+ keyspaceManager := suite .server .GetKeyspaceManager ()
280+ re .NotNil (keyspaceManager )
281+
282+ // Create test keyspaces (automatically added to default keyspace group 0)
283+ keyspaceMeta1 , err := keyspaceManager .CreateKeyspace (& keyspace.CreateKeyspaceRequest {
284+ Name : "test_keyspace_1" ,
285+ CreateTime : 0 ,
286+ })
287+ re .NoError (err )
288+ keyspaceID1 := keyspaceMeta1 .GetId ()
289+
290+ keyspaceMeta2 , err := keyspaceManager .CreateKeyspace (& keyspace.CreateKeyspaceRequest {
291+ Name : "test_keyspace_2" ,
292+ CreateTime : 0 ,
293+ })
294+ re .NoError (err )
295+ keyspaceID2 := keyspaceMeta2 .GetId ()
296+
297+ keyspaceMeta3 , err := keyspaceManager .CreateKeyspace (& keyspace.CreateKeyspaceRequest {
298+ Name : "test_keyspace_3" ,
299+ CreateTime : 0 ,
300+ })
301+ re .NoError (err )
302+ keyspaceID3 := keyspaceMeta3 .GetId ()
303+
304+ // Verify all keyspaces are in the default group
305+ kg := MustLoadKeyspaceGroupByID (re , suite .server , kgconstant .DefaultKeyspaceGroupID )
306+ re .Contains (kg .Keyspaces , keyspaceID1 )
307+ re .Contains (kg .Keyspaces , keyspaceID2 )
308+ re .Contains (kg .Keyspaces , keyspaceID3 )
309+
310+ // Test 1: Try to remove ENABLED keyspaces (should succeed but nothing removed)
311+ kg = MustRemoveKeyspacesFromGroup (re , suite .server , kgconstant .DefaultKeyspaceGroupID ,
312+ []uint32 {keyspaceID1 })
313+ // Verify nothing is removed (keyspace is still there because it's ENABLED)
314+ re .Contains (kg .Keyspaces , keyspaceID1 )
315+
316+ // Test 2: Update keyspaces to ARCHIVED/TOMBSTONE state and batch remove
317+ // Set keyspace1 to ARCHIVED
318+ _ , err = keyspaceManager .UpdateKeyspaceStateByID (keyspaceID1 , keyspacepb .KeyspaceState_DISABLED , 0 )
319+ re .NoError (err )
320+ _ , err = keyspaceManager .UpdateKeyspaceStateByID (keyspaceID1 , keyspacepb .KeyspaceState_ARCHIVED , 0 )
321+ re .NoError (err )
322+
323+ // Set keyspace2 to TOMBSTONE
324+ _ , err = keyspaceManager .UpdateKeyspaceStateByID (keyspaceID2 , keyspacepb .KeyspaceState_DISABLED , 0 )
325+ re .NoError (err )
326+ _ , err = keyspaceManager .UpdateKeyspaceStateByID (keyspaceID2 , keyspacepb .KeyspaceState_ARCHIVED , 0 )
327+ re .NoError (err )
328+ _ , err = keyspaceManager .UpdateKeyspaceStateByID (keyspaceID2 , keyspacepb .KeyspaceState_TOMBSTONE , 0 )
329+ re .NoError (err )
330+
331+ // Batch remove keyspace1 and keyspace2
332+ MustRemoveKeyspacesFromGroup (re , suite .server , kgconstant .DefaultKeyspaceGroupID ,
333+ []uint32 {keyspaceID1 , keyspaceID2 })
334+
335+ // Verify both keyspaces are removed
336+ kg = MustLoadKeyspaceGroupByID (re , suite .server , kgconstant .DefaultKeyspaceGroupID )
337+ re .NotContains (kg .Keyspaces , keyspaceID1 )
338+ re .NotContains (kg .Keyspaces , keyspaceID2 )
339+ re .Contains (kg .Keyspaces , keyspaceID3 ) // keyspace3 should still be there
340+
341+ // Test 3: Mix valid and invalid keyspaces
342+ // Set keyspace3 to ARCHIVED
343+ _ , err = keyspaceManager .UpdateKeyspaceStateByID (keyspaceID3 , keyspacepb .KeyspaceState_DISABLED , 0 )
344+ re .NoError (err )
345+ _ , err = keyspaceManager .UpdateKeyspaceStateByID (keyspaceID3 , keyspacepb .KeyspaceState_ARCHIVED , 0 )
346+ re .NoError (err )
347+
348+ // Include: valid (keyspace3), already removed (keyspace1), non-existent (99999)
349+ // Should only remove keyspace3, others are skipped
350+ MustRemoveKeyspacesFromGroup (re , suite .server , kgconstant .DefaultKeyspaceGroupID ,
351+ []uint32 {keyspaceID3 , keyspaceID1 , 99999 })
352+
353+ // Verify only keyspace3 is removed
354+ kg = MustLoadKeyspaceGroupByID (re , suite .server , kgconstant .DefaultKeyspaceGroupID )
355+ re .NotContains (kg .Keyspaces , keyspaceID3 )
356+
357+ // Test 4: Try to remove from non-existent group
358+ FailRemoveKeyspacesFromGroupWithCode (re , suite .server , 999 ,
359+ []uint32 {keyspaceID1 }, http .StatusInternalServerError )
360+
361+ // Test 5: Try to remove with empty keyspace list (should fail - empty list)
362+ FailRemoveKeyspacesFromGroupWithCode (re , suite .server , kgconstant .DefaultKeyspaceGroupID ,
363+ []uint32 {}, http .StatusBadRequest )
364+
365+ // Test 6: All keyspaces in wrong state (should succeed but nothing removed)
366+ keyspaceMeta4 , err := keyspaceManager .CreateKeyspace (& keyspace.CreateKeyspaceRequest {
367+ Name : "test_keyspace_4" ,
368+ CreateTime : 0 ,
369+ })
370+ re .NoError (err )
371+ keyspaceID4 := keyspaceMeta4 .GetId ()
372+
373+ kg = MustRemoveKeyspacesFromGroup (re , suite .server , kgconstant .DefaultKeyspaceGroupID ,
374+ []uint32 {keyspaceID4 }) // ENABLED state, will be skipped
375+ // Verify keyspace4 is still there
376+ re .Contains (kg .Keyspaces , keyspaceID4 )
377+ }
0 commit comments