Skip to content

Commit

Permalink
Compatibility tests to validate k8s and tanzu context mutual exclusio…
Browse files Browse the repository at this point in the history
…n behavior

Signed-off-by: Prem Kumar Kalle <[email protected]>
  • Loading branch information
prkalle committed Nov 8, 2023
1 parent 30cd7ce commit 253d55a
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 4 deletions.
1 change: 1 addition & 0 deletions test/compatibility/core/api_constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
SetCurrentContextAPI RuntimeAPIName = "SetCurrentContext"
GetCurrentContextAPI RuntimeAPIName = "GetCurrentContext"
RemoveCurrentContextAPI RuntimeAPIName = "RemoveCurrentContext"
GetActiveContextAPI RuntimeAPIName = "GetActiveContext"

SetServerAPI RuntimeAPIName = "SetServer"
AddServerAPI RuntimeAPIName = "AddServer"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/vmware-tanzu/tanzu-plugin-runtime/test/compatibility/framework/context"
"github.com/vmware-tanzu/tanzu-plugin-runtime/test/compatibility/framework/executer"
"github.com/vmware-tanzu/tanzu-plugin-runtime/test/compatibility/framework/legacyclientconfig"
"github.com/vmware-tanzu/tanzu-plugin-runtime/test/compatibility/framework/types"
)

var _ = ginkgo.Describe("Cross-version Context APIs compatibility tests", func() {
Expand Down Expand Up @@ -1254,6 +1255,39 @@ var _ = ginkgo.Describe("Cross-version Context APIs compatibility tests", func()

executer.Execute(testCase)
})
})
ginkgo.Context("Using tanzu and k8s context types objects on supported Runtime API versions to validate mutual exclusion behavior", func() {
ginkgo.It("Run SetContext, SetCurrentContext, GetActiveContext latest then SetContext,SetCurrentContext, GetCurrentContext ,GetActiveContext, v1.0.2 then DeleteContext latest then SetContext, SetCurrentContext, GetCurrentContext v1.0.2 then SetContext, SetCurrentContext, GetActiveContext latest then GetCurrentContextCommand v1.0.2", func() {
testCase := core.NewTestCase()
// When latest plugin version sets tanzu context as current and later old plugin API version sets k8s context as active,
// the k8s context type and tanzu context types should be active which CLI would inspect and remove the tanzu context type from current contexts
testCase.Add(context.SetContextCommand(context.WithContextType(types.ContextTypeTanzu)))
testCase.Add(context.SetCurrentContextCommand())
testCase.Add(context.GetActiveContextCommand(context.WithContextType(types.ContextTypeTanzu)))

testCase.Add(context.SetContextCommand(context.WithRuntimeVersion(core.Version102), context.WithContextName(common.CompatibilityTestTwo)))
testCase.Add(context.SetCurrentContextCommand(context.WithRuntimeVersion(core.Version102), context.WithContextName(common.CompatibilityTestTwo)))
testCase.Add(context.GetCurrentContextCommand(context.WithRuntimeVersion(core.Version102), context.WithContextName(common.CompatibilityTestTwo)))

testCase.Add(context.GetActiveContextCommand(context.WithContextType(types.ContextTypeTanzu)))
testCase.Add(context.GetActiveContextCommand(context.WithContextName(common.CompatibilityTestTwo)))

// When old plugin API version sets k8s context as active and later if latest plugin version sets tanzu context as current,
// the k8s context type should be removed from the current context list automatically
testCase.Add(context.DeleteContextCommand(context.WithRuntimeVersion(core.Version102)))
testCase.Add(context.DeleteContextCommand(context.WithRuntimeVersion(core.Version102), context.WithContextName(common.CompatibilityTestTwo)))

testCase.Add(context.SetContextCommand(context.WithRuntimeVersion(core.Version102), context.WithContextName(common.CompatibilityTestTwo)))
testCase.Add(context.SetCurrentContextCommand(context.WithRuntimeVersion(core.Version102), context.WithContextName(common.CompatibilityTestTwo)))
testCase.Add(context.GetCurrentContextCommand(context.WithRuntimeVersion(core.Version102), context.WithContextName(common.CompatibilityTestTwo)))

testCase.Add(context.SetContextCommand(context.WithContextType(types.ContextTypeTanzu)))
testCase.Add(context.SetCurrentContextCommand())
testCase.Add(context.GetActiveContextCommand(context.WithContextType(types.ContextTypeTanzu)))
testCase.Add(context.GetActiveContextCommand(context.WithError()))
testCase.Add(context.GetCurrentContextCommand(context.WithRuntimeVersion(core.Version102), context.WithError()))

executer.Execute(testCase)
})
})
})
65 changes: 65 additions & 0 deletions test/compatibility/framework/context/context_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,71 @@ func NewGetCurrentContextCommand(inputOpts *GetCurrentContextInputOptions, outpu
return c, nil
}

// NewGetActiveContextCommand constructs a command to make a call to specific runtime version GetActiveContext API
// Input Parameter inputOpts has all input parameters which are required for Runtime GetActiveContext API
// Input Parameter: outputOpts has details about expected output from Runtime GetActiveContext API call
// Return: command to execute or error if any validations fails for GetActiveContextInputOptions or GetActiveContextOutputOptions
// This method does validate the input parameters GetActiveContextInputOptions or GetActiveContextOutputOptions based on Runtime API Version
// For more details about supported parameters refer to GetActiveContextInputOptions or GetActiveContextOutputOptions definition(and ContextOpts struct, which is embedded)
func NewGetActiveContextCommand(inputOpts *GetActiveContextInputOptions, outputOpts *GetActiveContextOutputOptions) (*core.Command, error) {
// Init the Command object
c := &core.Command{}
// Init the API object
api := &core.API{Name: core.GetActiveContextAPI}

// Validate the Input Options
_, err := inputOpts.Validate()
if err != nil {
return nil, err
}

// Set API version
api.Version = inputOpts.RuntimeVersion

// Construct the context api arguments and output
api.Arguments = make(map[core.APIArgumentType]interface{})

if inputOpts.ContextType != "" {
api.Arguments[core.ContextType] = inputOpts.ContextType
}

// Construct Output parameters
var res = core.Success
var content = ""

if outputOpts.ContextOpts != nil {
// Validate the Output Options
_, err = outputOpts.Validate()
if err != nil {
return nil, err
}

// Construct get active context output context opts
bytes, err := yaml.Marshal(outputOpts.ContextOpts)
if err != nil {
return nil, err
}

content = string(bytes)
res = core.Success
} else if outputOpts.Error != "" {
res = core.Failed
content = outputOpts.Error
}

api.Output = &core.Output{
Result: res,
Content: content,
}

if outputOpts.ValidationStrategy != "" {
api.Output.ValidationStrategy = outputOpts.ValidationStrategy
}

c.APIs = append(c.APIs, api)
return c, nil
}

// NewRemoveCurrentContextCommand constructs a command to make a call to specific runtime version RemoveCurrentContext API
// Input Parameter inputOpts has all input parameters which are required for Runtime RemoveCurrentContext API
// Input Parameter: outputOpts has details about expected output from Runtime RemoveCurrentContext API call
Expand Down
57 changes: 57 additions & 0 deletions test/compatibility/framework/context/context_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,60 @@ func SetCurrentContextCommand(opts ...CfgContextArgsOption) *core.Command {

return cmd
}

func GetActiveContextCommand(opts ...CfgContextArgsOption) *core.Command {
args := &CfgContextArgs{
RuntimeAPIVersion: &core.RuntimeAPIVersion{
RuntimeVersion: core.VersionLatest,
},
ContextName: common.CompatibilityTestOne,
Target: types.TargetK8s,
ContextType: types.ContextTypeK8s,
GlobalOpts: &types.GlobalServerOpts{
Endpoint: common.DefaultEndpoint,
},
}

for _, opt := range opts {
opt(args)
}

var inputOpts *GetActiveContextInputOptions
var outputOpts *GetActiveContextOutputOptions

switch args.RuntimeAPIVersion.RuntimeVersion {
case core.VersionLatest:
inputOpts = &GetActiveContextInputOptions{
RuntimeAPIVersion: args.RuntimeAPIVersion,
ContextType: args.ContextType,
}
if args.Error {
outputOpts = &GetActiveContextOutputOptions{
RuntimeAPIVersion: args.RuntimeAPIVersion,
Error: fmt.Sprintf("no current context set for type \"%v\"", args.ContextType),
}
} else {
outputOpts = &GetActiveContextOutputOptions{
RuntimeAPIVersion: args.RuntimeAPIVersion,
ContextOpts: &types.ContextOpts{
Name: args.ContextName,
Target: types.Target(args.ContextType),
ContextType: args.ContextType,
GlobalOpts: args.GlobalOpts,
},
ValidationStrategy: core.ValidationStrategyStrict,
}
}
default:
// add runtime version and context type for unsupported versions
inputOpts = &GetActiveContextInputOptions{
RuntimeAPIVersion: args.RuntimeAPIVersion,
ContextType: args.ContextType,
}
}

cmd, err := NewGetActiveContextCommand(inputOpts, outputOpts)
gomega.Expect(err).To(gomega.BeNil())

return cmd
}
21 changes: 21 additions & 0 deletions test/compatibility/framework/context/context_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ func WithTarget(target types.Target) CfgContextArgsOption {
func WithContextType(contextType types.ContextType) CfgContextArgsOption {
return func(c *CfgContextArgs) {
c.ContextType = contextType
c.Target = ""
}
}

func WithSetCurrentContext() CfgContextArgsOption {
return func(c *CfgContextArgs) {
c.SetCurrentContext = true
}
}

Expand Down Expand Up @@ -130,6 +137,20 @@ type GetCurrentContextOutputOptions struct {
Error string // expected error message could be the sub string of actual error message
}

// GetActiveContextInputOptions used to generate GetActiveContext command
type GetActiveContextInputOptions struct {
*core.RuntimeAPIVersion // required
ContextType types.ContextType // required for v1.1.0
}

// GetActiveContextOutputOptions used to generate GetActiveContext command
type GetActiveContextOutputOptions struct {
*core.RuntimeAPIVersion // required
*types.ContextOpts // For specific version options look into ContextOpts definition
ValidationStrategy core.ValidationStrategy // Type of validation to be performed i.e. exact or partial. default is partial
Error string // expected error message could be the sub string of actual error message
}

// RemoveCurrentContextInputOptions used to generate RemoveCurrentContext command
type RemoveCurrentContextInputOptions struct {
*core.RuntimeAPIVersion // required
Expand Down
38 changes: 36 additions & 2 deletions test/compatibility/framework/context/context_validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ func (opts *GetCurrentContextInputOptions) ShouldNotIncludeContextType() bool {
return opts.ContextType == ""
}

func (opts *GetActiveContextInputOptions) ShouldIncludeContextType() bool {
return opts.ContextType != ""
}

func (opts *RemoveCurrentContextInputOptions) ShouldNotIncludeTarget() bool {
return opts.Target == ""
}
Expand All @@ -32,7 +36,19 @@ func (opts *SetContextInputOptions) Validate() (bool, error) {
}

switch opts.RuntimeVersion {
case core.VersionLatest, core.Version102, core.Version090, core.Version0280:
case core.VersionLatest:
if !opts.ValidName() {
return false, fmt.Errorf("invalid 'name' for set context input options for the specified runtime version %v", opts.RuntimeVersion)
}
if !opts.ValidContextType() {
return false, fmt.Errorf("invalid 'ContextType' for set context input options for the specified runtime version %v", opts.RuntimeVersion)
}
if !opts.ValidGlobalOptsOrClusterOpts() {
return false, fmt.Errorf("invalid 'global or clusterOpts' for set context input options for the specified runtime version %v", opts.RuntimeVersion)
}
return true, nil

case core.Version102, core.Version090, core.Version0280:
if !opts.ValidName() {
return false, fmt.Errorf("invalid 'name' for set context input options for the specified runtime version %v", opts.RuntimeVersion)
}
Expand All @@ -47,7 +63,7 @@ func (opts *SetContextInputOptions) Validate() (bool, error) {
if !opts.ValidName() {
return false, fmt.Errorf("invalid 'Name' for set context input options for the specified runtime version %v", opts.RuntimeVersion)
}
if !opts.ValidContextType() {
if !opts.ValidType() {
return false, fmt.Errorf("invalid 'ContextType' for set context input options for the specified runtime version %v", opts.RuntimeVersion)
}
if !opts.ValidGlobalOptsOrClusterOpts() {
Expand Down Expand Up @@ -175,3 +191,21 @@ func (opts *GetCurrentContextOutputOptions) Validate() (bool, error) {
return false, errors.New("GetCurrentContext API is not supported for the specified runtime version")
}
}

// Validate the opts as per runtime version i.e. check whether the expected fields are supported for the runtime version specified
func (opts *GetActiveContextInputOptions) Validate() (bool, error) {
_, err := opts.RuntimeAPIVersion.Validate()
if err != nil {
return false, err
}

switch opts.RuntimeVersion {
case core.VersionLatest:
if !opts.ShouldIncludeContextType() {
return false, fmt.Errorf("invalid get current context input options for the specified runtime version contextType is not provided %v", opts.RuntimeVersion)
}
return true, nil
default:
return false, fmt.Errorf("GetActiveContext API is not supported for the specified runtime version %v", opts.RuntimeVersion)
}
}
2 changes: 1 addition & 1 deletion test/compatibility/framework/types/cfg_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const (
ContextTypeK8s ContextType = "kubernetes"

// ContextTypeTMC is a Tanzu Mission Control type of context.
ContextTypeTMC ContextType = "misson-control"
ContextTypeTMC ContextType = "mission-control"

// ContextTypeTanzu is a Tanzu control plane type of context.
ContextTypeTanzu ContextType = "tanzu"
Expand Down
6 changes: 5 additions & 1 deletion test/compatibility/framework/types/cfg_validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,13 @@ func (opts *ContextOpts) ValidTarget() bool {
return opts.Target != "" && (opts.Target == TargetK8s || opts.Target == TargetTMC)
}

func (opts *ContextOpts) ValidContextType() bool {
// ValidType validates legacy context type
func (opts *ContextOpts) ValidType() bool {
return opts.Type != "" && (opts.Type == CtxTypeK8s || opts.Type == CtxTypeTMC)
}
func (opts *ContextOpts) ValidContextType() bool {
return opts.ContextType != "" && (opts.ContextType == ContextTypeK8s || opts.ContextType == ContextTypeTMC || opts.ContextType == ContextTypeTanzu)
}

func (opts *ContextOpts) ValidGlobalOptsOrClusterOpts() bool {
return (opts.GlobalOpts != nil && opts.GlobalOpts.Endpoint != "") || (opts.ClusterOpts != nil && opts.ClusterOpts.Endpoint != "")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var apiHandlers = map[core.RuntimeAPIName]func(*core.API) *core.APIResponse{
core.SetCurrentContextAPI: triggerSetCurrentContextAPI,
core.GetCurrentContextAPI: triggerGetCurrentContextAPI,
core.RemoveCurrentContextAPI: triggerRemoveCurrentContextAPI,
core.GetActiveContextAPI: triggerGetActiveContextAPI,

// Server APIs
core.SetServerAPI: triggerSetServerAPI,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ func triggerGetCurrentContextAPI(api *core.API) *core.APIResponse {
return getCurrentContext(configtypes.Target(target))
}

// triggerGetActiveContextAPI trigger Runtime GetActiveContext API
func triggerGetActiveContextAPI(api *core.API) *core.APIResponse {
// Parse arguments needed to trigger the Runtime GetActiveContext API
ctxTypeStr, err := core.ParseStr(api.Arguments[core.ContextType])
if err != nil {
return &core.APIResponse{
ResponseType: core.ErrorResponse,
ResponseBody: fmt.Errorf("failed to parse string from argument %v with error %v ", core.ContextType, err.Error()),
}
}
// Trigger GetActiveContext API
return getActiveContext(configtypes.ContextType(ctxTypeStr))
}

// triggerRemoveCurrentContextAPI trigger Runtime RemoveCurrentContext API
func triggerRemoveCurrentContextAPI(api *core.API) *core.APIResponse {
// Parse arguments needed to trigger the Runtime RemoveCurrentContext API
Expand Down Expand Up @@ -178,6 +192,26 @@ func getCurrentContext(target configtypes.Target) *core.APIResponse {
}
}

func getActiveContext(contextType configtypes.ContextType) *core.APIResponse {
ctx, err := configlib.GetActiveContext(contextType)
if err != nil {
return &core.APIResponse{
ResponseType: core.ErrorResponse,
ResponseBody: err.Error(),
}
}
if ctx == nil {
return &core.APIResponse{
ResponseType: core.ErrorResponse,
ResponseBody: fmt.Errorf("context %s not found", contextType),
}
}
return &core.APIResponse{
ResponseType: core.MapResponse,
ResponseBody: ctx,
}
}

func removeCurrentContext(target configtypes.Target) *core.APIResponse {
err := configlib.RemoveCurrentContext(target) //nolint:staticcheck // Deprecated
if err != nil {
Expand Down

0 comments on commit 253d55a

Please sign in to comment.