Skip to content

Commit 2bd3d22

Browse files
authored
Cosmos DB Output Binding - Conformance & Progress towards GA (#1180)
* cosmosdb binding - not as flexible as I'd like conformance tests now pass * add tests for new UUID injection logic * Use nested property as partition key value * avoid repeated string constants * Disable Identification Hydrator to avoid struct requirement * Remove struct * Simplify PR * Add comments ofor code maintenance
1 parent ca8cf5c commit 2bd3d22

File tree

5 files changed

+85
-17
lines changed

5 files changed

+85
-17
lines changed

bindings/azure/cosmosdb/cosmosdb.go

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ func (c *CosmosDB) Init(metadata bindings.Metadata) error {
6868
}
6969
config = documentdb.NewConfigWithServicePrincipal(spt)
7070
}
71+
// disable the identification hydrator (which autogenerates IDs if missing from the request)
72+
// so we aren't forced to use a struct by the upstream SDK
73+
// this allows us to provide the most flexibility in the request document sent to this binding
74+
config.IdentificationHydrator = nil
7175
client := documentdb.New(m.URL, config)
7276

7377
dbs, err := client.QueryDatabases(&documentdb.Query{
@@ -122,23 +126,28 @@ func (c *CosmosDB) Operations() []bindings.OperationKind {
122126
}
123127

124128
func (c *CosmosDB) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
125-
var obj interface{}
126-
err := json.Unmarshal(req.Data, &obj)
127-
if err != nil {
128-
return nil, err
129-
}
129+
switch req.Operation {
130+
case bindings.CreateOperation:
131+
var obj interface{}
132+
err := json.Unmarshal(req.Data, &obj)
133+
if err != nil {
134+
return nil, err
135+
}
130136

131-
val, err := c.getPartitionKeyValue(c.partitionKey, obj)
132-
if err != nil {
133-
return nil, err
134-
}
137+
val, err := c.getPartitionKeyValue(c.partitionKey, obj)
138+
if err != nil {
139+
return nil, err
140+
}
135141

136-
_, err = c.client.CreateDocument(c.collection.Self, obj, documentdb.PartitionKey(val))
137-
if err != nil {
138-
return nil, err
139-
}
142+
_, err = c.client.CreateDocument(c.collection.Self, obj, documentdb.PartitionKey(val))
143+
if err != nil {
144+
return nil, err
145+
}
140146

141-
return nil, nil
147+
return nil, nil
148+
default:
149+
return nil, fmt.Errorf("operation kind %s not supported", req.Operation)
150+
}
142151
}
143152

144153
func (c *CosmosDB) getPartitionKeyValue(key string, obj interface{}) (interface{}, error) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: dapr.io/v1alpha1
2+
kind: Component
3+
metadata:
4+
name: azure-cosmosdb-binding
5+
namespace: default
6+
spec:
7+
type: bindings.azure.cosmosdb
8+
version: v1
9+
metadata:
10+
- name: url
11+
value: ${{AzureCosmosDBUrl}}
12+
- name: masterKey
13+
value: ${{AzureCosmosDBMasterKey}}
14+
- name: database
15+
value: ${{AzureCosmosDB}}
16+
- name: collection
17+
value: ${{AzureCosmosDBCollection}}
18+
- name: partitionKey
19+
value: partitionKey

tests/config/bindings/tests.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ components:
1717
config:
1818
output:
1919
blobName: $((uuid))
20+
- component: azure.cosmosdb
21+
operations: ["create", "operations"]
22+
config:
23+
outputData: '{"id": "$((uuid))", "orderid": "abcdef-test", "partitionKey": "partitionValue", "nestedproperty": {"subproperty": "something of value for testing"}, "description": "conformance test item"}'
2024
- component: azure.eventhubs
2125
operations: ["create", "operations", "read"]
2226
- component: azure.eventgrid

tests/conformance/common.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package conformance
77

88
import (
9+
"encoding/json"
910
"errors"
1011
"fmt"
1112
"io/ioutil"
@@ -27,6 +28,7 @@ import (
2728
"github.com/dapr/kit/logger"
2829

2930
b_azure_blobstorage "github.com/dapr/components-contrib/bindings/azure/blobstorage"
31+
b_azure_cosmosdb "github.com/dapr/components-contrib/bindings/azure/cosmosdb"
3032
b_azure_eventgrid "github.com/dapr/components-contrib/bindings/azure/eventgrid"
3133
b_azure_eventhubs "github.com/dapr/components-contrib/bindings/azure/eventhubs"
3234
b_azure_servicebusqueues "github.com/dapr/components-contrib/bindings/azure/servicebusqueues"
@@ -131,6 +133,16 @@ func ParseConfigurationMap(t *testing.T, configMap map[string]interface{}) {
131133
val = uuid.New().String()
132134
t.Logf("Generated UUID %s", val)
133135
configMap[k] = val
136+
} else {
137+
jsonMap := make(map[string]interface{})
138+
err := json.Unmarshal([]byte(val), &jsonMap)
139+
if err == nil {
140+
ParseConfigurationMap(t, jsonMap)
141+
mapBytes, err := json.Marshal(jsonMap)
142+
if err == nil {
143+
configMap[k] = string(mapBytes)
144+
}
145+
}
134146
}
135147
case map[string]interface{}:
136148
ParseConfigurationMap(t, val)
@@ -149,6 +161,16 @@ func parseConfigurationInterfaceMap(t *testing.T, configMap map[interface{}]inte
149161
val = uuid.New().String()
150162
t.Logf("Generated UUID %s", val)
151163
configMap[k] = val
164+
} else {
165+
jsonMap := make(map[string]interface{})
166+
err := json.Unmarshal([]byte(val), &jsonMap)
167+
if err == nil {
168+
ParseConfigurationMap(t, jsonMap)
169+
mapBytes, err := json.Marshal(jsonMap)
170+
if err == nil {
171+
configMap[k] = string(mapBytes)
172+
}
173+
}
152174
}
153175
case map[string]interface{}:
154176
ParseConfigurationMap(t, val)
@@ -405,6 +427,8 @@ func loadOutputBindings(tc TestComponent) bindings.OutputBinding {
405427
binding = b_azure_eventgrid.NewAzureEventGrid(testLogger)
406428
case eventhubs:
407429
binding = b_azure_eventhubs.NewAzureEventHubs(testLogger)
430+
case "azure.cosmosdb":
431+
binding = b_azure_cosmosdb.NewCosmosDB(testLogger)
408432
case kafka:
409433
binding = b_kafka.NewKafka(testLogger)
410434
case "http":

tests/conformance/common_test.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package conformance
77

88
import (
9+
"encoding/json"
910
"os"
1011
"testing"
1112

@@ -104,15 +105,26 @@ func TestConvertMetadataToProperties(t *testing.T) {
104105

105106
func TestParseConfigurationMap(t *testing.T) {
106107
testMap := map[string]interface{}{
107-
"key": "$((uuid))",
108-
"blob": "testblob",
108+
"key": "$((uuid))",
109+
"blob": "testblob",
110+
"mapString": `{"nestedkey": "$((uuid))", "somethingtested": "somevalue"}`,
111+
"map": map[string]interface{}{
112+
"nestedkey": "$((uuid))",
113+
},
109114
}
110115

111116
ParseConfigurationMap(t, testMap)
112-
assert.Equal(t, 2, len(testMap))
117+
assert.Equal(t, 4, len(testMap))
113118
assert.Equal(t, "testblob", testMap["blob"])
114119
_, err := uuid.ParseBytes([]byte(testMap["key"].(string)))
115120
assert.NoError(t, err)
121+
122+
var nestedMap map[string]interface{}
123+
json.Unmarshal([]byte(testMap["mapString"].(string)), &nestedMap)
124+
_, err = uuid.ParseBytes([]byte(nestedMap["nestedkey"].(string)))
125+
assert.NoError(t, err)
126+
_, err = uuid.ParseBytes([]byte(testMap["map"].(map[string]interface{})["nestedkey"].(string)))
127+
assert.NoError(t, err)
116128
}
117129

118130
func TestConvertComponentNameToPath(t *testing.T) {

0 commit comments

Comments
 (0)