Add ETag operation to statestore conformance test (#716)

* Add ETag operation to statestore conformance test

ETags are used to enable concurrency guarantees and are part of the
statestore specification. Not all stores need to use them, however
if the store chooses to, it should be part of the certification
process. This commit adds a simple ETag test scenario that verifies
the basic behaviors of ETags.

https://github.com/dapr/components-contrib/issues/711

* Update tests.yml

* Error on mongodb when etag does not match on delete.

Co-authored-by: Artur Souza <artursouza.ms@outlook.com>
This commit is contained in:
halspang 2021-03-03 12:27:10 -08:00 committed by GitHub
parent 3ebe447759
commit cb3c881d39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 1 deletions

View File

@ -209,11 +209,15 @@ func (m *MongoDB) deleteInternal(ctx context.Context, req *state.DeleteRequest)
if req.ETag != nil {
filter[etag] = *req.ETag
}
_, err := m.collection.DeleteOne(ctx, filter)
result, err := m.collection.DeleteOne(ctx, filter)
if err != nil {
return err
}
if result.DeletedCount == 0 && req.ETag != nil {
return errors.New("key or etag not found")
}
return nil
}

View File

@ -382,4 +382,75 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
}
})
}
// Supporting etags requires support for get, set, and delete so they are not checked individually
if config.HasOperation("etag") {
t.Run("etag", func(t *testing.T) {
testKey := "etagTest"
firstValue := []byte("testValue1")
secondValue := []byte("testValue2")
fakeEtag := "not-an-etag"
// Delete any potential object, it's important to start from a clean slate.
err := statestore.Delete(&state.DeleteRequest{
Key: testKey,
})
assert.Nil(t, err)
// Set an object.
err = statestore.Set(&state.SetRequest{
Key: testKey,
Value: firstValue,
})
assert.Nil(t, err)
// Validate the set.
res, err := statestore.Get(&state.GetRequest{
Key: testKey,
})
assert.Nil(t, err)
assert.Equal(t, firstValue, res.Data)
etag := res.ETag
// Try and update with wrong ETag, expect failure.
err = statestore.Set(&state.SetRequest{
Key: testKey,
Value: secondValue,
ETag: &fakeEtag,
})
assert.NotNil(t, err)
// Try and update with corect ETag, expect success.
err = statestore.Set(&state.SetRequest{
Key: testKey,
Value: secondValue,
ETag: &etag,
})
assert.Nil(t, err)
// Validate the set.
res, err = statestore.Get(&state.GetRequest{
Key: testKey,
})
assert.Nil(t, err)
assert.Equal(t, secondValue, res.Data)
assert.NotEqual(t, etag, res.ETag)
etag = res.ETag
// Try and delete with wrong ETag, expect failure.
err = statestore.Delete(&state.DeleteRequest{
Key: testKey,
ETag: &fakeEtag,
})
assert.NotNil(t, err)
// Try and delete with correct ETag, expect success.
err = statestore.Delete(&state.DeleteRequest{
Key: testKey,
ETag: &etag,
})
assert.Nil(t, err)
})
}
}