Report SDK version to Dapr as User-Agent (#328)

* Report SDK version to Dapr

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Fixed typos

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Fixes

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* 💄

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Making the linter happy-maybe

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Update linter to support go:embed comments

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
This commit is contained in:
Alessandro (Ale) Segala 2022-12-16 11:16:10 -08:00 committed by GitHub
parent 014b4d6836
commit 718044ad12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 103 additions and 55 deletions

View File

@ -20,6 +20,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Check sdk-version file
run: |
if [[ "$(head -n1 version/sdk-version)" != "${{ github.ref }}" ]]; then
echo "File version/sdk-version needs to be updated to ${{ github.ref }}"
exit 1
fi
shell: bash
- name: Tidy
run: |
go mod tidy -compat=1.17
@ -39,7 +47,7 @@ jobs:
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: Automatic go Dapr client release
body: Automatic Go Dapr client release
draft: false
prerelease: false
@ -49,5 +57,5 @@ jobs:
severity: info
details: Release ${{ github.ref }} published
description: Release
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
avatarUrl: https://github.githubassets.com/images/modules/logos_page/Octocat.png
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
avatarUrl: https://github.githubassets.com/images/modules/logos_page/Octocat.png

View File

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
env:
GOVER: 1.17
GOLANGCILINT_VER: v1.31
GOLANGCILINT_VER: v1.48.0
steps:

View File

@ -244,9 +244,28 @@ linters:
- goerr113
- nestif
- nlreturn
- tagliatelle
- ifshort
- forbidigo
- exhaustive
- contextcheck
- exhaustruct
- exhaustivestruct
- wrapcheck
- predeclared
- varnamelen
- ireturn
- noctx
- forcetypeassert
- cyclop
- errchkjson
- godot
- gci
- paralleltest
- nonamedreturns
- nosnakecase
- nilnil
- staticcheck
issues:
exclude-rules:
- path: .*_test.go

View File

@ -25,6 +25,7 @@ import (
"github.com/dapr/go-sdk/actor"
"github.com/dapr/go-sdk/actor/config"
"github.com/dapr/go-sdk/version"
"github.com/pkg/errors"
"google.golang.org/grpc"
@ -39,13 +40,13 @@ import (
)
const (
daprPortDefault = "50001"
daprPortEnvVarName = "DAPR_GRPC_PORT" /* #nosec */
traceparentKey = "traceparent"
apiTokenKey = "dapr-api-token" /* #nosec */
apiTokenEnvVarName = "DAPR_API_TOKEN" /* #nosec */
clientDefaultTimoutSeconds = 5
clientTimoutSecondsEnvVarName = "DAPR_CLIENT_TIMEOUT_SECONDS"
daprPortDefault = "50001"
daprPortEnvVarName = "DAPR_GRPC_PORT" /* #nosec */
traceparentKey = "traceparent"
apiTokenKey = "dapr-api-token" /* #nosec */
apiTokenEnvVarName = "DAPR_API_TOKEN" /* #nosec */
clientDefaultTimeoutSeconds = 5
clientTimeoutSecondsEnvVarName = "DAPR_CLIENT_TIMEOUT_SECONDS"
)
var (
@ -222,7 +223,7 @@ func NewClientWithPort(port string) (client Client, err error) {
// NewClientWithAddress instantiates Dapr using specific address (including port).
func NewClientWithAddress(address string) (client Client, err error) {
if address == "" {
return nil, errors.New("nil address")
return nil, errors.New("empty address")
}
logger.Printf("dapr client initializing for: %s", address)
@ -230,28 +231,29 @@ func NewClientWithAddress(address string) (client Client, err error) {
if err != nil {
return nil, err
}
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Duration(timeoutSeconds)*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutSeconds)*time.Second)
conn, err := grpc.DialContext(
ctx,
address,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithUserAgent("dapr-sdk-go/"+version.SDKVersion),
grpc.WithBlock(),
)
cancel()
if err != nil {
ctxCancel()
return nil, errors.Wrapf(err, "error creating connection to '%s': %v", address, err)
return nil, fmt.Errorf("error creating connection to '%s': %w", address, err)
}
if hasToken := os.Getenv(apiTokenEnvVarName); hasToken != "" {
logger.Println("client uses API token")
}
return newClientWithConnectionAndCancelFunc(conn, ctxCancel), nil
return NewClientWithConnection(conn), nil
}
func getClientTimeoutSeconds() (int, error) {
timeoutStr := os.Getenv(clientTimoutSecondsEnvVarName)
timeoutStr := os.Getenv(clientTimeoutSecondsEnvVarName)
if len(timeoutStr) == 0 {
return clientDefaultTimoutSeconds, nil
return clientDefaultTimeoutSeconds, nil
}
timeoutVar, err := strconv.Atoi(timeoutStr)
if err != nil {
@ -269,10 +271,14 @@ func NewClientWithSocket(socket string) (client Client, err error) {
return nil, errors.New("nil socket")
}
logger.Printf("dapr client initializing for: %s", socket)
addr := fmt.Sprintf("unix://%s", socket)
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
addr := "unix://" + socket
conn, err := grpc.Dial(
addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithUserAgent("dapr-sdk-go/"+version.SDKVersion),
)
if err != nil {
return nil, errors.Wrapf(err, "error creating connection to '%s': %v", addr, err)
return nil, fmt.Errorf("error creating connection to '%s': %w", addr, err)
}
if hasToken := os.Getenv(apiTokenEnvVarName); hasToken != "" {
logger.Println("client uses API token")
@ -282,32 +288,22 @@ func NewClientWithSocket(socket string) (client Client, err error) {
// NewClientWithConnection instantiates Dapr client using specific connection.
func NewClientWithConnection(conn *grpc.ClientConn) Client {
return newClientWithConnectionAndCancelFunc(conn, func() {})
}
func newClientWithConnectionAndCancelFunc(
conn *grpc.ClientConn,
cancelFunc context.CancelFunc,
) Client {
return &GRPCClient{
connection: conn,
ctxCancelFunc: cancelFunc,
protoClient: pb.NewDaprClient(conn),
authToken: os.Getenv(apiTokenEnvVarName),
connection: conn,
protoClient: pb.NewDaprClient(conn),
authToken: os.Getenv(apiTokenEnvVarName),
}
}
// GRPCClient is the gRPC implementation of Dapr client.
type GRPCClient struct {
connection *grpc.ClientConn
ctxCancelFunc context.CancelFunc
protoClient pb.DaprClient
authToken string
connection *grpc.ClientConn
protoClient pb.DaprClient
authToken string
}
// Close cleans up all resources created by the client.
func (c *GRPCClient) Close() {
c.ctxCancelFunc()
if c.connection != nil {
c.connection.Close()
c.connection = nil

View File

@ -27,6 +27,7 @@ import (
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/test/bufconn"
@ -85,7 +86,7 @@ func TestNewClient(t *testing.T) {
t.Run("new client closed with token", func(t *testing.T) {
t.Setenv(apiTokenEnvVarName, "test")
c, err := NewClientWithSocket(testSocket)
assert.NoError(t, err)
require.NoError(t, err)
defer c.Close()
c.WithAuthToken("")
})
@ -101,21 +102,21 @@ func TestNewClient(t *testing.T) {
t.Run("new socket client closed with token", func(t *testing.T) {
t.Setenv(apiTokenEnvVarName, "test")
c, err := NewClientWithSocket(testSocket)
assert.NoError(t, err)
require.NoError(t, err)
defer c.Close()
c.WithAuthToken("")
})
t.Run("new socket client closed with empty token", func(t *testing.T) {
c, err := NewClientWithSocket(testSocket)
assert.NoError(t, err)
require.NoError(t, err)
defer c.Close()
c.WithAuthToken("")
})
t.Run("new socket client with trace ID", func(t *testing.T) {
c, err := NewClientWithSocket(testSocket)
assert.NoError(t, err)
require.NoError(t, err)
defer c.Close()
ctx := c.WithTraceID(context.Background(), "")
_ = c.WithTraceID(ctx, "test")
@ -197,33 +198,33 @@ func getTestClientWithSocket(ctx context.Context) (client Client, closer func())
func Test_getClientTimeoutSeconds(t *testing.T) {
t.Run("empty env var", func(t *testing.T) {
os.Setenv(clientTimoutSecondsEnvVarName, "")
t.Setenv(clientTimeoutSecondsEnvVarName, "")
got, err := getClientTimeoutSeconds()
assert.NoError(t, err)
assert.Equal(t, clientDefaultTimoutSeconds, got)
assert.Equal(t, clientDefaultTimeoutSeconds, got)
})
t.Run("invalid env var", func(t *testing.T) {
os.Setenv(clientTimoutSecondsEnvVarName, "invalid")
t.Setenv(clientTimeoutSecondsEnvVarName, "invalid")
_, err := getClientTimeoutSeconds()
assert.Error(t, err)
})
t.Run("normal env var", func(t *testing.T) {
os.Setenv(clientTimoutSecondsEnvVarName, "7")
t.Setenv(clientTimeoutSecondsEnvVarName, "7")
got, err := getClientTimeoutSeconds()
assert.NoError(t, err)
assert.Equal(t, 7, got)
})
t.Run("zero env var", func(t *testing.T) {
os.Setenv(clientTimoutSecondsEnvVarName, "0")
t.Setenv(clientTimeoutSecondsEnvVarName, "0")
_, err := getClientTimeoutSeconds()
assert.Error(t, err)
})
t.Run("negative env var", func(t *testing.T) {
os.Setenv(clientTimoutSecondsEnvVarName, "-3")
t.Setenv(clientTimeoutSecondsEnvVarName, "-3")
_, err := getClientTimeoutSeconds()
assert.Error(t, err)
})

View File

@ -83,8 +83,8 @@ func (c *GRPCClient) SubscribeConfigurationItems(ctx context.Context, storeName
go func() {
for {
rsp, err := client.Recv()
if err == io.EOF || rsp == nil {
// receive goroutine would close if unsubscribe is called
if errors.Is(err, io.EOF) || rsp == nil {
// receive goroutine would close if unsubscribe is called.
fmt.Println("dapr configuration subscribe finished.")
close(stopCh)
break

View File

@ -70,7 +70,6 @@ func TestUnSubscribeConfigurationItems(t *testing.T) {
counter := atomic.Int32{}
totalCounter := atomic.Int32{}
t.Run("Test unsubscribe configuration items", func(t *testing.T) {
subscribeID := ""
subscribeIDChan := make(chan string)
go func() {
keys := []string{"mykey1", "mykey2", "mykey3"}
@ -88,7 +87,7 @@ func TestUnSubscribeConfigurationItems(t *testing.T) {
})
assert.Nil(t, err)
}()
subscribeID = <-subscribeIDChan
subscribeID := <-subscribeIDChan
time.Sleep(time.Second * 2)
time.Sleep(time.Millisecond * 500)
err := testClient.UnsubscribeConfigurationItems(ctx, "example-config", subscribeID)

View File

@ -55,7 +55,7 @@ func TestInvokeErrors(t *testing.T) {
}
func TestInvokeWithToken(t *testing.T) {
_ = os.Setenv(cc.AppAPITokenEnvVar, "app-dapr-token")
t.Setenv(cc.AppAPITokenEnvVar, "app-dapr-token")
server := getTestServer()
startTestServer(server)
methodName := "test"

View File

@ -49,6 +49,8 @@ func startTestServer(server *Server) {
}
func stopTestServer(t *testing.T, server *Server) {
t.Helper()
assert.NotNil(t, server)
err := server.Stop()
assert.Nilf(t, err, "error stopping server")

View File

@ -39,7 +39,7 @@ func TestInvocationHandlerWithoutHandler(t *testing.T) {
func TestInvocationHandlerWithToken(t *testing.T) {
data := `{"name": "test", "data": hello}`
_ = os.Setenv(common.AppAPITokenEnvVar, "app-dapr-token")
t.Setenv(common.AppAPITokenEnvVar, "app-dapr-token")
s := newServer("", nil)
err := s.AddServiceInvocationHandler("/hello", func(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) {
if in == nil || in.Data == nil || in.ContentType == "" {

View File

@ -44,7 +44,7 @@ func newServer(address string, router *mux.Router) *Server {
}
return &Server{
address: address,
httpServer: &http.Server{
httpServer: &http.Server{ //nolint:gosec
Addr: address,
Handler: router,
},

View File

@ -14,6 +14,7 @@ limitations under the License.
package http
import (
"errors"
"io"
"net/http"
"net/http/httptest"
@ -35,7 +36,7 @@ func TestStoppingStartedService(t *testing.T) {
assert.NotNil(t, s)
go func() {
if err := s.Start(); err != nil && err != http.ErrServerClosed {
if err := s.Start(); err != nil && !errors.Is(err, http.ErrServerClosed) {
panic(err)
}
}()
@ -70,6 +71,8 @@ func TestSettingOptions(t *testing.T) {
}
func testRequest(t *testing.T, s *Server, r *http.Request, expectedStatusCode int) {
t.Helper()
rr := httptest.NewRecorder()
s.mux.ServeHTTP(rr, r)
resp := rr.Result()
@ -79,6 +82,8 @@ func testRequest(t *testing.T, s *Server, r *http.Request, expectedStatusCode in
}
func testRequestWithResponseBody(t *testing.T, s *Server, r *http.Request, expectedStatusCode int, expectedBody []byte) {
t.Helper()
rr := httptest.NewRecorder()
s.mux.ServeHTTP(rr, r)
rez := rr.Result()

View File

@ -334,18 +334,24 @@ func TestActorHandler(t *testing.T) {
}
func makeRequest(t *testing.T, s *Server, route, data, method string, expectedStatusCode int) {
t.Helper()
req, err := http.NewRequest(method, route, strings.NewReader(data))
assert.NoErrorf(t, err, "error creating request: %s", data)
testRequest(t, s, req, expectedStatusCode)
}
func makeRequestWithExpectedBody(t *testing.T, s *Server, route, data, method string, expectedStatusCode int, expectedBody []byte) {
t.Helper()
req, err := http.NewRequest(method, route, strings.NewReader(data))
assert.NoErrorf(t, err, "error creating request: %s", data)
testRequestWithResponseBody(t, s, req, expectedStatusCode, expectedBody)
}
func makeEventRequest(t *testing.T, s *Server, route, data string, expectedStatusCode int) {
t.Helper()
req, err := http.NewRequest(http.MethodPost, route, strings.NewReader(data))
assert.NoErrorf(t, err, "error creating request: %s", data)
req.Header.Set("Content-Type", "application/json")

1
version/sdk-version Normal file
View File

@ -0,0 +1 @@
v1.6.0

11
version/version.go Normal file
View File

@ -0,0 +1,11 @@
package version
import (
// Required for go:embed.
_ "embed"
)
// SDKVersion contains the version of the SDK.
//
//go:embed sdk-version
var SDKVersion string