Merge branch 'master' into state-fix

This commit is contained in:
Young Bu Park 2019-10-29 16:55:12 -07:00 committed by GitHub
commit e48d4bca90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 961 additions and 565 deletions

View File

@ -0,0 +1,61 @@
# ------------------------------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------------------------------
name: components-contrib
on:
push:
branches:
- master
- release-*
tags:
- v*
pull_request:
branches:
- master
- release-*
jobs:
build:
name: Build ${{ matrix.target_os }}_${{ matrix.target_arch }} binaries
runs-on: ${{ matrix.os }}
env:
GOVER: 1.13.3
GOOS: ${{ matrix.target_os }}
GOARCH: ${{ matrix.target_arch }}
GOPROXY: https://proxy.golang.org
GOLANGCI_LINT_VER: v1.21.0
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
target_arch: [arm, amd64]
include:
- os: ubuntu-latest
target_os: linux
- os: windows-latest
target_os: windows
- os: macOS-latest
target_os: darwin
exclude:
- os: windows-latest
target_arch: arm
- os: macOS-latest
target_arch: arm
steps:
- name: Set up Go ${{ env.GOVER }}
uses: actions/setup-go@v1
with:
go-version: ${{ env.GOVER }}
- name: Check out code into the Go module directory
uses: actions/checkout@v1
- name: Install golangci-lint ${{ env.GOLANGCI_LINT_VER }}
if: matrix.target_arch != 'arm'
run: |
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${{ env.GOROOT }}/bin" "${{ env.GOLANGCI_LINT_VER }}"
- name: Run make lint
if: matrix.target_arch != 'arm'
run: make lint
- name: Run make test
if: matrix.target_arch != 'arm'
run: make test

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/dist
.idea

228
.golangci.yml Normal file
View File

@ -0,0 +1,228 @@
# options for analysis running
run:
# default concurrency is a available CPU number
concurrency: 4
# timeout for analysis, e.g. 30s, 5m, default is 1m
deadline: 5m
# exit code when at least one issue was found, default is 1
issues-exit-code: 1
# include test files or not, default is true
tests: true
# list of build tags, all linters use it. Default is empty list.
#build-tags:
# - mytag
# which dirs to skip: they won't be analyzed;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but next dirs are always skipped independently
# from this option's value:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs:
- ^vendor$
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know.
skip-files:
# - ".*\\.my\\.go$"
# - lib/bad.go
# output configuration options
output:
# colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number"
format: tab
# print lines of code with issue, default is true
print-issued-lines: true
# print linter name in the end of issue text, default is true
print-linter-name: true
# all available settings of specific linters
linters-settings:
errcheck:
# report about not checking of errors in type assetions: `a := b.(MyStruct)`;
# default is false: such cases aren't reported by default.
check-type-assertions: false
# report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
# default is false: such cases aren't reported by default.
check-blank: false
# [deprecated] comma-separated list of pairs of the form pkg:regex
# the regex is used to ignore names within pkg. (default "fmt:.*").
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
ignore: fmt:.*,io/ioutil:^Read.*
# path to a file containing a list of functions to exclude from checking
# see https://github.com/kisielk/errcheck#excluding-functions for details
exclude:
funlen:
lines: 60
statements: 40
govet:
# report about shadowed variables
check-shadowing: true
# settings per analyzer
settings:
printf: # analyzer name, run `go tool vet help` to see all analyzers
funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
# enable or disable analyzers by name
enable:
- atomicalign
enable-all: false
disable:
- shadow
disable-all: false
golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
gofmt:
# simplify code: gofmt with `-s` option, true by default
simplify: true
goimports:
# put imports beginning with prefix after 3rd-party packages;
# it's a comma-separated list of prefixes
local-prefixes:
gocyclo:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 10
gocognit:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 10
maligned:
# print struct with more effective memory layout or not, false by default
suggest-new: true
dupl:
# tokens count to trigger issue, 150 by default
threshold: 100
goconst:
# minimal length of string constant, 3 by default
min-len: 3
# minimal occurrences count to trigger, 3 by default
min-occurrences: 3
depguard:
list-type: blacklist
include-go-root: false
packages:
- github.com/sirupsen/logrus
packages-with-error-messages:
# specify an error message to output when a blacklisted package is used
github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: default
ignore-words:
- someword
lll:
# max line length, lines longer will be reported. Default is 120.
# '\t' is counted as 1 character by default, and can be changed with the tab-width option
line-length: 120
# tab width in spaces. Default to 1.
tab-width: 1
unused:
# treat code as a program (not a library) and report unused exported identifiers; default is false.
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
unparam:
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
nakedret:
# make an issue if func has more lines of code than this setting and it has naked returns; default is 30
max-func-lines: 30
prealloc:
# XXX: we don't recommend using this linter before doing performance profiling.
# For most programs usage of prealloc will be a premature optimization.
# Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.
# True by default.
simple: true
range-loops: true # Report preallocation suggestions on range loops, true by default
for-loops: false # Report preallocation suggestions on for loops, false by default
gocritic:
# Which checks should be enabled; can't be combined with 'disabled-checks';
# See https://go-critic.github.io/overview#checks-overview
# To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run`
# By default list of stable checks is used.
enabled-checks:
# Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
disabled-checks:
- regexpMust
- rangeValCopy
- hugeParam
- ifElseChain
- singleCaseSwitch
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
enabled-tags:
- performance
settings: # settings passed to gocritic
captLocal: # must be valid enabled check name
paramsOnly: true
godox:
# report any comments starting with keywords, this is useful for TODO or FIXME comments that
# might be left in the code accidentally and should be resolved before merging
keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting
- NOTE
- OPTIMIZE # marks code that should be optimized before merging
- HACK # marks hack-arounds that should be removed before merging
dogsled:
# checks assignments with too many blank identifiers; default is 2
max-blank-identifiers: 2
whitespace:
multi-if: false # Enforces newlines (or comments) after every multi-line if statement
multi-func: false # Enforces newlines (or comments) after every multi-line function signature
wsl:
# If true append is only allowed to be cuddled if appending value is
# matching variables, fields or types on line above. Default is true.
strict-append: true
# Allow calls and assignments to be cuddled as long as the lines have any
# matching variables, fields or types. Default is true.
allow-assign-and-call: true
# Allow multiline assignments to be cuddled. Default is true.
allow-multiline-assign: true
# Allow case blocks to end with a whitespace.
allow-case-traling-whitespace: true
# Allow declarations (var) to be cuddled.
allow-cuddle-declarations: false
linters:
fast: false
enable-all: true
disable:
# TODO Enforce the below linters later
- dupl
- errcheck
- funlen
- gocyclo
- gocognit
- lll
- scopelint
- unparam
- wsl

62
Makefile Normal file
View File

@ -0,0 +1,62 @@
# ------------------------------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------------------------------
################################################################################
# Variables #
################################################################################
export GO111MODULE ?= on
export GOPROXY ?= https://proxy.golang.org
export GOSUMDB ?= sum.golang.org
GIT_COMMIT = $(shell git rev-list -1 HEAD)
GIT_VERSION = $(shell git describe --always --abbrev=7 --dirty)
# By default, disable CGO_ENABLED. See the details on https://golang.org/cmd/cgo
CGO ?= 0
LOCAL_ARCH := $(shell uname -m)
ifeq ($(LOCAL_ARCH),x86_64)
TARGET_ARCH_LOCAL=amd64
else ifeq ($(shell echo $(LOCAL_ARCH) | head -c 5),armv8)
TARGET_ARCH_LOCAL=arm64
else ifeq ($(shell echo $(LOCAL_ARCH) | head -c 4),armv)
TARGET_ARCH_LOCAL=arm
else
TARGET_ARCH_LOCAL=amd64
endif
export GOARCH ?= $(TARGET_ARCH_LOCAL)
LOCAL_OS := $(shell uname)
ifeq ($(LOCAL_OS),Linux)
TARGET_OS_LOCAL = linux
else ifeq ($(LOCAL_OS),Darwin)
TARGET_OS_LOCAL = darwin
else
TARGET_OS_LOCAL ?= windows
endif
export GOOS ?= $(TARGET_OS_LOCAL)
ifeq ($(GOOS),windows)
BINARY_EXT_LOCAL:=.exe
GOLANGCI_LINT:=golangci-lint.exe
else
BINARY_EXT_LOCAL:=
GOLANGCI_LINT:=golangci-lint
endif
################################################################################
# Target: test #
################################################################################
.PHONY: test
test:
go test ./... -mod=vendor
################################################################################
# Target: lint #
################################################################################
.PHONY: lint
lint:
# Due to https://github.com/golangci/golangci-lint/issues/580, we need to add --fix for windows
$(GOLANGCI_LINT) run --fix

View File

@ -1,5 +1,11 @@
# Components Contrib
[![Go Report Card](https://goreportcard.com/badge/github.com/dapr/components-contrib)](https://goreportcard.com/report/github.com/dapr/components-contrib)
[![Build Status](https://github.com/dapr/components-contrib/workflows/components-contrib/badge.svg?event=push&branch=master)](https://github.com/dapr/components-contrib/actions?workflow=components-contrib)
[![Gitter](https://badges.gitter.im/Dapr/community.svg)](https://gitter.im/Dapr/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
The purpose of Components Contrib is to provide open, community driven reusable components for building distributed applications.
These components are being used by the [Dapr](https://github.com/dapr/dapr) project, but are separate and decoupled from it.
@ -11,6 +17,7 @@ Available component types:
* [Pub Sub](pubsub/Readme.md)
* [State Stores](state/Readme.md)
* [Secret Stores](secretstores/Readme.md)
* [Tracing Exporters](exporters/Readme.md)
For documentation on how components are being used in Dapr in a language/platform agnostic way, visit [Dapr Docs](https://github.com/dapr/docs).
@ -36,5 +43,11 @@ git clone https://github.com/dapr/components-contrib.git github.com/dapr/compone
### Running tests
```bash
go test ./...
make test
```
### Running linting
```bash
make lint
```

View File

@ -49,7 +49,7 @@ func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error {
a.metadata = m
credential, err := azblob.NewSharedKeyCredential(m.StorageAccount, m.StorageAccessKey)
if err != nil {
return fmt.Errorf("Invalid credentials with error: %s", err.Error())
return fmt.Errorf("invalid credentials with error: %s", err.Error())
}
p := azblob.NewPipeline(credential, azblob.PipelineOptions{})

View File

@ -49,22 +49,28 @@ func (c *CosmosDB) Init(metadata bindings.Metadata) error {
})
dbs, err := client.QueryDatabases(&documentdb.Query{
Query: fmt.Sprintf("SELECT * FROM ROOT r WHERE r.id='%s'", m.Database),
Query: "SELECT * FROM ROOT r WHERE r.id=@id",
Parameters: []documentdb.Parameter{
{Name: "@id", Value: m.Database},
},
})
if err != nil {
return err
} else if len(dbs) == 0 {
return fmt.Errorf("Database %s for CosmosDB state store not found", m.Database)
return fmt.Errorf("database %s for CosmosDB state store not found", m.Database)
}
c.db = &dbs[0]
colls, err := client.QueryCollections(c.db.Self, &documentdb.Query{
Query: fmt.Sprintf("SELECT * FROM ROOT r WHERE r.id='%s'", m.Collection),
Query: "SELECT * FROM ROOT r WHERE r.id=@id",
Parameters: []documentdb.Parameter{
{Name: "@id", Value: m.Collection},
},
})
if err != nil {
return err
} else if len(colls) == 0 {
return fmt.Errorf("Collection %s for CosmosDB state store not found", m.Collection)
return fmt.Errorf("collection %s for CosmosDB state store not found", m.Collection)
}
c.collection = &colls[0]

View File

@ -10,6 +10,7 @@ import (
"encoding/json"
"os"
"os/signal"
"syscall"
"time"
eventhub "github.com/Azure/azure-event-hubs-go"
@ -111,7 +112,6 @@ func (a *AzureEventHubs) Read(handler func(*bindings.ReadResponse) error) error
if a.metadata.ConsumerGroup != "" {
log.Infof("eventhubs: using consumer group %s", a.metadata.ConsumerGroup)
ops = append(ops, eventhub.ReceiveWithConsumerGroup(a.metadata.ConsumerGroup))
}
for _, partitionID := range runtimeInfo.PartitionIDs {
@ -122,7 +122,7 @@ func (a *AzureEventHubs) Read(handler func(*bindings.ReadResponse) error) error
}
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, os.Kill)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
<-signalChan
a.hub.Close(context.Background())

View File

@ -16,6 +16,7 @@ import (
)
// HTTPSource is a binding for an http url endpoint invocation
// nolint:golint
type HTTPSource struct {
metadata httpMetadata
}

View File

@ -20,5 +20,4 @@ func TestInit(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, "a", hs.metadata.URL)
assert.Equal(t, "a", hs.metadata.Method)
}

View File

@ -127,7 +127,7 @@ func (k *Kafka) Read(handler func(*bindings.ReadResponse) error) error {
config := sarama.NewConfig()
config.Version = sarama.V1_0_0_0
consumer := consumer{
c := consumer{
callback: handler,
ready: make(chan bool),
}
@ -144,18 +144,18 @@ func (k *Kafka) Read(handler func(*bindings.ReadResponse) error) error {
go func() {
defer wg.Done()
for {
if err = client.Consume(ctx, k.topics, &consumer); err != nil {
log.Errorf("error from consumer: %s", err)
if err = client.Consume(ctx, k.topics, &c); err != nil {
log.Errorf("error from c: %s", err)
}
// check if context was cancelled, signaling that the consumer should stop
// check if context was cancelled, signaling that the c should stop
if ctx.Err() != nil {
return
}
consumer.ready = make(chan bool)
c.ready = make(chan bool)
}
}()
<-consumer.ready
<-c.ready
sigterm := make(chan os.Signal, 1)
signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM)

View File

@ -17,8 +17,6 @@ import (
"github.com/stretchr/testify/assert"
)
func makerFn() interface{} { return &client.V1Namespace{} }
type staticHandler struct {
Code int
Body string
@ -64,7 +62,7 @@ func TestReadItem(t *testing.T) {
}
count := 0
i.Read(func(res *bindings.ReadResponse) error {
count = count + 1
count++
result := client.Result{}
json.Unmarshal(res.Data, &result)

View File

@ -72,12 +72,12 @@ func (m *MQTT) getMQTTMetadata(metadata bindings.Metadata) (*mqttMetadata, error
return nil, err
}
var mqttMetadata mqttMetadata
err = json.Unmarshal(b, &mqttMetadata)
var mMetadata mqttMetadata
err = json.Unmarshal(b, &mMetadata)
if err != nil {
return nil, err
}
return &mqttMetadata, nil
return &mMetadata, nil
}
func (m *MQTT) Write(req *bindings.WriteRequest) error {

View File

@ -22,5 +22,4 @@ func TestParseMetadata(t *testing.T) {
assert.Equal(t, "a", rm.Host)
assert.Equal(t, true, rm.DeleteWhenUnused)
assert.Equal(t, true, rm.Durable)
}

View File

@ -9,7 +9,6 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/dapr/components-contrib/bindings"
@ -70,7 +69,7 @@ func (r *Redis) parseMetadata(metadata bindings.Metadata) (*redisMetadata, error
func (r *Redis) Write(req *bindings.WriteRequest) error {
if val, ok := req.Metadata["key"]; ok && val != "" {
key := fmt.Sprintf(val)
key := val
res := r.client.Do(context.Background(), "SET", key, req.Data)
if err := redis.AsError(res); err != nil {
return err

View File

@ -1,11 +1,11 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package exporters
// Exporter is the interface for tracing exporter wrappers
type Exporter interface {
Init(daprID string, hostAddress string, metadata Metadata) error
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package exporters
// Exporter is the interface for tracing exporter wrappers
type Exporter interface {
Init(daprID string, hostAddress string, metadata Metadata) error
}

View File

@ -1,12 +1,12 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package exporters
// Metadata represents a set of exporter specific properties
type Metadata struct {
Properties map[string]string `json:"properties"`
Buffer *string `json:"-"`
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package exporters
// Metadata represents a set of exporter specific properties
type Metadata struct {
Properties map[string]string `json:"properties"`
Buffer *string `json:"-"`
}

View File

@ -1,66 +1,66 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package native
import (
"encoding/json"
"strconv"
"contrib.go.opencensus.io/exporter/ocagent"
"github.com/dapr/components-contrib/exporters"
"go.opencensus.io/trace"
)
// Metadata is the native exporter config
type nativeExporterMetadata struct {
AgentEndpoint string `json:"agentEndpoint"`
Enabled string `json:"enabled"`
}
// NewNativeExporter returns a new native exporter instance
func NewNativeExporter() *Exporter {
return &Exporter{}
}
// Exporter is an OpenCensus native exporter
type Exporter struct {
}
// Init creates a new native endpoint and reporter
func (l *Exporter) Init(daprID string, hostAddress string, metadata exporters.Metadata) error {
meta, err := l.getNativeMetadata(metadata)
if err != nil {
return err
}
enabled, _ := strconv.ParseBool(meta.Enabled)
if !enabled {
return nil
}
exporter, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithServiceName(daprID), ocagent.WithAddress(meta.AgentEndpoint))
if err != nil {
return err
}
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
return nil
}
func (l *Exporter) getNativeMetadata(metadata exporters.Metadata) (*nativeExporterMetadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var nativeExporterMetadata nativeExporterMetadata
err = json.Unmarshal(b, &nativeExporterMetadata)
if err != nil {
return nil, err
}
return &nativeExporterMetadata, nil
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package native
import (
"encoding/json"
"strconv"
"contrib.go.opencensus.io/exporter/ocagent"
"github.com/dapr/components-contrib/exporters"
"go.opencensus.io/trace"
)
// Metadata is the native exporter config
type nativeExporterMetadata struct {
AgentEndpoint string `json:"agentEndpoint"`
Enabled string `json:"enabled"`
}
// NewNativeExporter returns a new native exporter instance
func NewNativeExporter() *Exporter {
return &Exporter{}
}
// Exporter is an OpenCensus native exporter
type Exporter struct {
}
// Init creates a new native endpoint and reporter
func (l *Exporter) Init(daprID string, hostAddress string, metadata exporters.Metadata) error {
meta, err := l.getNativeMetadata(metadata)
if err != nil {
return err
}
enabled, _ := strconv.ParseBool(meta.Enabled)
if !enabled {
return nil
}
exporter, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithServiceName(daprID), ocagent.WithAddress(meta.AgentEndpoint))
if err != nil {
return err
}
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
return nil
}
func (l *Exporter) getNativeMetadata(metadata exporters.Metadata) (*nativeExporterMetadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var nExporterMetadata nativeExporterMetadata
err = json.Unmarshal(b, &nExporterMetadata)
if err != nil {
return nil, err
}
return &nExporterMetadata, nil
}

View File

@ -1,22 +1,22 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package native
import (
"testing"
"github.com/dapr/components-contrib/exporters"
"github.com/stretchr/testify/assert"
)
func TestParseMetadata(t *testing.T) {
m := exporters.Metadata{}
m.Properties = map[string]string{"agentEndpoint": "c"}
exporter := NewNativeExporter()
metadata, err := exporter.getNativeMetadata(m)
assert.Nil(t, err)
assert.Equal(t, "c", metadata.AgentEndpoint)
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package native
import (
"testing"
"github.com/dapr/components-contrib/exporters"
"github.com/stretchr/testify/assert"
)
func TestParseMetadata(t *testing.T) {
m := exporters.Metadata{}
m.Properties = map[string]string{"agentEndpoint": "c"}
exporter := NewNativeExporter()
metadata, err := exporter.getNativeMetadata(m)
assert.Nil(t, err)
assert.Equal(t, "c", metadata.AgentEndpoint)
}

View File

@ -1,41 +1,41 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package stringexporter
import (
"strconv"
"github.com/dapr/components-contrib/exporters"
"go.opencensus.io/trace"
)
// Metadata is the string exporter config
type stringExporterMetadata struct {
Buffer *string
}
// NewStringExporter returns a new string exporter instance
func NewStringExporter() *Exporter {
return &Exporter{}
}
// Exporter is an OpenCensus string exporter
type Exporter struct {
Buffer *string
}
// ExportSpan exports span content to the buffer
func (se *Exporter) ExportSpan(sd *trace.SpanData) {
*se.Buffer = strconv.Itoa(int(sd.Status.Code))
}
// Init creates a new string exporter endpoint and reporter
func (se *Exporter) Init(daprID string, hostAddress string, metadata exporters.Metadata) error {
se.Buffer = metadata.Buffer
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
trace.RegisterExporter(se)
return nil
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package stringexporter
import (
"strconv"
"github.com/dapr/components-contrib/exporters"
"go.opencensus.io/trace"
)
// Metadata is the string exporter config
type Metadata struct {
Buffer *string
}
// NewStringExporter returns a new string exporter instance
func NewStringExporter() *Exporter {
return &Exporter{}
}
// Exporter is an OpenCensus string exporter
type Exporter struct {
Buffer *string
}
// ExportSpan exports span content to the buffer
func (se *Exporter) ExportSpan(sd *trace.SpanData) {
*se.Buffer = strconv.Itoa(int(sd.Status.Code))
}
// Init creates a new string exporter endpoint and reporter
func (se *Exporter) Init(daprID string, hostAddress string, metadata exporters.Metadata) error {
se.Buffer = metadata.Buffer
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
trace.RegisterExporter(se)
return nil
}

View File

@ -1,70 +1,69 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package zipkin
import (
"encoding/json"
"strconv"
"contrib.go.opencensus.io/exporter/zipkin"
"github.com/dapr/components-contrib/exporters"
openzipkin "github.com/openzipkin/zipkin-go"
zipkinHTTP "github.com/openzipkin/zipkin-go/reporter/http"
"go.opencensus.io/trace"
)
// Metadata is the zipkin config
type zipkinMetadata struct {
ExporterAddress string `json:"exporterAddress"`
Enabled string `json:"enabled"`
}
// NewZipkinExporter returns a new zipkin exporter instance
func NewZipkinExporter() *Exporter {
return &Exporter{}
}
// Exporter is an OpenCensus zipkin exporter
type Exporter struct {
}
// Init creates a new zipkin endpoint and reporter
func (z *Exporter) Init(daprID string, hostAddress string, metadata exporters.Metadata) error {
meta, err := z.getZipkinMetadata(metadata)
if err != nil {
return err
}
enabled, _ := strconv.ParseBool(meta.Enabled)
if !enabled {
return nil
}
localEndpoint, err := openzipkin.NewEndpoint(daprID, hostAddress)
if err != nil {
return err
}
reporter := zipkinHTTP.NewReporter(meta.ExporterAddress)
ze := zipkin.NewExporter(reporter, localEndpoint)
trace.RegisterExporter(ze)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
return nil
}
func (z *Exporter) getZipkinMetadata(metadata exporters.Metadata) (*zipkinMetadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var zipkinMeta zipkinMetadata
err = json.Unmarshal(b, &zipkinMeta)
if err != nil {
return nil, err
}
return &zipkinMeta, nil
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package zipkin
import (
"encoding/json"
"strconv"
"contrib.go.opencensus.io/exporter/zipkin"
"github.com/dapr/components-contrib/exporters"
openzipkin "github.com/openzipkin/zipkin-go"
zipkinHTTP "github.com/openzipkin/zipkin-go/reporter/http"
"go.opencensus.io/trace"
)
// Metadata is the zipkin config
type zipkinMetadata struct {
ExporterAddress string `json:"exporterAddress"`
Enabled string `json:"enabled"`
}
// NewZipkinExporter returns a new zipkin exporter instance
func NewZipkinExporter() *Exporter {
return &Exporter{}
}
// Exporter is an OpenCensus zipkin exporter
type Exporter struct {
}
// Init creates a new zipkin endpoint and reporter
func (z *Exporter) Init(daprID string, hostAddress string, metadata exporters.Metadata) error {
meta, err := z.getZipkinMetadata(metadata)
if err != nil {
return err
}
enabled, _ := strconv.ParseBool(meta.Enabled)
if !enabled {
return nil
}
localEndpoint, err := openzipkin.NewEndpoint(daprID, hostAddress)
if err != nil {
return err
}
reporter := zipkinHTTP.NewReporter(meta.ExporterAddress)
ze := zipkin.NewExporter(reporter, localEndpoint)
trace.RegisterExporter(ze)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
return nil
}
func (z *Exporter) getZipkinMetadata(metadata exporters.Metadata) (*zipkinMetadata, error) {
b, err := json.Marshal(metadata.Properties)
if err != nil {
return nil, err
}
var zipkinMeta zipkinMetadata
err = json.Unmarshal(b, &zipkinMeta)
if err != nil {
return nil, err
}
return &zipkinMeta, nil
}

View File

@ -1,22 +1,22 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package zipkin
import (
"testing"
"github.com/dapr/components-contrib/exporters"
"github.com/stretchr/testify/assert"
)
func TestParseMetadata(t *testing.T) {
m := exporters.Metadata{}
m.Properties = map[string]string{"exporterAddress": "c"}
exporter := NewZipkinExporter()
metadata, err := exporter.getZipkinMetadata(m)
assert.Nil(t, err)
assert.Equal(t, "c", metadata.ExporterAddress)
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package zipkin
import (
"testing"
"github.com/dapr/components-contrib/exporters"
"github.com/stretchr/testify/assert"
)
func TestParseMetadata(t *testing.T) {
m := exporters.Metadata{}
m.Properties = map[string]string{"exporterAddress": "c"}
exporter := NewZipkinExporter()
metadata, err := exporter.getZipkinMetadata(m)
assert.Nil(t, err)
assert.Equal(t, "c", metadata.ExporterAddress)
}

14
go.mod
View File

@ -1,6 +1,6 @@
module github.com/dapr/components-contrib
go 1.12
go 1.13
require (
cloud.google.com/go/pubsub v1.0.1
@ -22,7 +22,9 @@ require (
github.com/Sirupsen/logrus v1.0.6
github.com/a8m/documentdb v1.2.0
github.com/aws/aws-sdk-go v1.25.0
github.com/coreos/bbolt v1.3.3 // indirect
github.com/coreos/etcd v3.3.17+incompatible // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/creack/pty v1.1.9 // indirect
@ -34,10 +36,14 @@ require (
github.com/gocql/gocql v0.0.0-20191018090344-07ace3bab0f8
github.com/google/pprof v0.0.0-20190908185732-236ed259b199 // indirect
github.com/google/uuid v1.1.1
github.com/gorilla/websocket v1.4.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.11.2 // indirect
github.com/hashicorp/consul/api v1.2.0
github.com/hashicorp/golang-lru v0.5.3 // indirect
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/jonboulle/clockwork v0.1.0 // indirect
github.com/joomcode/errorx v1.0.0 // indirect
github.com/joomcode/redispipe v0.9.0
github.com/json-iterator/go v1.1.7
@ -52,13 +58,15 @@ require (
github.com/rogpeppe/fastuuid v1.2.0 // indirect
github.com/rogpeppe/go-internal v1.4.0 // indirect
github.com/satori/go.uuid v1.2.0
github.com/soheilhy/cmux v0.1.4 // indirect
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
github.com/stretchr/testify v1.4.0
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
go.etcd.io/bbolt v1.3.3 // indirect
go.etcd.io/etcd v3.3.17+incompatible
go.opencensus.io v0.22.1
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/multierr v1.2.0 // indirect
go.uber.org/zap v1.10.0 // indirect
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad
golang.org/x/exp v0.0.0-20190927203820-447a159532ef // indirect
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a // indirect

19
go.sum
View File

@ -103,8 +103,10 @@ github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.17+incompatible h1:f/Z3EoDSx1yjaIjLQGo1diYUlQYSBrrAQ5vP8NjwXwo=
github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
@ -156,6 +158,8 @@ github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415 h1:WSBJMqJbLxsn+bTCP
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -201,7 +205,10 @@ github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@ -249,6 +256,7 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5i
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/joomcode/errorx v1.0.0 h1:RJAKLTy1Sv2Tszhu14m5RZP4VGRlhXutG/XlL1En5VM=
github.com/joomcode/errorx v1.0.0/go.mod h1:kgco15ekB6cs+4Xjzo7SPeXzx38PbJzBwbnu9qfVNHQ=
github.com/joomcode/redispipe v0.9.0 h1:NukwwIvxhg6r2lVxa1RJhEZXYPZZF/OX9WZJk+2cK1Q=
@ -261,8 +269,10 @@ github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62F
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@ -305,6 +315,7 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3 h1:EooPXg51Tn+xmWPXJUGCnJhJSpeuMlBmfJVcqIRmmv8=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin/zipkin-go v0.1.1 h1:A/ADD6HaPnAKj3yS7HjGHRK77qi41Hi0DirOOIQAeIw=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.6 h1:yXiysv1CSK7Q5yjGy1710zZGnsbMUIjluWBxtLXHPBo=
@ -339,6 +350,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.1.1 h1:VzGj7lhU7KEB9e9gMpAV/v5XT2NVSvLJhJLCWbnkgXg=
github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw=
@ -352,8 +365,11 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v3.3.17+incompatible h1:g8iRku1SID8QAW8cDlV0L/PkZlw63LSiYEHYHoE6j/s=
go.etcd.io/etcd v3.3.17+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
@ -364,6 +380,7 @@ go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.2.0 h1:6I+W7f5VwC5SV9dNrZ3qXrDB9mD0dyGOi/ZJmYw03T4=
go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
@ -449,6 +466,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -470,6 +488,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZe
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -194,8 +194,7 @@ func getCassandraMetadata(metadata state.Metadata) (*cassandraMetadata, error) {
// Delete performs a delete operation
func (c *Cassandra) Delete(req *state.DeleteRequest) error {
query := fmt.Sprintf("DELETE FROM %s WHERE key='%s'", c.table, req.Key)
return c.session.Query(query).Exec()
return c.session.Query("DELETE FROM ? WHERE key = ?", c.table, req.Key).Exec()
}
// BulkDelete performs a bulk delete operation
@ -212,8 +211,6 @@ func (c *Cassandra) BulkDelete(req []state.DeleteRequest) error {
// Get retrieves state from cassandra with a key
func (c *Cassandra) Get(req *state.GetRequest) (*state.GetResponse, error) {
query := fmt.Sprintf("SELECT value FROM %s WHERE key='%s'", c.table, req.Key)
session := c.session
if req.Options.Consistency == state.Strong {
@ -232,7 +229,7 @@ func (c *Cassandra) Get(req *state.GetRequest) (*state.GetResponse, error) {
session = sess
}
results, err := session.Query(query).Iter().SliceMap()
results, err := session.Query("SELECT value FROM ? WHERE key = ?", c.table, req.Key).Iter().SliceMap()
if err != nil {
return nil, err
}
@ -255,8 +252,6 @@ func (c *Cassandra) Set(req *state.SetRequest) error {
bt, _ = jsoniter.ConfigFastest.Marshal(req.Value)
}
query := fmt.Sprintf("INSERT INTO %s (key, value) VALUES (?, ?)", c.table)
session := c.session
if req.Options.Consistency == state.Strong {
@ -275,7 +270,7 @@ func (c *Cassandra) Set(req *state.SetRequest) error {
session = sess
}
return session.Query(query, req.Key, bt).Exec()
return session.Query("INSERT INTO ? (key, value) VALUES (?, ?)", c.table, req.Key, bt).Exec()
}
func (c *Cassandra) createSession(consistency gocql.Consistency) (*gocql.Session, error) {

View File

@ -63,22 +63,28 @@ func (c *StateStore) Init(metadata state.Metadata) error {
})
dbs, err := client.QueryDatabases(&documentdb.Query{
Query: fmt.Sprintf("SELECT * FROM ROOT r WHERE r.id='%s'", creds.Database),
Query: "SELECT * FROM ROOT r WHERE r.id=@id",
Parameters: []documentdb.Parameter{
{Name: "@id", Value: creds.Database},
},
})
if err != nil {
return err
} else if len(dbs) == 0 {
return fmt.Errorf("Database %s for CosmosDB state store not found", creds.Database)
return fmt.Errorf("database %s for CosmosDB state store not found", creds.Database)
}
c.db = &dbs[0]
colls, err := client.QueryCollections(c.db.Self, &documentdb.Query{
Query: fmt.Sprintf("SELECT * FROM ROOT r WHERE r.id='%s'", creds.Collection),
Query: "SELECT * FROM ROOT r WHERE r.id=@id",
Parameters: []documentdb.Parameter{
{Name: "@id", Value: creds.Collection},
},
})
if err != nil {
return err
} else if len(colls) == 0 {
return fmt.Errorf("Collection %s for CosmosDB state store not found", creds.Collection)
return fmt.Errorf("collection %s for CosmosDB state store not found", creds.Collection)
}
c.collection = &colls[0]
@ -102,7 +108,7 @@ func (c *StateStore) Get(req *state.GetRequest) (*state.GetResponse, error) {
_, err := c.client.QueryDocuments(
c.collection.Self,
documentdb.NewQuery("SELECT * FROM ROOT r WHERE r.id=@id", documentdb.P{"@id", key}),
documentdb.NewQuery("SELECT * FROM ROOT r WHERE r.id=@id", documentdb.P{Name: "@id", Value: key}),
&items,
options...,
)

View File

@ -19,10 +19,10 @@ import (
"google.golang.org/grpc"
)
const defaultOperationTimeout = time.Duration(10 * time.Second)
const defaultOperationTimeout = 10 * time.Second
const defaultSeparator = ","
var errMissingEndpoints = errors.New("Endpoints are required")
var errMissingEndpoints = errors.New("endpoints are required")
var errInvalidDialTimeout = errors.New("DialTimeout is invalid")
// ETCD is a state store
@ -126,7 +126,8 @@ func validateRequired(configProps *configProperties) error {
// Get retrieves state from ETCD with a key
func (r *ETCD) Get(req *state.GetRequest) (*state.GetResponse, error) {
ctx, _ := context.WithTimeout(context.Background(), r.operationTimeout)
ctx, cancel := context.WithTimeout(context.Background(), r.operationTimeout)
defer cancel()
resp, err := r.client.Get(ctx, req.Key, clientv3.WithSort(clientv3.SortByVersion, clientv3.SortDescend))
if err != nil {
return nil, err
@ -144,7 +145,8 @@ func (r *ETCD) Get(req *state.GetRequest) (*state.GetResponse, error) {
// Delete performs a delete operation
func (r *ETCD) Delete(req *state.DeleteRequest) error {
ctx, _ := context.WithTimeout(context.Background(), r.operationTimeout)
ctx, cancelFn := context.WithTimeout(context.Background(), r.operationTimeout)
defer cancelFn()
_, err := r.client.Delete(ctx, req.Key)
if err != nil {
return err
@ -167,8 +169,8 @@ func (r *ETCD) BulkDelete(req []state.DeleteRequest) error {
// Set saves state into ETCD
func (r *ETCD) Set(req *state.SetRequest) error {
ctx, _ := context.WithTimeout(context.Background(), r.operationTimeout)
ctx, cancelFn := context.WithTimeout(context.Background(), r.operationTimeout)
defer cancelFn()
var vStr string
b, ok := req.Value.([]byte)
if ok {

View File

@ -97,13 +97,12 @@ func (r *StateStore) getConnectedSlaves() (int, error) {
}
return r.parseConnectedSlaves(s), nil
}
func (r *StateStore) parseConnectedSlaves(res string) int {
infos := strings.Split(res, infoReplicationDelimiter)
for _, info := range infos {
if strings.Index(info, connectedSlavesReplicas) >= 0 {
if strings.Contains(info, connectedSlavesReplicas) {
parsedReplicas, _ := strconv.ParseUint(info[len(connectedSlavesReplicas):], 10, 32)
return int(parsedReplicas)
}

View File

@ -1,86 +1,86 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package redis
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetKeyVersion(t *testing.T) {
store := NewRedisStateStore()
t.Run("With all required fields", func(t *testing.T) {
key, ver, err := store.getKeyVersion([]interface{}{"data", "TEST_KEY", "version", "TEST_VER"})
assert.Equal(t, nil, err, "failed to read all fields")
assert.Equal(t, "TEST_KEY", key, "failed to read key")
assert.Equal(t, "TEST_VER", ver, "failed to read version")
})
t.Run("With missing data", func(t *testing.T) {
_, _, err := store.getKeyVersion([]interface{}{"version", "TEST_VER"})
assert.NotNil(t, err, "failed to respond to missing data field")
})
t.Run("With missing version", func(t *testing.T) {
_, _, err := store.getKeyVersion([]interface{}{"data", "TEST_KEY"})
assert.NotNil(t, err, "failed to respond to missing version field")
})
t.Run("With all required fields - out of order", func(t *testing.T) {
key, ver, err := store.getKeyVersion([]interface{}{"version", "TEST_VER", "dragon", "TEST_DRAGON", "data", "TEST_KEY"})
assert.Equal(t, nil, err, "failed to read all fields")
assert.Equal(t, "TEST_KEY", key, "failed to read key")
assert.Equal(t, "TEST_VER", ver, "failed to read version")
})
t.Run("With no fields", func(t *testing.T) {
_, _, err := store.getKeyVersion([]interface{}{})
assert.NotNil(t, err, "failed to respond to missing fields")
})
t.Run("With wrong fields", func(t *testing.T) {
_, _, err := store.getKeyVersion([]interface{}{"dragon", "TEST_DRAGON"})
assert.NotNil(t, err, "failed to respond to missing fields")
})
}
func TestParseEtag(t *testing.T) {
store := NewRedisStateStore()
t.Run("Empty ETag", func(t *testing.T) {
ver, err := store.parseETag("")
assert.Equal(t, nil, err, "failed to parse ETag")
assert.Equal(t, 0, ver, "default version should be 0")
})
t.Run("Number ETag", func(t *testing.T) {
ver, err := store.parseETag("354")
assert.Equal(t, nil, err, "failed to parse ETag")
assert.Equal(t, 354, ver, "version should be 254")
})
t.Run("String ETag", func(t *testing.T) {
_, err := store.parseETag("dragon")
assert.NotNil(t, err, "shouldn't recognize string ETag")
})
}
func TestParseConnectedSlavs(t *testing.T) {
store := NewRedisStateStore()
t.Run("Empty info", func(t *testing.T) {
slaves := store.parseConnectedSlaves("")
assert.Equal(t, 0, slaves, "connected slaves must be 0")
})
t.Run("connectedSlaves property is not included", func(t *testing.T) {
slaves := store.parseConnectedSlaves("# Replication\r\nrole:master\r\n")
assert.Equal(t, 0, slaves, "connected slaves must be 0")
})
t.Run("connectedSlaves is 2", func(t *testing.T) {
slaves := store.parseConnectedSlaves("# Replication\r\nrole:master\r\nconnected_slaves:2\r\n")
assert.Equal(t, 2, slaves, "connected slaves must be 2")
})
t.Run("connectedSlaves is 1", func(t *testing.T) {
slaves := store.parseConnectedSlaves("# Replication\r\nrole:master\r\nconnected_slaves:1")
assert.Equal(t, 1, slaves, "connected slaves must be 1")
})
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package redis
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetKeyVersion(t *testing.T) {
store := NewRedisStateStore()
t.Run("With all required fields", func(t *testing.T) {
key, ver, err := store.getKeyVersion([]interface{}{"data", "TEST_KEY", "version", "TEST_VER"})
assert.Equal(t, nil, err, "failed to read all fields")
assert.Equal(t, "TEST_KEY", key, "failed to read key")
assert.Equal(t, "TEST_VER", ver, "failed to read version")
})
t.Run("With missing data", func(t *testing.T) {
_, _, err := store.getKeyVersion([]interface{}{"version", "TEST_VER"})
assert.NotNil(t, err, "failed to respond to missing data field")
})
t.Run("With missing version", func(t *testing.T) {
_, _, err := store.getKeyVersion([]interface{}{"data", "TEST_KEY"})
assert.NotNil(t, err, "failed to respond to missing version field")
})
t.Run("With all required fields - out of order", func(t *testing.T) {
key, ver, err := store.getKeyVersion([]interface{}{"version", "TEST_VER", "dragon", "TEST_DRAGON", "data", "TEST_KEY"})
assert.Equal(t, nil, err, "failed to read all fields")
assert.Equal(t, "TEST_KEY", key, "failed to read key")
assert.Equal(t, "TEST_VER", ver, "failed to read version")
})
t.Run("With no fields", func(t *testing.T) {
_, _, err := store.getKeyVersion([]interface{}{})
assert.NotNil(t, err, "failed to respond to missing fields")
})
t.Run("With wrong fields", func(t *testing.T) {
_, _, err := store.getKeyVersion([]interface{}{"dragon", "TEST_DRAGON"})
assert.NotNil(t, err, "failed to respond to missing fields")
})
}
func TestParseEtag(t *testing.T) {
store := NewRedisStateStore()
t.Run("Empty ETag", func(t *testing.T) {
ver, err := store.parseETag("")
assert.Equal(t, nil, err, "failed to parse ETag")
assert.Equal(t, 0, ver, "default version should be 0")
})
t.Run("Number ETag", func(t *testing.T) {
ver, err := store.parseETag("354")
assert.Equal(t, nil, err, "failed to parse ETag")
assert.Equal(t, 354, ver, "version should be 254")
})
t.Run("String ETag", func(t *testing.T) {
_, err := store.parseETag("dragon")
assert.NotNil(t, err, "shouldn't recognize string ETag")
})
}
func TestParseConnectedSlavs(t *testing.T) {
store := NewRedisStateStore()
t.Run("Empty info", func(t *testing.T) {
slaves := store.parseConnectedSlaves("")
assert.Equal(t, 0, slaves, "connected slaves must be 0")
})
t.Run("connectedSlaves property is not included", func(t *testing.T) {
slaves := store.parseConnectedSlaves("# Replication\r\nrole:master\r\n")
assert.Equal(t, 0, slaves, "connected slaves must be 0")
})
t.Run("connectedSlaves is 2", func(t *testing.T) {
slaves := store.parseConnectedSlaves("# Replication\r\nrole:master\r\nconnected_slaves:2\r\n")
assert.Equal(t, 2, slaves, "connected slaves must be 2")
})
t.Run("connectedSlaves is 1", func(t *testing.T) {
slaves := store.parseConnectedSlaves("# Replication\r\nrole:master\r\nconnected_slaves:1")
assert.Equal(t, 1, slaves, "connected slaves must be 1")
})
}

View File

@ -1,98 +1,98 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package state
import (
"fmt"
"time"
)
const (
FirstWrite = "first-write"
LastWrite = "last-write"
Strong = "strong"
Eventual = "eventual"
Exponential = "exponential"
Linear = "linear"
)
// CheckSetRequestOptions checks if set request options use supported keywords
func CheckSetRequestOptions(req *SetRequest) error {
if req.Options.Concurrency != "" && req.Options.Concurrency != FirstWrite && req.Options.Concurrency != LastWrite {
return fmt.Errorf("unrecognized concurrency model '%s'", req.Options.Concurrency)
}
if req.Options.Consistency != "" && req.Options.Consistency != Strong && req.Options.Consistency != Eventual {
return fmt.Errorf("unrecognized consistency model '%s'", req.Options.Consistency)
}
return nil
}
// CheckDeleteRequestOptions checks if delete request options use supported keywords
func CheckDeleteRequestOptions(req *DeleteRequest) error {
if req.Options.Concurrency != "" && req.Options.Concurrency != FirstWrite && req.Options.Concurrency != LastWrite {
return fmt.Errorf("unrecognized concurrency model '%s'", req.Options.Concurrency)
}
if req.Options.Consistency != "" && req.Options.Consistency != Strong && req.Options.Consistency != Eventual {
return fmt.Errorf("unrecognized consistency model '%s'", req.Options.Consistency)
}
return nil
}
// SetWithRetries handles SetRequest with retries
func SetWithRetries(method func(req *SetRequest) error, req *SetRequest) error {
switch req.Options.RetryPolicy.Pattern {
case "":
fallthrough
case Linear:
fallthrough
case Exponential:
if req.Options.RetryPolicy.Threshold > 0 {
duration := req.Options.RetryPolicy.Interval
for i := 0; i < req.Options.RetryPolicy.Threshold; i++ {
err := method(req)
if err == nil {
return nil
}
time.Sleep(duration)
if req.Options.RetryPolicy.Pattern == Exponential {
duration *= 2
}
}
return fmt.Errorf("failed to set value after %d retries", req.Options.RetryPolicy.Threshold)
}
return method(req)
default:
return fmt.Errorf("unrecognized retry patter '%s'", req.Options.RetryPolicy.Pattern)
}
}
// DeleteWithRetries handles SetRequest with retries
func DeleteWithRetries(method func(req *DeleteRequest) error, req *DeleteRequest) error {
switch req.Options.RetryPolicy.Pattern {
case "":
fallthrough
case Linear:
fallthrough
case Exponential:
if req.Options.RetryPolicy.Threshold > 0 {
duration := req.Options.RetryPolicy.Interval
for i := 0; i < req.Options.RetryPolicy.Threshold; i++ {
err := method(req)
if err == nil {
return nil
}
time.Sleep(duration)
if req.Options.RetryPolicy.Pattern == Exponential {
duration *= 2
}
}
return fmt.Errorf("failed to set value after %d retries", req.Options.RetryPolicy.Threshold)
}
return method(req)
default:
return fmt.Errorf("unrecognized retry patter '%s'", req.Options.RetryPolicy.Pattern)
}
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package state
import (
"fmt"
"time"
)
const (
FirstWrite = "first-write"
LastWrite = "last-write"
Strong = "strong"
Eventual = "eventual"
Exponential = "exponential"
Linear = "linear"
)
// CheckSetRequestOptions checks if set request options use supported keywords
func CheckSetRequestOptions(req *SetRequest) error {
if req.Options.Concurrency != "" && req.Options.Concurrency != FirstWrite && req.Options.Concurrency != LastWrite {
return fmt.Errorf("unrecognized concurrency model '%s'", req.Options.Concurrency)
}
if req.Options.Consistency != "" && req.Options.Consistency != Strong && req.Options.Consistency != Eventual {
return fmt.Errorf("unrecognized consistency model '%s'", req.Options.Consistency)
}
return nil
}
// CheckDeleteRequestOptions checks if delete request options use supported keywords
func CheckDeleteRequestOptions(req *DeleteRequest) error {
if req.Options.Concurrency != "" && req.Options.Concurrency != FirstWrite && req.Options.Concurrency != LastWrite {
return fmt.Errorf("unrecognized concurrency model '%s'", req.Options.Concurrency)
}
if req.Options.Consistency != "" && req.Options.Consistency != Strong && req.Options.Consistency != Eventual {
return fmt.Errorf("unrecognized consistency model '%s'", req.Options.Consistency)
}
return nil
}
// SetWithRetries handles SetRequest with retries
func SetWithRetries(method func(req *SetRequest) error, req *SetRequest) error {
switch req.Options.RetryPolicy.Pattern {
case "":
fallthrough
case Linear:
fallthrough
case Exponential:
if req.Options.RetryPolicy.Threshold > 0 {
duration := req.Options.RetryPolicy.Interval
for i := 0; i < req.Options.RetryPolicy.Threshold; i++ {
err := method(req)
if err == nil {
return nil
}
time.Sleep(duration)
if req.Options.RetryPolicy.Pattern == Exponential {
duration *= 2
}
}
return fmt.Errorf("failed to set value after %d retries", req.Options.RetryPolicy.Threshold)
}
return method(req)
default:
return fmt.Errorf("unrecognized retry patter '%s'", req.Options.RetryPolicy.Pattern)
}
}
// DeleteWithRetries handles SetRequest with retries
func DeleteWithRetries(method func(req *DeleteRequest) error, req *DeleteRequest) error {
switch req.Options.RetryPolicy.Pattern {
case "":
fallthrough
case Linear:
fallthrough
case Exponential:
if req.Options.RetryPolicy.Threshold > 0 {
duration := req.Options.RetryPolicy.Interval
for i := 0; i < req.Options.RetryPolicy.Threshold; i++ {
err := method(req)
if err == nil {
return nil
}
time.Sleep(duration)
if req.Options.RetryPolicy.Pattern == Exponential {
duration *= 2
}
}
return fmt.Errorf("failed to set value after %d retries", req.Options.RetryPolicy.Threshold)
}
return method(req)
default:
return fmt.Errorf("unrecognized retry patter '%s'", req.Options.RetryPolicy.Pattern)
}
}

View File

@ -1,89 +1,88 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package state
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
// TestRetryPolicies is used to test retry policies
func TestRetryPolicies(t *testing.T) {
t.Run("set with no options", func(t *testing.T) {
counter := 0
SetWithRetries(func(req *SetRequest) error {
counter++
return nil
}, &SetRequest{})
assert.Equal(t, 1, counter, "should execute only once")
})
t.Run("set with no retry policies", func(t *testing.T) {
counter := 0
SetWithRetries(func(req *SetRequest) error {
counter++
return nil
}, &SetRequest{
Options: SetStateOption{},
})
assert.Equal(t, 1, counter, "should execute only once")
})
t.Run("set with empty retry policies", func(t *testing.T) {
counter := 0
SetWithRetries(func(req *SetRequest) error {
counter++
return nil
}, &SetRequest{
Options: SetStateOption{
RetryPolicy: RetryPolicy{
Interval: 0,
Threshold: 0,
Pattern: "",
},
},
})
assert.Equal(t, 1, counter, "should execute only once")
})
t.Run("bad policy", func(t *testing.T) {
ret := SetWithRetries(func(req *SetRequest) error {
return nil
}, &SetRequest{
Options: SetStateOption{
RetryPolicy: RetryPolicy{
Interval: 100,
Threshold: 3,
Pattern: "dummy",
},
},
})
assert.NotNil(t, ret, "should reject policy")
})
t.Run("liner retry 3 times", func(t *testing.T) {
counter := 0
SetWithRetries(func(req *SetRequest) error {
counter++
if counter < 3 {
return fmt.Errorf("BAD")
}
return nil
}, &SetRequest{
Options: SetStateOption{
RetryPolicy: RetryPolicy{
Interval: 100,
Threshold: 3,
Pattern: "linear",
},
},
})
assert.Equal(t, 3, counter, "should execute 3 times")
})
}
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package state
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
// TestRetryPolicies is used to test retry policies
func TestRetryPolicies(t *testing.T) {
t.Run("set with no options", func(t *testing.T) {
counter := 0
SetWithRetries(func(req *SetRequest) error {
counter++
return nil
}, &SetRequest{})
assert.Equal(t, 1, counter, "should execute only once")
})
t.Run("set with no retry policies", func(t *testing.T) {
counter := 0
SetWithRetries(func(req *SetRequest) error {
counter++
return nil
}, &SetRequest{
Options: SetStateOption{},
})
assert.Equal(t, 1, counter, "should execute only once")
})
t.Run("set with empty retry policies", func(t *testing.T) {
counter := 0
SetWithRetries(func(req *SetRequest) error {
counter++
return nil
}, &SetRequest{
Options: SetStateOption{
RetryPolicy: RetryPolicy{
Interval: 0,
Threshold: 0,
Pattern: "",
},
},
})
assert.Equal(t, 1, counter, "should execute only once")
})
t.Run("bad policy", func(t *testing.T) {
ret := SetWithRetries(func(req *SetRequest) error {
return nil
}, &SetRequest{
Options: SetStateOption{
RetryPolicy: RetryPolicy{
Interval: 100,
Threshold: 3,
Pattern: "dummy",
},
},
})
assert.NotNil(t, ret, "should reject policy")
})
t.Run("liner retry 3 times", func(t *testing.T) {
counter := 0
SetWithRetries(func(req *SetRequest) error {
counter++
if counter < 3 {
return fmt.Errorf("BAD")
}
return nil
}, &SetRequest{
Options: SetStateOption{
RetryPolicy: RetryPolicy{
Interval: 100,
Threshold: 3,
Pattern: "linear",
},
},
})
assert.Equal(t, 3, counter, "should execute 3 times")
})
}

View File

@ -6,6 +6,7 @@
package state
// StateStore is an interface to perform operations on store
// nolint:golint
type StateStore interface {
Init(metadata Metadata) error
Delete(req *DeleteRequest) error