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

Add checkmechanism test suite #141

Merged
merged 1 commit into from
Feb 24, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) 2020 Cisco 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 checkmechanism provides TestSuites for use with implementations of a mechanism networkservice chain element.
package checkmechanism

import (
"context"
"testing"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"

"github.com/networkservicemesh/sdk/pkg/networkservice/common/mechanisms"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/adapters"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/chain"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkrequest"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/null"
)

type checkClientSetsMechanismPreferences struct {
networkservice.NetworkServiceClient
}

// CheckClientSetsMechanismPreferences - returns a NetworkServiceClient that will check to make sure that the
// clientUnderTest correctly sets the MechanismPreferences to include
// a mechanism of type mechanismType
// t - *testing.T for checking
// clientUnderTest - client we are testing
// mechanismType - Mechanism.Type implemented by clientUnderTest
// mechanismCheck - function to check for any parameters that should be present in
// the MechanismPreference
func CheckClientSetsMechanismPreferences(t *testing.T, clientUnderTest networkservice.NetworkServiceClient, mechanismType string, mechanismCheck func(*testing.T, *networkservice.Mechanism)) networkservice.NetworkServiceClient {
rv := &checkClientSetsMechanismPreferences{}
rv.NetworkServiceClient = chain.NewNetworkServiceClient(
clientUnderTest,
// Check after the clientUnderTest under test is run to make sure we have the right MechanismPreferences set
checkrequest.NewClient(t,
func(t *testing.T, req *networkservice.NetworkServiceRequest) {
var found bool
for _, mechanism := range req.GetMechanismPreferences() {
if mechanism.GetType() == mechanismType {
found = true
// Run any mechanism specific checks
mechanismCheck(t, mechanism)
}
}
assert.True(t, found, "Did not find %s Mechanism in MechanismPreferences", mechanismType)
},
),
// Its important to have a working 'server' to return a connection to us
adapters.NewServerToClient(mechanisms.NewServer(
map[string]networkservice.NetworkServiceServer{
mechanismType: null.NewServer(),
}),
),
)
return rv
}

func (m *checkClientSetsMechanismPreferences) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
// Make sure we are creating a copy before we change it
request = request.Clone()
// Make sure no MechanismPreferences are set
request.MechanismPreferences = nil
return m.NetworkServiceClient.Request(ctx, request)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) 2020 Cisco 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 checkmechanism

import (
"context"
"testing"

"github.com/networkservicemesh/api/pkg/api/networkservice"

"github.com/networkservicemesh/sdk/pkg/networkservice/common/mechanisms"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/adapters"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/chain"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkcontext"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkcontextonreturn"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/null"
)

// CheckClientContextOnReturn - returns a NetworkServiceClient that will check the state of the context.Context
// after the clientUnderTest has returned
// t - *testing.T for checks
// clientUnderTest - client we are testing - presumed to implement a mechanism
// mechanismType - Mechanism.Type implemented by the clientUnderTest
// check - function to check the state of the context.Context after the clientUnderTest has returned
func CheckClientContextOnReturn(t *testing.T, clientUnderTest networkservice.NetworkServiceClient, mechanismType string, check func(*testing.T, context.Context)) networkservice.NetworkServiceClient {
return chain.NewNetworkServiceClient(
checkcontextonreturn.NewClient(t, check),
clientUnderTest,
adapters.NewServerToClient(mechanisms.NewServer(
map[string]networkservice.NetworkServiceServer{
mechanismType: null.NewServer(),
})),
)
}

// CheckClientContextAfter - returns a NetworkServiceClient that will check the state of the context.Context after it has left
// the clientUnderTest. Note: it should almost always be the case that there are no side effects
// related to implementing the Mechanism at this point, as the clientUnderTest can't know what to
// do until after the elements after it have returned a fully complete Connection.
// t - *testing.T for checks
// clientUnderTest - client we are testing - presumed to implement a mechanism
// mechanismType - Mechanism.Type implemented by the clientUnderTest
// check - function to check that the clientUnderTest has not taken action to implement the Mechanism
// (as it cannot know what to do at this stage)
func CheckClientContextAfter(t *testing.T, client networkservice.NetworkServiceClient, mechanismType string, check func(*testing.T, context.Context)) networkservice.NetworkServiceClient {
return chain.NewNetworkServiceClient(
client,
checkcontext.NewClient(t, check),
adapters.NewServerToClient(mechanisms.NewServer(
map[string]networkservice.NetworkServiceServer{
mechanismType: null.NewServer(),
})),
)
}

// CheckContextAfterServer - returns a NetworkServiceServer that will check the state of the context.Context after it has
// left the serverUnderTest. At this time the context.Context should contain any side effects needed
// to implement the Mechanism, as it should have a complete Connection to work with.
// t - *testing.T for checks
// serverUnderTest - server we are testing - presumed to implement a mechanism
// mechanismType - Mechanism.Type implemented by the serverUnderTest
// check - function to check that the serverUnderTest has taken action to implement the Mechanism
func CheckContextAfterServer(t *testing.T, serverUnderTest networkservice.NetworkServiceServer, mechanismType string, check func(*testing.T, context.Context)) networkservice.NetworkServiceServer {
return chain.NewNetworkServiceServer(
mechanisms.NewServer(
map[string]networkservice.NetworkServiceServer{
mechanismType: serverUnderTest,
},
),
checkcontext.NewServer(t, check),
)
}
137 changes: 137 additions & 0 deletions pkg/networkservice/common/mechanisms/checkmechanism/client_suite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright (c) 2020 Cisco 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 checkmechanism

import (
"context"
"testing"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"

"github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkerror"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkopts"
)

// ClientSuite - test suite to check that a NetworkServiceClient implementing a Mechanism meets basic contracts
type ClientSuite struct {
suite.Suite
clientUnderTest networkservice.NetworkServiceClient
configureContext func(ctx context.Context) context.Context
mechanismType string
mechanismCheck func(*testing.T, *networkservice.Mechanism)
contextOnReturnCheck func(*testing.T, context.Context)
contextCheck func(*testing.T, context.Context)
Request *networkservice.NetworkServiceRequest
ConnClose *networkservice.Connection
}

// NewClientSuite - returns a ClientTestSuite
// clientUnderTest - the client we are testing to make sure it correctly implements a Mechanism
// configureContext - a function that is applied to context.Background to make sure anything
// needed by the clientUnderTest is present in the context.Context
// mechanismType - Mechanism.Type implemented by the clientUnderTest
// mechanismCheck - function to check that the clientUnderTest has properly added Mechanism.Parameters
// to the Mechanism it has appended to MechanismPreferences
// contextOnReturnCheck - function to check that the context.Context *after* clientUnderTest has returned are correct
// contextCheck - function to check that the clientUnderTest introduces no side effects to the context.Context
// before calling the next element in the chain
// request - NetworkServiceRequest to be used for testing
// connClose - Connection to be used for testing Close(...)
func NewClientSuite(
clientUnderTest networkservice.NetworkServiceClient,
configureContext func(ctx context.Context) context.Context,
mechanismType string,
mechanismCheck func(*testing.T, *networkservice.Mechanism),
contextOnReturnCheck,
contextCheck func(*testing.T, context.Context),

request *networkservice.NetworkServiceRequest,
connClose *networkservice.Connection,
) *ClientSuite {
return &ClientSuite{
clientUnderTest: clientUnderTest,
configureContext: configureContext,
mechanismType: mechanismType,
mechanismCheck: mechanismCheck,
contextOnReturnCheck: contextOnReturnCheck,
contextCheck: contextCheck,
Request: request,
ConnClose: connClose,
}
}

// TestPropagatesError - tests that the clientUnderTest returns an error when the next element in the chain returned an error to it
func (m *ClientSuite) TestPropagatesError() {
check := checkerror.CheckPropagatesErrorClient(m.T(), m.clientUnderTest)
_, err := check.Request(m.configureContext(context.Background()), m.Request.Clone())
assert.NotNil(m.T(), err)
_, err = check.Close(m.configureContext(context.Background()), m.ConnClose)
assert.NotNil(m.T(), err)
}

// TestPropogatesOpts - tests that the clientUnderTest passes along the grpc.CallOptions to the next client in the chain
func (m *ClientSuite) TestPropogatesOpts() {
contract := checkopts.CheckPropogateOptsClient(m.T(), m.clientUnderTest)
_, err := contract.Request(m.configureContext(context.Background()), m.Request.Clone())
assert.Nil(m.T(), err)
_, err = contract.Close(m.configureContext(context.Background()), m.ConnClose)
assert.Nil(m.T(), err)
}

// TestSetsMechanismPreference - test that the clientUnderTest correctly sets MechanismPreferences for the Mechanism it implements
// before calling the next element in the chain
func (m *ClientSuite) TestSetsMechanismPreference() {
check := CheckClientSetsMechanismPreferences(m.T(),
m.clientUnderTest,
m.mechanismType,
m.mechanismCheck,
)
conn, err := check.Request(m.configureContext(context.Background()), m.Request.Clone())
assert.Nil(m.T(), err)
_, err = check.Close(m.configureContext(context.Background()), conn)
assert.Nil(m.T(), err)
_, err = check.Close(m.configureContext(context.Background()), m.ConnClose)
assert.Nil(m.T(), err)
}

// TestContextOnReturn - test that the clientUnderTest has the correct side effects on the context.Context when it returns
func (m *ClientSuite) TestContextOnReturn() {
contract := CheckClientContextOnReturn(m.T(),
m.clientUnderTest,
m.mechanismType,
m.contextOnReturnCheck,
)
_, err := contract.Request(m.configureContext(context.Background()), m.Request.Clone())
assert.Nil(m.T(), err)
_, err = contract.Close(m.configureContext(context.Background()), m.ConnClose)
assert.Nil(m.T(), err)
}

// TestContextAfter - tests that the clientUnderTest has no side effects on the context.Context before it calls the next element in the chain
func (m *ClientSuite) TestContextAfter() {
contract := CheckClientContextAfter(m.T(),
m.clientUnderTest,
m.mechanismType,
m.contextCheck,
)
_, err := contract.Request(m.configureContext(context.Background()), m.Request.Clone())
assert.Nil(m.T(), err)
_, err = contract.Close(m.configureContext(context.Background()), m.ConnClose)
assert.Nil(m.T(), err)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) 2020 Cisco 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 checkmechanism

import (
"context"
"testing"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"

"github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkerror"
)

// ServerSuite - test suite to check that a NetworkServiceServer implementing a Mechanism meets basic contracts
type ServerSuite struct {
suite.Suite
serverUnderTest networkservice.NetworkServiceServer
configureContext func(ctx context.Context) context.Context
mechanismType string
contextCheck func(*testing.T, context.Context)
Request *networkservice.NetworkServiceRequest
ConnClose *networkservice.Connection
}

// NewServerSuite - returns a ServerSuite
// serverUnderTest - the server being tested to make sure it correctly implements a Mechanism
// configureContext - a function that is applied to context.Background to make sure anything
// needed by the serverUnderTest is present in the context.Context
// mechanismType - Mechanism.Type implemented by the serverUnderTest
// contextCheck - function to check that the serverUnderTest introduces all needed side effects to the context.Context
// before calling the next element in the chain
// request - NetworkServiceRequest to be used for testing
// connClose - Connection to be used for testing Close(...)
func NewServerSuite(
serverUnderTest networkservice.NetworkServiceServer,
configureContext func(ctx context.Context) context.Context,
mechanismType string,
contextCheck func(*testing.T, context.Context),
request *networkservice.NetworkServiceRequest,
connClose *networkservice.Connection,
) *ServerSuite {
return &ServerSuite{
serverUnderTest: serverUnderTest,
configureContext: configureContext,
mechanismType: mechanismType,
contextCheck: contextCheck,
Request: request,
ConnClose: connClose,
}
}

// TestPropagatesError - tests that the serverUnderTest returns an error when the next element in the chain returned an error to it
func (m *ServerSuite) TestPropagatesError() {
contract := checkerror.CheckPropogatesErrorServer(m.T(), m.serverUnderTest)
_, err := contract.Request(m.configureContext(context.Background()), m.Request.Clone())
assert.NotNil(m.T(), err)
_, err = contract.Close(m.configureContext(context.Background()), m.ConnClose)
assert.NotNil(m.T(), err)
}

// TestContextAfter - tests that the serverUnderTest has all needed side effects on the context.Context before it calls the next element in the chain
func (m *ServerSuite) TestContextAfter() {
contract := CheckContextAfterServer(m.T(),
m.serverUnderTest,
m.mechanismType,
m.contextCheck,
)
_, err := contract.Request(m.configureContext(context.Background()), m.Request.Clone())
assert.Nil(m.T(), err)
_, err = contract.Close(m.configureContext(context.Background()), m.ConnClose)
assert.Nil(m.T(), err)
}