@@ -337,7 +337,7 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
337337 // so will only assert require.NoError(t, err) finally, i.e. when current implementation
338338 // implements ping in existing stable components
339339 if err != nil {
340- require .EqualError (t , err , "ping is not implemented by this state store" )
340+ require .ErrorIs (t , err , state . ErrPingNotImplemented )
341341 } else {
342342 require .NoError (t , err )
343343 }
@@ -575,7 +575,7 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
575575 }
576576
577577 transactionStore , ok := statestore .(state.TransactionalStore )
578- assert .True (t , ok )
578+ require .True (t , ok )
579579 sort .Ints (transactionGroups )
580580 for _ , transactionGroup := range transactionGroups {
581581 t .Logf ("Testing transaction #%d" , transactionGroup )
@@ -704,7 +704,12 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
704704 }
705705 })
706706 } else {
707- t .Run ("transactional feature not present" , func (t * testing.T ) {
707+ t .Run ("component does not implement TransactionalStore interface" , func (t * testing.T ) {
708+ _ , ok := statestore .(state.TransactionalStore )
709+ require .False (t , ok )
710+ })
711+
712+ t .Run ("Transactional feature not present" , func (t * testing.T ) {
708713 features := statestore .Features ()
709714 assert .False (t , state .FeatureTransactional .IsPresent (features ))
710715 })
@@ -1302,6 +1307,109 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
13021307 })
13031308 })
13041309 }
1310+
1311+ if config .HasOperation ("delete-with-prefix" ) {
1312+ keys := map [string ]bool {
1313+ "prefix||key1" : true ,
1314+ "prefix||key2" : true ,
1315+ "prefix||prefix2||key3" : true ,
1316+ "other-prefix||key1" : true ,
1317+ "no-prefix" : true ,
1318+ }
1319+ validateFn := func () func (t * testing.T ) {
1320+ return func (t * testing.T ) {
1321+ for key , exists := range keys {
1322+ res , err := statestore .Get (context .Background (), & state.GetRequest {Key : key })
1323+ require .NoErrorf (t , err , "Error retrieving key '%s'" , key )
1324+ if exists {
1325+ require .NotEmptyf (t , res .Data , "Expected key '%s' to be not empty" , key )
1326+ } else {
1327+ require .Emptyf (t , res .Data , "Expected key '%s' to be empty, but contained data: %s" , key , string (res .Data ))
1328+ }
1329+ }
1330+ }
1331+ }
1332+
1333+ var statestoreDeleteWithPrefix state.DeleteWithPrefix
1334+ t .Run ("component implements DeleteWithPrefix interface" , func (t * testing.T ) {
1335+ var ok bool
1336+ statestoreDeleteWithPrefix , ok = statestore .(state.DeleteWithPrefix )
1337+ require .True (t , ok )
1338+ })
1339+
1340+ t .Run ("DeleteWithPrefix feature present" , func (t * testing.T ) {
1341+ features := statestore .Features ()
1342+ require .True (t , state .FeatureDeleteWithPrefix .IsPresent (features ))
1343+ })
1344+
1345+ t .Run ("set test data" , func (t * testing.T ) {
1346+ err := statestore .BulkSet (context .Background (), []state.SetRequest {
1347+ {Key : "prefix||key1" , Value : []byte ("Ovid, Metamorphoseon" )},
1348+ {Key : "prefix||key2" , Value : []byte ("In nova fert animus mutatas dicere formas" )},
1349+ {Key : "prefix||prefix2||key3" , Value : []byte ("corpora; di, coeptis (nam vos mutastis et illas)" )},
1350+ {Key : "other-prefix||key1" , Value : []byte ("adspirate meis primaque ab origine mundi" )}, // Note this still has "prefix||" but not at the start of the string
1351+ {Key : "no-prefix" , Value : []byte ("ad mea perpetuum deducite tempora carmen." )},
1352+ }, state.BulkStoreOpts {})
1353+ require .NoError (t , err )
1354+
1355+ t .Run ("all keys are set" , validateFn ())
1356+ })
1357+
1358+ require .False (t , t .Failed (), "Cannot continue if previous test failed" )
1359+
1360+ t .Run ("delete with prefix" , func (t * testing.T ) {
1361+ res , err := statestoreDeleteWithPrefix .DeleteWithPrefix (context .Background (), state.DeleteWithPrefixRequest {
1362+ // Does not delete "prefix||prefix2||key3"
1363+ Prefix : "prefix||" ,
1364+ })
1365+ require .NoError (t , err )
1366+ assert .Equal (t , int64 (2 ), res .Count )
1367+
1368+ keys ["prefix||key1" ] = false
1369+ keys ["prefix||key2" ] = false
1370+
1371+ t .Run ("validate keys present" , validateFn ())
1372+ })
1373+
1374+ t .Run ("delete with prefix appends ||" , func (t * testing.T ) {
1375+ res , err := statestoreDeleteWithPrefix .DeleteWithPrefix (context .Background (), state.DeleteWithPrefixRequest {
1376+ // Appends || automatically
1377+ Prefix : "other-prefix" ,
1378+ })
1379+ require .NoError (t , err )
1380+ assert .Equal (t , int64 (1 ), res .Count )
1381+
1382+ keys ["other-prefix||key1" ] = false
1383+
1384+ t .Run ("validate keys present" , validateFn ())
1385+ })
1386+
1387+ t .Run ("error when prefix is empty" , func (t * testing.T ) {
1388+ _ , err := statestoreDeleteWithPrefix .DeleteWithPrefix (context .Background (), state.DeleteWithPrefixRequest {
1389+ Prefix : "" ,
1390+ })
1391+ require .Error (t , err )
1392+ require .ErrorContains (t , err , "prefix is required" )
1393+ })
1394+
1395+ t .Run ("error when prefix is ||" , func (t * testing.T ) {
1396+ _ , err := statestoreDeleteWithPrefix .DeleteWithPrefix (context .Background (), state.DeleteWithPrefixRequest {
1397+ Prefix : "||" ,
1398+ })
1399+ require .Error (t , err )
1400+ require .ErrorContains (t , err , "prefix is required" )
1401+ })
1402+ } else {
1403+ t .Run ("component does not implement DeleteWithPrefix interface" , func (t * testing.T ) {
1404+ _ , ok := statestore .(state.DeleteWithPrefix )
1405+ require .False (t , ok )
1406+ })
1407+
1408+ t .Run ("DeleteWithPrefix feature not present" , func (t * testing.T ) {
1409+ features := statestore .Features ()
1410+ require .False (t , state .FeatureDeleteWithPrefix .IsPresent (features ))
1411+ })
1412+ }
13051413}
13061414
13071415func assertEquals (t * testing.T , value any , res * state.GetResponse ) {
0 commit comments