package appmesh

import (
	"context"
	appmesh "github.com/aws/aws-app-mesh-controller-for-k8s/apis/appmesh/v1beta2"
	mock_mesh "github.com/aws/aws-app-mesh-controller-for-k8s/mocks/aws-app-mesh-controller-for-k8s/pkg/mesh"
	mock_virtualgateway "github.com/aws/aws-app-mesh-controller-for-k8s/mocks/aws-app-mesh-controller-for-k8s/pkg/virtualgateway"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/golang/mock/gomock"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/assert"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"testing"
)

func Test_gatewayRouteMutator_defaultingAWSName(t *testing.T) {
	type args struct {
		gr *appmesh.GatewayRoute
	}
	tests := []struct {
		name    string
		args    args
		want    *appmesh.GatewayRoute
		wantErr error
	}{
		{
			name: "GatewayRoute didn't specify awsName",
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					AWSName: aws.String("my-gr_awesome-ns"),
				},
			},
		},
		{
			name: "GatewayRoute specified empty awsName",
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{
						AWSName: aws.String(""),
					},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					AWSName: aws.String("my-gr_awesome-ns"),
				},
			},
		},
		{
			name: "GatewayRoute specified non-empty awsName",
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{
						AWSName: aws.String("my-gr_awesome-ns_my-cluster"),
					},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					AWSName: aws.String("my-gr_awesome-ns_my-cluster"),
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			m := &gatewayRouteMutator{}
			err := m.defaultingAWSName(tt.args.gr)
			if tt.wantErr != nil {
				assert.EqualError(t, err, tt.wantErr.Error())
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.want, tt.args.gr)
			}
		})
	}
}

func Test_gatewayRouteMutator_designateMeshMembership(t *testing.T) {
	type fields struct {
		meshMembershipDesignatorDesignate func(ctx context.Context, obj metav1.Object) (*appmesh.Mesh, error)
	}
	type args struct {
		gr *appmesh.GatewayRoute
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    *appmesh.GatewayRoute
		wantErr error
	}{
		{
			name: "successfully designate mesh membership",
			fields: fields{
				meshMembershipDesignatorDesignate: func(ctx context.Context, obj metav1.Object) (*appmesh.Mesh, error) {
					return &appmesh.Mesh{
						ObjectMeta: metav1.ObjectMeta{
							Name: "my-mesh",
							UID:  "408d3036-7dec-11ea-b156-0e30aabe1ca8",
						},
					}, nil
				},
			},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					MeshRef: &appmesh.MeshReference{
						Name: "my-mesh",
						UID:  "408d3036-7dec-11ea-b156-0e30aabe1ca8",
					},
				},
			},
		},
		{
			name: "failed to designate mesh membership",
			fields: fields{
				meshMembershipDesignatorDesignate: func(ctx context.Context, obj metav1.Object) (*appmesh.Mesh, error) {
					return nil, errors.New("oops, some error happened")
				},
			},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			wantErr: errors.New("oops, some error happened"),
		},
		{
			name:   "meshRef already specified",
			fields: fields{},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{
						MeshRef: &appmesh.MeshReference{
							Name: "my-mesh",
							UID:  "408d3036-7dec-11ea-b156-0e30aabe1ca8",
						},
					},
				},
			},
			wantErr: errors.New("GatewayRoute create may not specify read-only field: spec.meshRef"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := context.Background()
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()
			designator := mock_mesh.NewMockMembershipDesignator(ctrl)
			if tt.fields.meshMembershipDesignatorDesignate != nil {
				designator.EXPECT().Designate(gomock.Any(), gomock.Any()).DoAndReturn(tt.fields.meshMembershipDesignatorDesignate)
			}

			m := &gatewayRouteMutator{
				meshMembershipDesignator:           designator,
				virtualGatewayMembershipDesignator: nil,
			}
			_, err := m.designateMeshMembership(ctx, tt.args.gr)

			if tt.wantErr != nil {
				assert.EqualError(t, err, tt.wantErr.Error())
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.want, tt.args.gr)
			}
		})
	}
}

func Test_gatewayRouteMutator_designateVirtualGatewayMembership(t *testing.T) {
	type fields struct {
		vgMembershipDesignatorDesignate func(ctx context.Context, obj metav1.Object) (*appmesh.VirtualGateway, error)
	}
	type args struct {
		gr *appmesh.GatewayRoute
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    *appmesh.GatewayRoute
		wantErr error
	}{
		{
			name: "successfully designate virtualGateway membership",
			fields: fields{
				vgMembershipDesignatorDesignate: func(ctx context.Context, obj metav1.Object) (*appmesh.VirtualGateway, error) {
					return &appmesh.VirtualGateway{
						ObjectMeta: metav1.ObjectMeta{
							Name:      "my-vg",
							Namespace: "gateway-ns",
							UID:       "408d3036-7dec-11ea-b156-0e30aabe1ca8",
						},
					}, nil
				},
			},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					VirtualGatewayRef: &appmesh.VirtualGatewayReference{
						Name:      "my-vg",
						Namespace: aws.String("gateway-ns"),
						UID:       "408d3036-7dec-11ea-b156-0e30aabe1ca8",
					},
				},
			},
		},
		{
			name: "failed to designate virtualGateway membership",
			fields: fields{
				vgMembershipDesignatorDesignate: func(ctx context.Context, obj metav1.Object) (*appmesh.VirtualGateway, error) {
					return nil, errors.New("oops, some error happened")
				},
			},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			wantErr: errors.New("oops, some error happened"),
		},
		{
			name:   "virtualGatewayRef already specified",
			fields: fields{},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{
						VirtualGatewayRef: &appmesh.VirtualGatewayReference{
							Name:      "my-vg",
							Namespace: aws.String("gateway-ns"),
							UID:       "408d3036-7dec-11ea-b156-0e30aabe1ca8",
						},
					},
				},
			},
			wantErr: errors.New("GatewayRoute create may not specify read-only field: spec.virtualGatewayRef"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := context.Background()
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()
			designator := mock_virtualgateway.NewMockMembershipDesignator(ctrl)
			if tt.fields.vgMembershipDesignatorDesignate != nil {
				designator.EXPECT().DesignateForGatewayRoute(gomock.Any(), gomock.Any()).DoAndReturn(tt.fields.vgMembershipDesignatorDesignate)
			}

			m := &gatewayRouteMutator{
				meshMembershipDesignator:           nil,
				virtualGatewayMembershipDesignator: designator,
			}
			_, err := m.designateVirtualGatewayMembership(ctx, tt.args.gr)

			if tt.wantErr != nil {
				assert.EqualError(t, err, tt.wantErr.Error())
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.want, tt.args.gr)
			}
		})
	}
}
package appmesh

import (
	"context"
	appmesh "github.com/aws/aws-app-mesh-controller-for-k8s/apis/appmesh/v1beta2"
	mock_mesh "github.com/aws/aws-app-mesh-controller-for-k8s/mocks/aws-app-mesh-controller-for-k8s/pkg/mesh"
	mock_virtualgateway "github.com/aws/aws-app-mesh-controller-for-k8s/mocks/aws-app-mesh-controller-for-k8s/pkg/virtualgateway"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/golang/mock/gomock"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/assert"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"testing"
)

func Test_gatewayRouteMutator_defaultingAWSName(t *testing.T) {
	type args struct {
		gr *appmesh.GatewayRoute
	}
	tests := []struct {
		name    string
		args    args
		want    *appmesh.GatewayRoute
		wantErr error
	}{
		{
			name: "GatewayRoute didn't specify awsName",
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					AWSName: aws.String("my-gr_awesome-ns"),
				},
			},
		},
		{
			name: "GatewayRoute specified empty awsName",
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{
						AWSName: aws.String(""),
					},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					AWSName: aws.String("my-gr_awesome-ns"),
				},
			},
		},
		{
			name: "GatewayRoute specified non-empty awsName",
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{
						AWSName: aws.String("my-gr_awesome-ns_my-cluster"),
					},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					AWSName: aws.String("my-gr_awesome-ns_my-cluster"),
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			m := &gatewayRouteMutator{}
			err := m.defaultingAWSName(tt.args.gr)
			if tt.wantErr != nil {
				assert.EqualError(t, err, tt.wantErr.Error())
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.want, tt.args.gr)
			}
		})
	}
}

func Test_gatewayRouteMutator_designateMeshMembership(t *testing.T) {
	type fields struct {
		meshMembershipDesignatorDesignate func(ctx context.Context, obj metav1.Object) (*appmesh.Mesh, error)
	}
	type args struct {
		gr *appmesh.GatewayRoute
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    *appmesh.GatewayRoute
		wantErr error
	}{
		{
			name: "successfully designate mesh membership",
			fields: fields{
				meshMembershipDesignatorDesignate: func(ctx context.Context, obj metav1.Object) (*appmesh.Mesh, error) {
					return &appmesh.Mesh{
						ObjectMeta: metav1.ObjectMeta{
							Name: "my-mesh",
							UID:  "408d3036-7dec-11ea-b156-0e30aabe1ca8",
						},
					}, nil
				},
			},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					MeshRef: &appmesh.MeshReference{
						Name: "my-mesh",
						UID:  "408d3036-7dec-11ea-b156-0e30aabe1ca8",
					},
				},
			},
		},
		{
			name: "failed to designate mesh membership",
			fields: fields{
				meshMembershipDesignatorDesignate: func(ctx context.Context, obj metav1.Object) (*appmesh.Mesh, error) {
					return nil, errors.New("oops, some error happened")
				},
			},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			wantErr: errors.New("oops, some error happened"),
		},
		{
			name:   "meshRef already specified",
			fields: fields{},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{
						MeshRef: &appmesh.MeshReference{
							Name: "my-mesh",
							UID:  "408d3036-7dec-11ea-b156-0e30aabe1ca8",
						},
					},
				},
			},
			wantErr: errors.New("GatewayRoute create may not specify read-only field: spec.meshRef"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := context.Background()
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()
			designator := mock_mesh.NewMockMembershipDesignator(ctrl)
			if tt.fields.meshMembershipDesignatorDesignate != nil {
				designator.EXPECT().Designate(gomock.Any(), gomock.Any()).DoAndReturn(tt.fields.meshMembershipDesignatorDesignate)
			}

			m := &gatewayRouteMutator{
				meshMembershipDesignator:           designator,
				virtualGatewayMembershipDesignator: nil,
			}
			_, err := m.designateMeshMembership(ctx, tt.args.gr)

			if tt.wantErr != nil {
				assert.EqualError(t, err, tt.wantErr.Error())
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.want, tt.args.gr)
			}
		})
	}
}

func Test_gatewayRouteMutator_designateVirtualGatewayMembership(t *testing.T) {
	type fields struct {
		vgMembershipDesignatorDesignate func(ctx context.Context, obj metav1.Object) (*appmesh.VirtualGateway, error)
	}
	type args struct {
		gr *appmesh.GatewayRoute
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    *appmesh.GatewayRoute
		wantErr error
	}{
		{
			name: "successfully designate virtualGateway membership",
			fields: fields{
				vgMembershipDesignatorDesignate: func(ctx context.Context, obj metav1.Object) (*appmesh.VirtualGateway, error) {
					return &appmesh.VirtualGateway{
						ObjectMeta: metav1.ObjectMeta{
							Name:      "my-vg",
							Namespace: "gateway-ns",
							UID:       "408d3036-7dec-11ea-b156-0e30aabe1ca8",
						},
					}, nil
				},
			},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			want: &appmesh.GatewayRoute{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "awesome-ns",
					Name:      "my-gr",
				},
				Spec: appmesh.GatewayRouteSpec{
					VirtualGatewayRef: &appmesh.VirtualGatewayReference{
						Name:      "my-vg",
						Namespace: aws.String("gateway-ns"),
						UID:       "408d3036-7dec-11ea-b156-0e30aabe1ca8",
					},
				},
			},
		},
		{
			name: "failed to designate virtualGateway membership",
			fields: fields{
				vgMembershipDesignatorDesignate: func(ctx context.Context, obj metav1.Object) (*appmesh.VirtualGateway, error) {
					return nil, errors.New("oops, some error happened")
				},
			},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{},
				},
			},
			wantErr: errors.New("oops, some error happened"),
		},
		{
			name:   "virtualGatewayRef already specified",
			fields: fields{},
			args: args{
				gr: &appmesh.GatewayRoute{
					ObjectMeta: metav1.ObjectMeta{
						Namespace: "awesome-ns",
						Name:      "my-gr",
					},
					Spec: appmesh.GatewayRouteSpec{
						VirtualGatewayRef: &appmesh.VirtualGatewayReference{
							Name:      "my-vg",
							Namespace: aws.String("gateway-ns"),
							UID:       "408d3036-7dec-11ea-b156-0e30aabe1ca8",
						},
					},
				},
			},
			wantErr: errors.New("GatewayRoute create may not specify read-only field: spec.virtualGatewayRef"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := context.Background()
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()
			designator := mock_virtualgateway.NewMockMembershipDesignator(ctrl)
			if tt.fields.vgMembershipDesignatorDesignate != nil {
				designator.EXPECT().DesignateForGatewayRoute(gomock.Any(), gomock.Any()).DoAndReturn(tt.fields.vgMembershipDesignatorDesignate)
			}

			m := &gatewayRouteMutator{
				meshMembershipDesignator:           nil,
				virtualGatewayMembershipDesignator: designator,
			}
			_, err := m.designateVirtualGatewayMembership(ctx, tt.args.gr)

			if tt.wantErr != nil {
				assert.EqualError(t, err, tt.wantErr.Error())
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.want, tt.args.gr)
			}
		})
	}
}
