Add CosmosDB state store conformance tests (#622)
* Add CosmosDB conformance tests * Fix workflow & lint * Add more disclaimers to README.md
This commit is contained in:
parent
079d0b1bd0
commit
3086450ced
|
@ -23,16 +23,33 @@ jobs:
|
||||||
#
|
#
|
||||||
# The KeyVault policy must be granted to your Service Principal using
|
# The KeyVault policy must be granted to your Service Principal using
|
||||||
# az keyvault set-policy -n $AZURE_KEYVAULT --secret-permissions get list --spn $SPN_CLIENT_ID
|
# az keyvault set-policy -n $AZURE_KEYVAULT --secret-permissions get list --spn $SPN_CLIENT_ID
|
||||||
AZURE_KEYVAULT: conformance-tests-secret
|
AZURE_KEYVAULT: dapr-conf-tests
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false # Keep running even if one component fails
|
fail-fast: false # Keep running even if one component fails
|
||||||
matrix:
|
matrix:
|
||||||
# List here all the components that needs to be invoked in this workflow.
|
# List here all the components that needs to be invoked in this workflow.
|
||||||
component:
|
component:
|
||||||
- state.redis
|
|
||||||
- pubsub.redis
|
- pubsub.redis
|
||||||
- secretstores.localenv
|
- secretstores.localenv
|
||||||
|
- state.cosmosdb
|
||||||
|
- state.redis
|
||||||
|
include:
|
||||||
|
- component: state.cosmosdb
|
||||||
|
# Unfortunately, Azure secrets can't have underscores in
|
||||||
|
# names, while environment variables with hyphens ('-') are
|
||||||
|
# troublesome.
|
||||||
|
#
|
||||||
|
# We work around here by leveraging the fact that
|
||||||
|
# environment variable names are case sensitive, so
|
||||||
|
# CamelCase would still work.
|
||||||
|
#
|
||||||
|
# That is slightly better than something like
|
||||||
|
# AZURECOSMOSDBMASTERKEY, which is extremely hard to read
|
||||||
|
# and errorprone.
|
||||||
|
#
|
||||||
|
# Only list the secrets you need for this component.
|
||||||
|
required-secrets: AzureCosmosDBMasterKey,AzureCosmosDBUrl,AzureCosmosDB,AzureCosmosDBCollection
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code onto GOPATH
|
- name: Check out code onto GOPATH
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
@ -65,11 +82,11 @@ jobs:
|
||||||
NAME=$(echo ${{ matrix.component }} | cut -d. -f2)
|
NAME=$(echo ${{ matrix.component }} | cut -d. -f2)
|
||||||
KIND_UPPER="$(tr '[:lower:]' '[:upper:]' <<< ${KIND:0:1})${KIND:1}"
|
KIND_UPPER="$(tr '[:lower:]' '[:upper:]' <<< ${KIND:0:1})${KIND:1}"
|
||||||
|
|
||||||
if [ ${KIND}=="secretstores" ]; then
|
if [ "${KIND}" = "secretstores" ]; then
|
||||||
KIND_UPPER=SecretStore
|
KIND_UPPER=SecretStore
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${KIND}=="output-binding" ]; then
|
if [ "${KIND}" = "output-binding" ]; then
|
||||||
KIND_UPPER=OutputBinding
|
KIND_UPPER=OutputBinding
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -71,6 +71,7 @@ require (
|
||||||
gopkg.in/couchbase/gocb.v1 v1.6.4
|
gopkg.in/couchbase/gocb.v1 v1.6.4
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
k8s.io/api v0.20.0
|
k8s.io/api v0.20.0
|
||||||
|
k8s.io/apiextensions-apiserver v0.17.2
|
||||||
k8s.io/apimachinery v0.20.0
|
k8s.io/apimachinery v0.20.0
|
||||||
k8s.io/client-go v0.20.0
|
k8s.io/client-go v0.20.0
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: dapr.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: statestore
|
||||||
|
spec:
|
||||||
|
type: state.azure.cosmosdb
|
||||||
|
version: v1
|
||||||
|
metadata:
|
||||||
|
- name: url
|
||||||
|
value: ${{AzureCosmosDBUrl}}
|
||||||
|
- name: masterKey
|
||||||
|
value: ${{AzureCosmosDBMasterKey}}
|
||||||
|
- name: database
|
||||||
|
value: ${{AzureCosmosDB}}
|
||||||
|
- name: collection
|
||||||
|
value: ${{AzureCosmosDBCollection}}
|
|
@ -4,4 +4,13 @@ components:
|
||||||
allOperations: true
|
allOperations: true
|
||||||
config:
|
config:
|
||||||
maxInitDuration: 30
|
maxInitDuration: 30
|
||||||
maxSetDuration: 20
|
maxSetDuration: 20
|
||||||
|
- component: cosmosdb
|
||||||
|
allOperations: true
|
||||||
|
config:
|
||||||
|
maxInitDuration: 900
|
||||||
|
maxSetDuration: 300
|
||||||
|
maxGetDuration: 300
|
||||||
|
maxBulkSetDuration: 300
|
||||||
|
maxBulkDeleteDuration: 300
|
||||||
|
maxDeleteDuration: 300
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
2. All the conformance tests are within the `tests/conformance` directory.
|
2. All the conformance tests are within the `tests/conformance` directory.
|
||||||
3. All the configurations are in the `tests/config` directory.
|
3. All the configurations are in the `tests/config` directory.
|
||||||
4. Each of the component specific `component` definition are in their specific `component type` folder in the `tests/config` folder. For eg: `redis` statestore component definition within `state` directory. And the other component types are `state`, `secretstores`, `pubsub` and `bindings`.
|
4. Each of the component specific `component` definition are in their specific `component type` folder in the `tests/config` folder. For eg: `redis` statestore component definition within `state` directory. And the other component types are `state`, `secretstores`, `pubsub` and `bindings`.
|
||||||
5. Similar to the component definitions, each component type has its own set of the conformance tests definitions.
|
5. Similar to the component definitions, each component type has its own set of the conformance tests definitions.
|
||||||
6. Each component type contains a `tests.yml` definition that defines the component to be tested along with component specific test configuration.
|
6. Each component type contains a `tests.yml` definition that defines the component to be tested along with component specific test configuration.
|
||||||
7. All the tests configurations are defined in `common.go` file.
|
7. All the tests configurations are defined in `common.go` file.
|
||||||
8. Each component type has its own `_test` file to trigger the conformance tests.
|
8. Each component type has its own `_test` file to trigger the conformance tests.
|
||||||
|
|
||||||
## Running conformance tests
|
## Running conformance tests
|
||||||
1. Test test setup is independent of the test run.
|
1. Test test setup is independent of the test run.
|
||||||
2. Run Redis with 6379 exposed locally.
|
2. Run Redis with 6379 exposed locally.
|
||||||
3. Run `make conf-tests` to run the conformance tests locally.
|
3. Run `make conf-tests` to run the conformance tests locally.
|
||||||
> Note: Any component that cannot run as dockerized containers are not tested locally.
|
> Note Some conformance tests require credentials in the form of environment variables. For examples Azure CosmosDB conformance tests will need to have Azure CosmosDB credentials. You will need to supply them to make these tests pass.
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
package conformance
|
package conformance
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -5,6 +10,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -12,11 +18,13 @@ import (
|
||||||
|
|
||||||
"fortio.org/fortio/log"
|
"fortio.org/fortio/log"
|
||||||
"github.com/dapr/components-contrib/pubsub"
|
"github.com/dapr/components-contrib/pubsub"
|
||||||
|
p_servicebus "github.com/dapr/components-contrib/pubsub/azure/servicebus"
|
||||||
p_redis "github.com/dapr/components-contrib/pubsub/redis"
|
p_redis "github.com/dapr/components-contrib/pubsub/redis"
|
||||||
"github.com/dapr/components-contrib/secretstores"
|
"github.com/dapr/components-contrib/secretstores"
|
||||||
ss_local_env "github.com/dapr/components-contrib/secretstores/local/env"
|
ss_local_env "github.com/dapr/components-contrib/secretstores/local/env"
|
||||||
ss_local_file "github.com/dapr/components-contrib/secretstores/local/file"
|
ss_local_file "github.com/dapr/components-contrib/secretstores/local/file"
|
||||||
"github.com/dapr/components-contrib/state"
|
"github.com/dapr/components-contrib/state"
|
||||||
|
s_cosmosdb "github.com/dapr/components-contrib/state/azure/cosmosdb"
|
||||||
s_redis "github.com/dapr/components-contrib/state/redis"
|
s_redis "github.com/dapr/components-contrib/state/redis"
|
||||||
conf_pubsub "github.com/dapr/components-contrib/tests/conformance/pubsub"
|
conf_pubsub "github.com/dapr/components-contrib/tests/conformance/pubsub"
|
||||||
conf_secret "github.com/dapr/components-contrib/tests/conformance/secretstores"
|
conf_secret "github.com/dapr/components-contrib/tests/conformance/secretstores"
|
||||||
|
@ -74,10 +82,27 @@ func LoadComponents(componentPath string) ([]v1alpha1.Component, error) {
|
||||||
return components, nil
|
return components, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LookUpEnv(key string) string {
|
||||||
|
if val, ok := os.LookupEnv(key); ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func ConvertMetadataToProperties(items []v1alpha1.MetadataItem) map[string]string {
|
func ConvertMetadataToProperties(items []v1alpha1.MetadataItem) map[string]string {
|
||||||
properties := map[string]string{}
|
properties := map[string]string{}
|
||||||
for _, c := range items {
|
for _, c := range items {
|
||||||
properties[c.Name] = c.Value.String()
|
val := c.Value.String()
|
||||||
|
if strings.HasPrefix(c.Value.String(), "${{") {
|
||||||
|
// look up env var with that name. remove ${{}} and space
|
||||||
|
k := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(val, "${{"), "}}"))
|
||||||
|
v := LookUpEnv(k)
|
||||||
|
if v != "" {
|
||||||
|
val = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties[c.Name] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties
|
return properties
|
||||||
|
@ -172,6 +197,8 @@ func loadPubSub(tc TestComponent) pubsub.PubSub {
|
||||||
switch tc.Component {
|
switch tc.Component {
|
||||||
case "redis":
|
case "redis":
|
||||||
pubsub = p_redis.NewRedisStreams(testLogger)
|
pubsub = p_redis.NewRedisStreams(testLogger)
|
||||||
|
case "azure-servicebus":
|
||||||
|
pubsub = p_servicebus.NewAzureServiceBus(testLogger)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -198,6 +225,8 @@ func loadStateStore(tc TestComponent) state.Store {
|
||||||
switch tc.Component {
|
switch tc.Component {
|
||||||
case "redis":
|
case "redis":
|
||||||
store = s_redis.NewRedisStateStore(testLogger)
|
store = s_redis.NewRedisStateStore(testLogger)
|
||||||
|
case "cosmosdb":
|
||||||
|
store = s_cosmosdb.NewCosmosDBStateStore(testLogger)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package conformance
|
package conformance
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/dapr/dapr/pkg/apis/components/v1alpha1"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDecodeYaml(t *testing.T) {
|
func TestDecodeYaml(t *testing.T) {
|
||||||
|
@ -40,3 +43,36 @@ func TestIsYaml(t *testing.T) {
|
||||||
resp = isYaml("test.exe")
|
resp = isYaml("test.exe")
|
||||||
assert.False(t, resp)
|
assert.False(t, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLookUpEnv(t *testing.T) {
|
||||||
|
os.Setenv("CONF_TEST_KEY", "testval")
|
||||||
|
defer os.Unsetenv("CONF_TEST_KEY")
|
||||||
|
r := LookUpEnv("CONF_TEST_KEY")
|
||||||
|
assert.Equal(t, "testval", r)
|
||||||
|
r = LookUpEnv("CONF_TEST_NOT_THERE")
|
||||||
|
assert.Equal(t, "", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertMetadataToProperties(t *testing.T) {
|
||||||
|
items := []v1alpha1.MetadataItem{
|
||||||
|
{
|
||||||
|
Name: "test_key",
|
||||||
|
Value: v1alpha1.DynamicValue{
|
||||||
|
JSON: v1.JSON{Raw: []byte("test")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "env_var_sub",
|
||||||
|
Value: v1alpha1.DynamicValue{
|
||||||
|
JSON: v1.JSON{Raw: []byte("${{CONF_TEST_KEY}}")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
os.Setenv("CONF_TEST_KEY", "testval")
|
||||||
|
defer os.Unsetenv("CONF_TEST_KEY")
|
||||||
|
resp := ConvertMetadataToProperties(items)
|
||||||
|
assert.NotNil(t, resp)
|
||||||
|
assert.Equal(t, 2, len(resp))
|
||||||
|
assert.Equal(t, "test", resp["test_key"])
|
||||||
|
assert.Equal(t, "testval", resp["env_var_sub"])
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue