ci: standard linter config (#199)

Signed-off-by: Long <long0dai@foxmail.com>
This commit is contained in:
Long Dai 2021-09-23 02:02:52 +08:00 committed by GitHub
parent 994f9b69f2
commit de5cf935fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 387 additions and 116 deletions

View File

@ -11,6 +11,10 @@ jobs:
build: build:
name: Test and Lint on Push name: Test and Lint on Push
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
GOVER: 1.17
GOLANGCILINT_VER: v1.31
steps: steps:
- name: Setup - name: Setup
@ -41,8 +45,6 @@ jobs:
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v1
- name: Lint - name: Lint
uses: golangci/golangci-lint-action@v2 uses: golangci/golangci-lint-action@v2.2.1
with: with:
version: v1.33 version: ${{ env.GOLANGCILINT_VER }}

255
.golangci.yml Normal file
View File

@ -0,0 +1,255 @@
# 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: 10m
# 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:
# third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs:
- ^pkg.*client.*clientset.*versioned.*
- ^pkg.*client.*informers.*externalversions.*
- ^pkg.*proto.*
# 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: github.com/dapr/
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: 5
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: "must use github.com/dapr/kit/logger"
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
- exitAfterDefer
# 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
godot:
exclude:
- 'nosec'
capital: false
scope: all
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
- gochecknoglobals
- gochecknoinits
- gocyclo
- gocognit
- godox
- interfacer
- lll
- maligned
- scopelint
- unparam
- wsl
- gomnd
- testpackage
- goerr113
- nestif
- nlreturn
- exhaustive
- noctx
- gci
issues:
exclude-rules:
- path: .*_test.go
linters:
- godot

View File

@ -3,11 +3,12 @@ package client
import ( import (
"context" "context"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
) )
// InvokeBindingRequest represents binding invocation request // InvokeBindingRequest represents binding invocation request.
type InvokeBindingRequest struct { type InvokeBindingRequest struct {
// Name is name of binding to invoke. // Name is name of binding to invoke.
Name string Name string
@ -19,7 +20,7 @@ type InvokeBindingRequest struct {
Metadata map[string]string Metadata map[string]string
} }
// BindingEvent represents the binding event handler input // BindingEvent represents the binding event handler input.
type BindingEvent struct { type BindingEvent struct {
// Data is the input bindings sent // Data is the input bindings sent
Data []byte Data []byte
@ -29,7 +30,7 @@ type BindingEvent struct {
// InvokeBinding invokes specific operation on the configured Dapr binding. // InvokeBinding invokes specific operation on the configured Dapr binding.
// This method covers input, output, and bi-directional bindings. // This method covers input, output, and bi-directional bindings.
func (c *GRPCClient) InvokeBinding(ctx context.Context, in *InvokeBindingRequest) (out *BindingEvent, err error) { func (c *GRPCClient) InvokeBinding(ctx context.Context, in *InvokeBindingRequest) (*BindingEvent, error) {
if in == nil { if in == nil {
return nil, errors.New("binding invocation required") return nil, errors.New("binding invocation required")
} }
@ -52,14 +53,14 @@ func (c *GRPCClient) InvokeBinding(ctx context.Context, in *InvokeBindingRequest
return nil, errors.Wrapf(err, "error invoking binding %s/%s", in.Name, in.Operation) return nil, errors.Wrapf(err, "error invoking binding %s/%s", in.Name, in.Operation)
} }
out = &BindingEvent{}
if resp != nil { if resp != nil {
out.Data = resp.Data return &BindingEvent{
out.Metadata = resp.Metadata Data: resp.Data,
Metadata: resp.Metadata,
}, nil
} }
return return nil, nil
} }
// InvokeOutputBinding invokes configured Dapr binding with data (allows nil).InvokeOutputBinding // InvokeOutputBinding invokes configured Dapr binding with data (allows nil).InvokeOutputBinding

View File

@ -42,5 +42,4 @@ func TestInvokeBinding(t *testing.T) {
assert.NotNil(t, out) assert.NotNil(t, out)
assert.Equal(t, "test", string(out.Data)) assert.Equal(t, "test", string(out.Data))
}) })
} }

View File

@ -19,8 +19,8 @@ const (
daprPortDefault = "50001" daprPortDefault = "50001"
daprPortEnvVarName = "DAPR_GRPC_PORT" daprPortEnvVarName = "DAPR_GRPC_PORT"
traceparentKey = "traceparent" traceparentKey = "traceparent"
apiTokenKey = "dapr-api-token" apiTokenKey = "dapr-api-token" /* #nosec */
apiTokenEnvVarName = "DAPR_API_TOKEN" apiTokenEnvVarName = "DAPR_API_TOKEN" /* #nosec */
) )
var ( var (
@ -175,14 +175,14 @@ func (c *GRPCClient) Close() {
} }
// WithAuthToken sets Dapr API token on the instantiated client. // WithAuthToken sets Dapr API token on the instantiated client.
// Allows empty string to reset token on existing client // Allows empty string to reset token on existing client.
func (c *GRPCClient) WithAuthToken(token string) { func (c *GRPCClient) WithAuthToken(token string) {
c.mux.Lock() c.mux.Lock()
c.authToken = token c.authToken = token
c.mux.Unlock() c.mux.Unlock()
} }
// WithTraceID adds existing trace ID to the outgoing context // WithTraceID adds existing trace ID to the outgoing context.
func (c *GRPCClient) WithTraceID(ctx context.Context, id string) context.Context { func (c *GRPCClient) WithTraceID(ctx context.Context, id string) context.Context {
if id == "" { if id == "" {
return ctx return ctx
@ -196,7 +196,7 @@ func (c *GRPCClient) withAuthToken(ctx context.Context) context.Context {
if c.authToken == "" { if c.authToken == "" {
return ctx return ctx
} }
return metadata.NewOutgoingContext(ctx, metadata.Pairs(apiTokenKey, string(c.authToken))) return metadata.NewOutgoingContext(ctx, metadata.Pairs(apiTokenKey, c.authToken))
} }
// Shutdown the sidecar. // Shutdown the sidecar.

View File

@ -23,9 +23,7 @@ const (
testBufSize = 1024 * 1024 testBufSize = 1024 * 1024
) )
var ( var testClient Client
testClient Client
)
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
ctx := context.Background() ctx := context.Background()
@ -72,7 +70,6 @@ func TestShutdown(t *testing.T) {
}) })
} }
func getTestClient(ctx context.Context) (client Client, closer func()) { func getTestClient(ctx context.Context) (client Client, closer func()) {
s := grpc.NewServer() s := grpc.NewServer()
pb.RegisterDaprServer(s, &testDaprServer{ pb.RegisterDaprServer(s, &testDaprServer{
@ -233,4 +230,4 @@ func (s *testDaprServer) UnregisterActorTimer(context.Context, *pb.UnregisterAct
func (s *testDaprServer) Shutdown(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { func (s *testDaprServer) Shutdown(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {
return &empty.Empty{}, nil return &empty.Empty{}, nil
} }

View File

@ -5,13 +5,14 @@ import (
"encoding/json" "encoding/json"
"strings" "strings"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
anypb "github.com/golang/protobuf/ptypes/any" anypb "github.com/golang/protobuf/ptypes/any"
"github.com/pkg/errors" "github.com/pkg/errors"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
) )
// DataContent the service invocation content // DataContent the service invocation content.
type DataContent struct { type DataContent struct {
// Data is the input data // Data is the input data
Data []byte Data []byte
@ -97,7 +98,7 @@ func (c *GRPCClient) InvokeMethodWithContent(ctx context.Context, appID, methodN
} }
// InvokeMethodWithCustomContent invokes service with custom content (struct + content type). // InvokeMethodWithCustomContent invokes service with custom content (struct + content type).
func (c *GRPCClient) InvokeMethodWithCustomContent(ctx context.Context, appID, methodName, verb string, contentType string, content interface{}) (out []byte, err error) { func (c *GRPCClient) InvokeMethodWithCustomContent(ctx context.Context, appID, methodName, verb string, contentType string, content interface{}) ([]byte, error) {
if err := hasRequiredInvokeArgs(appID, methodName, verb); err != nil { if err := hasRequiredInvokeArgs(appID, methodName, verb); err != nil {
return nil, errors.Wrap(err, "missing required parameter") return nil, errors.Wrap(err, "missing required parameter")
} }

View File

@ -4,8 +4,9 @@ import (
"context" "context"
"testing" "testing"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
) )
type _testStructwithText struct { type _testStructwithText struct {

View File

@ -4,8 +4,9 @@ import (
"context" "context"
"encoding/json" "encoding/json"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
) )
// PublishEvent publishes data onto specific pubsub topic. // PublishEvent publishes data onto specific pubsub topic.
@ -41,7 +42,6 @@ func (c *GRPCClient) PublishEventfromCustomContent(ctx context.Context, pubsubNa
} }
bytes, err := json.Marshal(data) bytes, err := json.Marshal(data)
if err != nil { if err != nil {
return errors.WithMessage(err, "error serializing input struct") return errors.WithMessage(err, "error serializing input struct")
} }

View File

@ -3,8 +3,9 @@ package client
import ( import (
"context" "context"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
) )
// GetSecret retrieves preconfigured secret from specified store using key. // GetSecret retrieves preconfigured secret from specified store using key.

View File

@ -4,10 +4,11 @@ import (
"context" "context"
"time" "time"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/golang/protobuf/ptypes/duration" "github.com/golang/protobuf/ptypes/duration"
"github.com/pkg/errors" "github.com/pkg/errors"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
) )
const ( const (
@ -31,7 +32,7 @@ const (
StateOperationTypeUpsert OperationType = 1 StateOperationTypeUpsert OperationType = 1
// StateOperationTypeDelete represents delete operation type value. // StateOperationTypeDelete represents delete operation type value.
StateOperationTypeDelete OperationType = 2 StateOperationTypeDelete OperationType = 2
// UndefinedType represents undefined type value // UndefinedType represents undefined type value.
UndefinedType = "undefined" UndefinedType = "undefined"
) )
@ -44,12 +45,12 @@ type (
OperationType int OperationType int
) )
// GetPBConsistency get consistency pb value // GetPBConsistency get consistency pb value.
func (s StateConsistency) GetPBConsistency() v1.StateOptions_StateConsistency { func (s StateConsistency) GetPBConsistency() v1.StateOptions_StateConsistency {
return v1.StateOptions_StateConsistency(s) return v1.StateOptions_StateConsistency(s)
} }
// GetPBConcurrency get concurrency pb value // GetPBConcurrency get concurrency pb value.
func (s StateConcurrency) GetPBConcurrency() v1.StateOptions_StateConcurrency { func (s StateConcurrency) GetPBConcurrency() v1.StateOptions_StateConcurrency {
return v1.StateOptions_StateConcurrency(s) return v1.StateOptions_StateConcurrency(s)
} }
@ -69,39 +70,37 @@ func (o OperationType) String() string {
} }
// String returns the string value of the StateConsistency. // String returns the string value of the StateConsistency.
func (c StateConsistency) String() string { func (s StateConsistency) String() string {
names := [...]string{ names := [...]string{
UndefinedType, UndefinedType,
"strong", "strong",
"eventual", "eventual",
} }
if c < StateConsistencyStrong || c > StateConsistencyEventual { if s < StateConsistencyStrong || s > StateConsistencyEventual {
return UndefinedType return UndefinedType
} }
return names[c] return names[s]
} }
// String returns the string value of the StateConcurrency. // String returns the string value of the StateConcurrency.
func (c StateConcurrency) String() string { func (s StateConcurrency) String() string {
names := [...]string{ names := [...]string{
UndefinedType, UndefinedType,
"first-write", "first-write",
"last-write", "last-write",
} }
if c < StateConcurrencyFirstWrite || c > StateConcurrencyLastWrite { if s < StateConcurrencyFirstWrite || s > StateConcurrencyLastWrite {
return UndefinedType return UndefinedType
} }
return names[c] return names[s]
} }
var ( var stateOptionDefault = &v1.StateOptions{
stateOptionDefault = &v1.StateOptions{ Concurrency: v1.StateOptions_CONCURRENCY_LAST_WRITE,
Concurrency: v1.StateOptions_CONCURRENCY_LAST_WRITE, Consistency: v1.StateOptions_CONSISTENCY_STRONG,
Consistency: v1.StateOptions_CONSISTENCY_STRONG, }
}
)
// StateOperation is a collection of StateItems with a store name. // StateOperation is a collection of StateItems with a store name.
type StateOperation struct { type StateOperation struct {
@ -138,7 +137,7 @@ type SetStateItem struct {
// DeleteStateItem represents a single state to be deleted. // DeleteStateItem represents a single state to be deleted.
type DeleteStateItem SetStateItem type DeleteStateItem SetStateItem
// ETag represents an versioned record information // ETag represents an versioned record information.
type ETag struct { type ETag struct {
Value string Value string
} }
@ -149,17 +148,17 @@ type StateOptions struct {
Consistency StateConsistency Consistency StateConsistency
} }
// StateOption StateOptions's function type // StateOption StateOptions's function type.
type StateOption func(*StateOptions) type StateOption func(*StateOptions)
// WithConcurrency set StateOptions's Concurrency // WithConcurrency set StateOptions's Concurrency.
func WithConcurrency(concurrency StateConcurrency) StateOption { func WithConcurrency(concurrency StateConcurrency) StateOption {
return func(so *StateOptions) { return func(so *StateOptions) {
so.Concurrency = concurrency so.Concurrency = concurrency
} }
} }
// WithConsistency set StateOptions's consistency // WithConsistency set StateOptions's consistency.
func WithConsistency(consistency StateConsistency) StateOption { func WithConsistency(consistency StateConsistency) StateOption {
return func(so *StateOptions) { return func(so *StateOptions) {
so.Consistency = consistency so.Consistency = consistency
@ -212,7 +211,7 @@ func toProtoDuration(d time.Duration) *duration.Duration {
secs := nanos / 1e9 secs := nanos / 1e9
nanos -= secs * 1e9 nanos -= secs * 1e9
return &duration.Duration{ return &duration.Duration{
Seconds: int64(secs), Seconds: secs,
Nanos: int32(nanos), Nanos: int32(nanos),
} }
} }
@ -247,9 +246,9 @@ func (c *GRPCClient) ExecuteStateTransaction(ctx context.Context, storeName stri
return nil return nil
} }
// SaveState saves the raw data into store, default options: strong, last-write // SaveState saves the raw data into store, default options: strong, last-write.
func (c *GRPCClient) SaveState(ctx context.Context, storeName, key string, data []byte, so ...StateOption) error { func (c *GRPCClient) SaveState(ctx context.Context, storeName, key string, data []byte, so ...StateOption) error {
var stateOptions = new(StateOptions) stateOptions := new(StateOptions)
for _, o := range so { for _, o := range so {
o(stateOptions) o(stateOptions)
} }
@ -332,7 +331,7 @@ func (c *GRPCClient) GetState(ctx context.Context, storeName, key string) (item
} }
// GetStateWithConsistency retrieves state from specific store using provided state consistency. // GetStateWithConsistency retrieves state from specific store using provided state consistency.
func (c *GRPCClient) GetStateWithConsistency(ctx context.Context, storeName, key string, meta map[string]string, sc StateConsistency) (item *StateItem, err error) { func (c *GRPCClient) GetStateWithConsistency(ctx context.Context, storeName, key string, meta map[string]string, sc StateConsistency) (*StateItem, error) {
if err := hasRequiredStateArgs(storeName, key); err != nil { if err := hasRequiredStateArgs(storeName, key); err != nil {
return nil, errors.Wrap(err, "missing required arguments") return nil, errors.Wrap(err, "missing required arguments")
} }

View File

@ -5,8 +5,14 @@ import (
"testing" "testing"
"time" "time"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
)
const (
testData = "test"
testStore = "store"
) )
func TestTypes(t *testing.T) { func TestTypes(t *testing.T) {
@ -19,7 +25,7 @@ func TestTypes(t *testing.T) {
} }
func TestDurationConverter(t *testing.T) { func TestDurationConverter(t *testing.T) {
d := time.Duration(10 * time.Second) d := 10 * time.Second
pd := toProtoDuration(d) pd := toProtoDuration(d)
assert.NotNil(t, pd) assert.NotNil(t, pd)
assert.Equal(t, pd.Seconds, int64(10)) assert.Equal(t, pd.Seconds, int64(10))
@ -39,8 +45,8 @@ func TestStateOptionsConverter(t *testing.T) {
// go test -timeout 30s ./client -count 1 -run ^TestSaveState$ // go test -timeout 30s ./client -count 1 -run ^TestSaveState$
func TestSaveState(t *testing.T) { func TestSaveState(t *testing.T) {
ctx := context.Background() ctx := context.Background()
data := "test" data := testData
store := "test" store := testStore
key := "key1" key := "key1"
t.Run("save data", func(t *testing.T) { t.Run("save data", func(t *testing.T) {
@ -87,8 +93,8 @@ func TestSaveState(t *testing.T) {
// go test -timeout 30s ./client -count 1 -run ^TestDeleteState$ // go test -timeout 30s ./client -count 1 -run ^TestDeleteState$
func TestDeleteState(t *testing.T) { func TestDeleteState(t *testing.T) {
ctx := context.Background() ctx := context.Background()
data := "test" data := testData
store := "test" store := testStore
key := "key1" key := "key1"
t.Run("delete not exist data", func(t *testing.T) { t.Run("delete not exist data", func(t *testing.T) {
@ -165,8 +171,8 @@ func TestDeleteState(t *testing.T) {
func TestDeleteBulkState(t *testing.T) { func TestDeleteBulkState(t *testing.T) {
ctx := context.Background() ctx := context.Background()
data := "test" data := testData
store := "test" store := testStore
keys := []string{"key1", "key2", "key3"} keys := []string{"key1", "key2", "key3"}
t.Run("delete not exist data", func(t *testing.T) { t.Run("delete not exist data", func(t *testing.T) {
@ -273,7 +279,7 @@ func TestDeleteBulkState(t *testing.T) {
func TestStateTransactions(t *testing.T) { func TestStateTransactions(t *testing.T) {
ctx := context.Background() ctx := context.Background()
data := `{ "message": "test" }` data := `{ "message": "test" }`
store := "test" store := testStore
meta := map[string]string{} meta := map[string]string{}
keys := []string{"k1", "k2", "k3"} keys := []string{"k1", "k2", "k3"}
adds := make([]*StateOperation, 0) adds := make([]*StateOperation, 0)
@ -341,5 +347,4 @@ func TestStateTransactions(t *testing.T) {
assert.NotNil(t, items) assert.NotNil(t, items)
assert.Len(t, items, 0) assert.Len(t, items, 0)
}) })
} }

2
service/common/service.go Executable file → Normal file
View File

@ -2,7 +2,7 @@ package common
import "context" import "context"
// Service represents Dapr callback service // Service represents Dapr callback service.
type Service interface { type Service interface {
// AddServiceInvocationHandler appends provided service invocation handler with its name to the service. // AddServiceInvocationHandler appends provided service invocation handler with its name to the service.
AddServiceInvocationHandler(name string, fn func(ctx context.Context, in *InvocationEvent) (out *Content, err error)) error AddServiceInvocationHandler(name string, fn func(ctx context.Context, in *InvocationEvent) (out *Content, err error)) error

18
service/common/type.go Executable file → Normal file
View File

@ -1,6 +1,6 @@
package common package common
// TopicEvent is the content of the inbound topic message // TopicEvent is the content of the inbound topic message.
type TopicEvent struct { type TopicEvent struct {
// ID identifies the event. // ID identifies the event.
ID string `json:"id"` ID string `json:"id"`
@ -23,7 +23,7 @@ type TopicEvent struct {
PubsubName string `json:"pubsubname"` PubsubName string `json:"pubsubname"`
} }
// InvocationEvent represents the input and output of binding invocation // InvocationEvent represents the input and output of binding invocation.
type InvocationEvent struct { type InvocationEvent struct {
// Data is the payload that the input bindings sent. // Data is the payload that the input bindings sent.
Data []byte `json:"data"` Data []byte `json:"data"`
@ -37,7 +37,7 @@ type InvocationEvent struct {
QueryString string `json:"-"` QueryString string `json:"-"`
} }
// Content is a generic data content // Content is a generic data content.
type Content struct { type Content struct {
// Data is the payload that the input bindings sent. // Data is the payload that the input bindings sent.
Data []byte `json:"data"` Data []byte `json:"data"`
@ -47,7 +47,7 @@ type Content struct {
DataTypeURL string `json:"typeUrl,omitempty"` DataTypeURL string `json:"typeUrl,omitempty"`
} }
// BindingEvent represents the binding event handler input // BindingEvent represents the binding event handler input.
type BindingEvent struct { type BindingEvent struct {
// Data is the input bindings sent // Data is the input bindings sent
Data []byte `json:"data"` Data []byte `json:"data"`
@ -55,7 +55,7 @@ type BindingEvent struct {
Metadata map[string]string `json:"metadata,omitempty"` Metadata map[string]string `json:"metadata,omitempty"`
} }
// Subscription represents single topic subscription // Subscription represents single topic subscription.
type Subscription struct { type Subscription struct {
// PubsubName is name of the pub/sub this message came from // PubsubName is name of the pub/sub this message came from
PubsubName string `json:"pubsubname"` PubsubName string `json:"pubsubname"`
@ -68,15 +68,15 @@ type Subscription struct {
} }
const ( const (
// SubscriptionResponseStatusSuccess means message is processed successfully // SubscriptionResponseStatusSuccess means message is processed successfully.
SubscriptionResponseStatusSuccess = "SUCCESS" SubscriptionResponseStatusSuccess = "SUCCESS"
// SubscriptionResponseStatusRetry means message to be retried by Dapr // SubscriptionResponseStatusRetry means message to be retried by Dapr.
SubscriptionResponseStatusRetry = "RETRY" SubscriptionResponseStatusRetry = "RETRY"
// SubscriptionResponseStatusDrop means warning is logged and message is dropped // SubscriptionResponseStatusDrop means warning is logged and message is dropped.
SubscriptionResponseStatusDrop = "DROP" SubscriptionResponseStatusDrop = "DROP"
) )
// SubscriptionResponse represents the response handling hint from subscriber to Dapr // SubscriptionResponse represents the response handling hint from subscriber to Dapr.
type SubscriptionResponse struct { type SubscriptionResponse struct {
Status string `json:"status"` Status string `json:"status"`
} }

View File

@ -4,13 +4,14 @@ import (
"context" "context"
"fmt" "fmt"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
"github.com/pkg/errors" "github.com/pkg/errors"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
) )
// AddBindingInvocationHandler appends provided binding invocation handler with its name to the service // AddBindingInvocationHandler appends provided binding invocation handler with its name to the service.
func (s *Server) AddBindingInvocationHandler(name string, fn func(ctx context.Context, in *common.BindingEvent) (out []byte, err error)) error { func (s *Server) AddBindingInvocationHandler(name string, fn func(ctx context.Context, in *common.BindingEvent) (out []byte, err error)) error {
if name == "" { if name == "" {
return fmt.Errorf("binding name required") return fmt.Errorf("binding name required")
@ -23,7 +24,7 @@ func (s *Server) AddBindingInvocationHandler(name string, fn func(ctx context.Co
} }
// ListInputBindings is called by Dapr to get the list of bindings the app will get invoked by. In this example, we are telling Dapr // ListInputBindings is called by Dapr to get the list of bindings the app will get invoked by. In this example, we are telling Dapr
// To invoke our app with a binding named storage // To invoke our app with a binding named storage.
func (s *Server) ListInputBindings(ctx context.Context, in *empty.Empty) (*pb.ListInputBindingsResponse, error) { func (s *Server) ListInputBindings(ctx context.Context, in *empty.Empty) (*pb.ListInputBindingsResponse, error) {
list := make([]string, 0) list := make([]string, 0)
for k := range s.bindingHandlers { for k := range s.bindingHandlers {
@ -35,7 +36,7 @@ func (s *Server) ListInputBindings(ctx context.Context, in *empty.Empty) (*pb.Li
}, nil }, nil
} }
// OnBindingEvent gets invoked every time a new event is fired from a registered binding. The message carries the binding name, a payload and optional metadata // OnBindingEvent gets invoked every time a new event is fired from a registered binding. The message carries the binding name, a payload and optional metadata.
func (s *Server) OnBindingEvent(ctx context.Context, in *pb.BindingEventRequest) (*pb.BindingEventResponse, error) { func (s *Server) OnBindingEvent(ctx context.Context, in *pb.BindingEventRequest) (*pb.BindingEventResponse, error) {
if in == nil { if in == nil {
return nil, errors.New("nil binding event request") return nil, errors.New("nil binding event request")

View File

@ -5,10 +5,11 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
) )
func testBindingHandler(ctx context.Context, in *common.BindingEvent) (out []byte, err error) { func testBindingHandler(ctx context.Context, in *common.BindingEvent) (out []byte, err error) {

View File

@ -4,13 +4,14 @@ import (
"context" "context"
"fmt" "fmt"
cpb "github.com/dapr/go-sdk/dapr/proto/common/v1"
cc "github.com/dapr/go-sdk/service/common"
"github.com/golang/protobuf/ptypes/any" "github.com/golang/protobuf/ptypes/any"
"github.com/pkg/errors" "github.com/pkg/errors"
cpb "github.com/dapr/go-sdk/dapr/proto/common/v1"
cc "github.com/dapr/go-sdk/service/common"
) )
// AddServiceInvocationHandler appends provided service invocation handler with its method to the service // AddServiceInvocationHandler appends provided service invocation handler with its method to the service.
func (s *Server) AddServiceInvocationHandler(method string, fn func(ctx context.Context, in *cc.InvocationEvent) (our *cc.Content, err error)) error { func (s *Server) AddServiceInvocationHandler(method string, fn func(ctx context.Context, in *cc.InvocationEvent) (our *cc.Content, err error)) error {
if method == "" { if method == "" {
return fmt.Errorf("servie name required") return fmt.Errorf("servie name required")
@ -22,7 +23,7 @@ func (s *Server) AddServiceInvocationHandler(method string, fn func(ctx context.
return nil return nil
} }
// OnInvoke gets invoked when a remote service has called the app through Dapr // OnInvoke gets invoked when a remote service has called the app through Dapr.
func (s *Server) OnInvoke(ctx context.Context, in *cpb.InvokeRequest) (*cpb.InvokeResponse, error) { func (s *Server) OnInvoke(ctx context.Context, in *cpb.InvokeRequest) (*cpb.InvokeResponse, error) {
if in == nil { if in == nil {
return nil, errors.New("nil invoke request") return nil, errors.New("nil invoke request")

View File

@ -4,11 +4,12 @@ import (
"context" "context"
"testing" "testing"
"github.com/dapr/go-sdk/dapr/proto/common/v1"
cc "github.com/dapr/go-sdk/service/common"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/anypb"
"github.com/dapr/go-sdk/dapr/proto/common/v1"
cc "github.com/dapr/go-sdk/service/common"
) )
func testInvokeHandler(ctx context.Context, in *cc.InvocationEvent) (out *cc.Content, err error) { func testInvokeHandler(ctx context.Context, in *cc.InvocationEvent) (out *cc.Content, err error) {

View File

@ -6,9 +6,10 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/grpc"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1" pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common" "github.com/dapr/go-sdk/service/common"
"google.golang.org/grpc"
) )
// NewService creates new Service. // NewService creates new Service.

View File

@ -4,13 +4,14 @@ import (
"context" "context"
"fmt" "fmt"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
"github.com/pkg/errors" "github.com/pkg/errors"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
) )
// AddTopicEventHandler appends provided event handler with topic name to the service // AddTopicEventHandler appends provided event handler with topic name to the service.
func (s *Server) AddTopicEventHandler(sub *common.Subscription, fn func(ctx context.Context, e *common.TopicEvent) (retry bool, err error)) error { func (s *Server) AddTopicEventHandler(sub *common.Subscription, fn func(ctx context.Context, e *common.TopicEvent) (retry bool, err error)) error {
if sub == nil { if sub == nil {
return errors.New("subscription required") return errors.New("subscription required")

View File

@ -5,10 +5,11 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/dapr/go-sdk/dapr/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
) )
func TestTopicErrors(t *testing.T) { func TestTopicErrors(t *testing.T) {
@ -65,7 +66,7 @@ func TestTopic(t *testing.T) {
t.Run("topic event for wrong topic", func(t *testing.T) { t.Run("topic event for wrong topic", func(t *testing.T) {
in := &runtime.TopicEventRequest{ in := &runtime.TopicEventRequest{
Topic: "invlid", Topic: "invalid",
} }
_, err := server.OnTopicEvent(ctx, in) _, err := server.OnTopicEvent(ctx, in)
assert.Error(t, err) assert.Error(t, err)

2
service/http/binding.go Executable file → Normal file
View File

@ -10,7 +10,7 @@ import (
"github.com/dapr/go-sdk/service/common" "github.com/dapr/go-sdk/service/common"
) )
// AddBindingInvocationHandler appends provided binding invocation handler with its route to the service // AddBindingInvocationHandler appends provided binding invocation handler with its route to the service.
func (s *Server) AddBindingInvocationHandler(route string, fn func(ctx context.Context, in *common.BindingEvent) (out []byte, err error)) error { func (s *Server) AddBindingInvocationHandler(route string, fn func(ctx context.Context, in *common.BindingEvent) (out []byte, err error)) error {
if route == "" { if route == "" {
return fmt.Errorf("binding route required") return fmt.Errorf("binding route required")

3
service/http/binding_test.go Executable file → Normal file
View File

@ -8,8 +8,9 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/dapr/go-sdk/service/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/dapr/go-sdk/service/common"
) )
func TestBindingHandlerWithoutHandler(t *testing.T) { func TestBindingHandlerWithoutHandler(t *testing.T) {

4
service/http/invoke.go Executable file → Normal file
View File

@ -10,7 +10,7 @@ import (
"github.com/dapr/go-sdk/service/common" "github.com/dapr/go-sdk/service/common"
) )
// AddServiceInvocationHandler appends provided service invocation handler with its route to the service // AddServiceInvocationHandler appends provided service invocation handler with its route to the service.
func (s *Server) AddServiceInvocationHandler(route string, fn func(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error)) error { func (s *Server) AddServiceInvocationHandler(route string, fn func(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error)) error {
if route == "" { if route == "" {
return fmt.Errorf("service route required") return fmt.Errorf("service route required")
@ -63,5 +63,3 @@ func (s *Server) AddServiceInvocationHandler(route string, fn func(ctx context.C
return nil return nil
} }

3
service/http/invoke_test.go Executable file → Normal file
View File

@ -9,8 +9,9 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/dapr/go-sdk/service/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/dapr/go-sdk/service/common"
) )
func TestInvocationHandlerWithoutHandler(t *testing.T) { func TestInvocationHandlerWithoutHandler(t *testing.T) {

10
service/http/service.go Executable file → Normal file
View File

@ -6,12 +6,12 @@ import (
"github.com/dapr/go-sdk/service/common" "github.com/dapr/go-sdk/service/common"
) )
// NewService creates new Service // NewService creates new Service.
func NewService(address string) common.Service { func NewService(address string) common.Service {
return newServer(address, nil) return newServer(address, nil)
} }
// NewServiceWithMux creates new Service with existing http mux // NewServiceWithMux creates new Service with existing http mux.
func NewServiceWithMux(address string, mux *http.ServeMux) common.Service { func NewServiceWithMux(address string, mux *http.ServeMux) common.Service {
return newServer(address, mux) return newServer(address, mux)
} }
@ -27,14 +27,14 @@ func newServer(address string, mux *http.ServeMux) *Server {
} }
} }
// Server is the HTTP server wrapping mux many Dapr helpers // Server is the HTTP server wrapping mux many Dapr helpers.
type Server struct { type Server struct {
address string address string
mux *http.ServeMux mux *http.ServeMux
topicSubscriptions []*common.Subscription topicSubscriptions []*common.Subscription
} }
// Start starts the HTTP handler. Blocks while serving // Start starts the HTTP handler. Blocks while serving.
func (s *Server) Start() error { func (s *Server) Start() error {
s.registerSubscribeHandler() s.registerSubscribeHandler()
server := http.Server{ server := http.Server{
@ -44,7 +44,7 @@ func (s *Server) Start() error {
return server.ListenAndServe() return server.ListenAndServe()
} }
// Stop stops previously started HTTP service // Stop stops previously started HTTP service.
func (s *Server) Stop() error { func (s *Server) Stop() error {
// TODO: implement service stop // TODO: implement service stop
return nil return nil

View File

@ -21,6 +21,7 @@ func TestSettingOptions(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
setOptions(w, req) setOptions(w, req)
resp := w.Result() resp := w.Result()
defer resp.Body.Close()
assert.NotNil(t, resp) assert.NotNil(t, resp)
assert.Equal(t, "*", resp.Header.Get("Access-Control-Allow-Origin")) assert.Equal(t, "*", resp.Header.Get("Access-Control-Allow-Origin"))
assert.Equal(t, "POST,OPTIONS", resp.Header.Get("Access-Control-Allow-Methods")) assert.Equal(t, "POST,OPTIONS", resp.Header.Get("Access-Control-Allow-Methods"))
@ -31,7 +32,8 @@ func TestSettingOptions(t *testing.T) {
func testRequest(t *testing.T, s *Server, r *http.Request, expectedStatusCode int) { func testRequest(t *testing.T, s *Server, r *http.Request, expectedStatusCode int) {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
s.mux.ServeHTTP(rr, r) s.mux.ServeHTTP(rr, r)
rez := rr.Result() resp := rr.Result()
assert.NotNil(t, rez) defer resp.Body.Close()
assert.Equal(t, expectedStatusCode, rez.StatusCode) assert.NotNil(t, resp)
assert.Equal(t, expectedStatusCode, resp.StatusCode)
} }

8
service/http/topic.go Executable file → Normal file
View File

@ -13,13 +13,13 @@ import (
) )
const ( const (
// PubSubHandlerSuccessStatusCode is the successful ack code for pubsub event appcallback response // PubSubHandlerSuccessStatusCode is the successful ack code for pubsub event appcallback response.
PubSubHandlerSuccessStatusCode int = http.StatusOK PubSubHandlerSuccessStatusCode int = http.StatusOK
// PubSubHandlerRetryStatusCode is the error response code (nack) pubsub event appcallback response // PubSubHandlerRetryStatusCode is the error response code (nack) pubsub event appcallback response.
PubSubHandlerRetryStatusCode int = http.StatusInternalServerError PubSubHandlerRetryStatusCode int = http.StatusInternalServerError
// PubSubHandlerDropStatusCode is the pubsub event appcallback response code indicating that Dapr should drop that message // PubSubHandlerDropStatusCode is the pubsub event appcallback response code indicating that Dapr should drop that message.
PubSubHandlerDropStatusCode int = http.StatusSeeOther PubSubHandlerDropStatusCode int = http.StatusSeeOther
) )
@ -34,7 +34,7 @@ func (s *Server) registerSubscribeHandler() {
s.mux.HandleFunc("/dapr/subscribe", f) s.mux.HandleFunc("/dapr/subscribe", f)
} }
// AddTopicEventHandler appends provided event handler with it's name to the service // AddTopicEventHandler appends provided event handler with it's name to the service.
func (s *Server) AddTopicEventHandler(sub *common.Subscription, fn func(ctx context.Context, e *common.TopicEvent) (retry bool, err error)) error { func (s *Server) AddTopicEventHandler(sub *common.Subscription, fn func(ctx context.Context, e *common.TopicEvent) (retry bool, err error)) error {
if sub == nil { if sub == nil {
return errors.New("subscription required") return errors.New("subscription required")

3
service/http/topic_test.go Executable file → Normal file
View File

@ -8,8 +8,9 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/dapr/go-sdk/service/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/dapr/go-sdk/service/common"
) )
func testTopicFunc(ctx context.Context, e *common.TopicEvent) (retry bool, err error) { func testTopicFunc(ctx context.Context, e *common.TopicEvent) (retry bool, err error) {