Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix metadata, add helper generator #612

Closed
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ jobs:
run: go get -u github.com/golang/protobuf/protoc-gen-go@v1.4.2
- name: Install go-syncmap
run: go get github.com/searKing/golang/tools/cmd/go-syncmap
- name: Install genny
run: go get github.com/cheekybits/genny
- name: Generate files
run: go generate ./...
- name: Check for changes in generated code
Expand Down
5 changes: 5 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ issues:
linters:
- dupl
- golint
- goheader
- path: .*\.template\.go
linters:
- dupl
- deadcode
- path: .*registry.*.go
linters:
- dupl
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.15
require (
github.com/HdrHistogram/hdrhistogram-go v1.0.0 // indirect
github.com/RoaringBitmap/roaring v0.4.23
github.com/cheekybits/genny v1.0.0
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/edwarnicke/exechelper v1.0.2
github.com/edwarnicke/grpcfd v0.0.0-20200920223154-d5b6e1f19bd0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ github.com/bombsimon/wsl/v3 v3.1.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
Expand Down
8 changes: 6 additions & 2 deletions pkg/networkservice/utils/metadata/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,16 @@ func NewClient() networkservice.NetworkServiceClient {
}

func (m *metaDataClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
ctx = store(ctx, request.GetConnection().GetId(), &m.Map)
connID := request.GetConnection().GetId()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although... it should always be true that the conn..GetId() below is the same as the request.GetConnection().GetId() ... its good defensive coding what you've done here, but an issue here would have been a sign of a bug in updatetoken ...


ctx = store(ctx, connID, &m.Map)

conn, err := next.Client(ctx).Request(ctx, request, opts...)
if err != nil {
del(ctx, conn.GetId(), &m.Map)
del(ctx, connID, &m.Map)
return nil, err
}

return conn, nil
}

Expand Down
10 changes: 0 additions & 10 deletions pkg/networkservice/utils/metadata/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,3 @@ type metaData struct {
client sync.Map
server sync.Map
}

Bolodya1997 marked this conversation as resolved.
Show resolved Hide resolved
// LoadAndDelete deletes the value for a key, returning the previous value if any.
// The loaded result reports whether the key was present.
func (m *metaDataMap) LoadAndDelete(key string) (value *metaData, loaded bool) {
actual, loaded := (*sync.Map)(m).LoadAndDelete(key)
if actual == nil {
return nil, loaded
}
return actual.(*metaData), loaded
}
51 changes: 42 additions & 9 deletions pkg/networkservice/utils/metadata/meta_data_map.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

150 changes: 150 additions & 0 deletions pkg/networkservice/utils/metadata/meta_data_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright (c) 2020 Doc.ai and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package metadata_test

import (
"context"
"testing"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"

"github.com/networkservicemesh/sdk/pkg/networkservice/common/updatepath"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/adapters"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/next"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkcontext"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/inject/injecterror"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata"
)

const (
testKey = "test"
)

func testServer(server networkservice.NetworkServiceServer) networkservice.NetworkServiceServer {
return next.NewNetworkServiceServer(
updatepath.NewServer("server"),
server,
)
}

func testRequest(conn *networkservice.Connection) *networkservice.NetworkServiceRequest {
return &networkservice.NetworkServiceRequest{
Connection: conn,
}
}

type sample struct {
name string
test func(t *testing.T, server networkservice.NetworkServiceServer, isClient bool)
}

var samples = []*sample{
{
name: "Request",
test: func(t *testing.T, server networkservice.NetworkServiceServer, isClient bool) {
var actual, expected map[string]string = nil, map[string]string{"a": "A"}

chainServer := next.NewNetworkServiceServer(
testServer(server),
checkcontext.NewServer(t, func(_ *testing.T, ctx context.Context) {
metadata.Map(ctx, isClient).Store(testKey, expected)
}),
)
conn, err := chainServer.Request(context.TODO(), testRequest(nil))
require.NoError(t, err)

chainServer = next.NewNetworkServiceServer(
testServer(server),
checkcontext.NewServer(t, func(_ *testing.T, ctx context.Context) {
if raw, ok := metadata.Map(ctx, isClient).Load(testKey); ok {
actual = raw.(map[string]string)
} else {
actual = nil
}
}),
)
_, err = chainServer.Request(context.TODO(), testRequest(conn))
require.NoError(t, err)

require.Equal(t, expected, actual)
},
},
{
name: "Request failed",
test: func(t *testing.T, server networkservice.NetworkServiceServer, _ bool) {
chainServer := next.NewNetworkServiceServer(
testServer(server),
injecterror.NewServer(errors.New("error")),
)
_, err := chainServer.Request(context.TODO(), testRequest(nil))
require.Error(t, err)
},
},
{
name: "Close",
test: func(t *testing.T, server networkservice.NetworkServiceServer, isClient bool) {
data := map[string]string{"a": "A"}

chainServer := next.NewNetworkServiceServer(
testServer(server),
checkcontext.NewServer(t, func(_ *testing.T, ctx context.Context) {
metadata.Map(ctx, isClient).Store(testKey, data)
}),
)
conn, err := chainServer.Request(context.TODO(), testRequest(nil))
require.NoError(t, err)

_, err = testServer(server).Close(context.TODO(), conn)
require.NoError(t, err)

chainServer = next.NewNetworkServiceServer(
testServer(server),
checkcontext.NewServer(t, func(_ *testing.T, ctx context.Context) {
if raw, ok := metadata.Map(ctx, isClient).Load(testKey); ok {
data = raw.(map[string]string)
} else {
data = nil
}
}),
)
_, err = chainServer.Request(context.TODO(), testRequest(conn))
require.NoError(t, err)

require.Nil(t, data)
},
},
}

func TestMetaDataServer(t *testing.T) {
for i := range samples {
sample := samples[i]
t.Run(sample.name, func(t *testing.T) {
sample.test(t, metadata.NewServer(), false)
})
}
}

func TestMetaDataClient(t *testing.T) {
for i := range samples {
sample := samples[i]
t.Run(sample.name, func(t *testing.T) {
sample.test(t, adapters.NewClientToServer(metadata.NewClient()), true)
})
}
}
9 changes: 7 additions & 2 deletions pkg/networkservice/utils/metadata/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@ func NewServer() networkservice.NetworkServiceServer {
}

func (m *metadataServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) {
ctx = store(ctx, request.GetConnection().GetId(), &m.Map)
connID := request.GetConnection().GetId()

ctx = store(ctx, connID, &m.Map)

conn, err := next.Server(ctx).Request(ctx, request)
if err != nil {
del(ctx, conn.GetId(), &m.Map)
del(ctx, connID, &m.Map)
return nil, err
}

return conn, nil
}

Expand Down
69 changes: 69 additions & 0 deletions pkg/tools/metadatahelper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Metadata helper

Metadata helper is a [genny](https://github.com/cheekybits/genny) template to generate a helper class for the metadata
usage. Template parameters are:
* prefix - prefix for the metadata type and constructor;
* valueType - stored type.
Generated helpers can both be exported (**P**refix) and unexported (**p**refix).

gen.go:
```go
package connect

//go:generate bash -c "genny -in=$(go list -f '{{.Dir}} github.com/networkservicemesh/sdk/pkg/tools/metadatahelper)/meta_data.template.go -out=client_meta_data.gen.go -pkg=$GOPACKAGE gen 'prefix=client valueType=networkservice.NetworkServiceClient'"
```
client_meta_data.gen.go:
```go
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny

package connect

import (
"context"
"sync"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata"
)

type _ClientKeyType struct{}

type clientMetadataHelper struct {
m *sync.Map
}

func clientMetadata(ctx context.Context, isClient bool) *clientMetadataHelper {
return &clientMetadataHelper{
m: metadata.Map(ctx, isClient),
}
}

func (h *clientMetadataHelper) Store(value networkservice.NetworkServiceClient) {
h.m.Store(_ClientKeyType{}, value)
}

func (h *clientMetadataHelper) LoadOrStore(value networkservice.NetworkServiceClient) (networkservice.NetworkServiceClient, bool) {
raw, ok := h.m.LoadOrStore(_ClientKeyType{}, value)
return raw.(networkservice.NetworkServiceClient), ok
}

func (h *clientMetadataHelper) Load() (networkservice.NetworkServiceClient, bool) {
if raw, ok := h.m.Load(_ClientKeyType{}); ok {
return raw.(networkservice.NetworkServiceClient), true
}
return func() (v networkservice.NetworkServiceClient) { return }(), false
}

func (h *clientMetadataHelper) LoadAndDelete() (networkservice.NetworkServiceClient, bool) {
if raw, ok := h.m.LoadAndDelete(_ClientKeyType{}); ok {
return raw.(networkservice.NetworkServiceClient), true
}
return func() (v networkservice.NetworkServiceClient) { return }(), false
}

func (h *clientMetadataHelper) Delete() {
h.m.Delete(_ClientKeyType{})
}
```
Loading