github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/okta_test.go (about)

     1  /*
     2  Copyright 2023 Gravitational, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package types
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/gravitational/trace"
    25  	"github.com/stretchr/testify/require"
    26  
    27  	"github.com/gravitational/teleport/api/constants"
    28  )
    29  
    30  func TestOktaAssignments_SetStatus(t *testing.T) {
    31  	tests := []struct {
    32  		startStatus string
    33  		nextStatus  string
    34  		invalid     bool
    35  	}{
    36  
    37  		// PENDING transitions
    38  		{startStatus: constants.OktaAssignmentStatusPending, nextStatus: constants.OktaAssignmentStatusPending, invalid: true},
    39  		{startStatus: constants.OktaAssignmentStatusPending, nextStatus: constants.OktaAssignmentStatusProcessing},
    40  		{startStatus: constants.OktaAssignmentStatusPending, nextStatus: constants.OktaAssignmentStatusSuccessful, invalid: true},
    41  		{startStatus: constants.OktaAssignmentStatusPending, nextStatus: constants.OktaAssignmentStatusFailed, invalid: true},
    42  
    43  		// PROCESSING transitions
    44  		{startStatus: constants.OktaAssignmentStatusProcessing, nextStatus: constants.OktaAssignmentStatusPending, invalid: true},
    45  		{startStatus: constants.OktaAssignmentStatusProcessing, nextStatus: constants.OktaAssignmentStatusProcessing},
    46  		{startStatus: constants.OktaAssignmentStatusProcessing, nextStatus: constants.OktaAssignmentStatusSuccessful},
    47  		{startStatus: constants.OktaAssignmentStatusProcessing, nextStatus: constants.OktaAssignmentStatusFailed},
    48  
    49  		// SUCCESSFUL transitions
    50  		{startStatus: constants.OktaAssignmentStatusSuccessful, nextStatus: constants.OktaAssignmentStatusPending, invalid: true},
    51  		{startStatus: constants.OktaAssignmentStatusSuccessful, nextStatus: constants.OktaAssignmentStatusProcessing},
    52  		{startStatus: constants.OktaAssignmentStatusSuccessful, nextStatus: constants.OktaAssignmentStatusSuccessful, invalid: true},
    53  		{startStatus: constants.OktaAssignmentStatusSuccessful, nextStatus: constants.OktaAssignmentStatusFailed, invalid: true},
    54  
    55  		// FAILED transitions
    56  		{startStatus: constants.OktaAssignmentStatusFailed, nextStatus: constants.OktaAssignmentStatusPending, invalid: true},
    57  		{startStatus: constants.OktaAssignmentStatusFailed, nextStatus: constants.OktaAssignmentStatusProcessing},
    58  		{startStatus: constants.OktaAssignmentStatusFailed, nextStatus: constants.OktaAssignmentStatusSuccessful, invalid: true},
    59  		{startStatus: constants.OktaAssignmentStatusFailed, nextStatus: constants.OktaAssignmentStatusFailed, invalid: true},
    60  
    61  		// UNKNOWN transitions
    62  		{startStatus: constants.OktaAssignmentStatusUnknown, nextStatus: constants.OktaAssignmentStatusPending},
    63  		{startStatus: constants.OktaAssignmentStatusUnknown, nextStatus: constants.OktaAssignmentStatusProcessing},
    64  		{startStatus: constants.OktaAssignmentStatusUnknown, nextStatus: constants.OktaAssignmentStatusSuccessful},
    65  		{startStatus: constants.OktaAssignmentStatusUnknown, nextStatus: constants.OktaAssignmentStatusFailed},
    66  	}
    67  
    68  	for _, test := range tests {
    69  		t.Run(fmt.Sprintf("%s -> %s", test.startStatus, test.nextStatus), func(t *testing.T) {
    70  			var errAssertionFunc require.ErrorAssertionFunc
    71  			if test.invalid {
    72  				errAssertionFunc = invalidTransition(test.startStatus, test.nextStatus)
    73  			} else {
    74  				errAssertionFunc = require.NoError
    75  			}
    76  
    77  			assignment := newOktaAssignment(t, test.startStatus)
    78  			errAssertionFunc(t, assignment.SetStatus(test.nextStatus))
    79  		})
    80  	}
    81  }
    82  
    83  func TestOktAssignmentIsEqual(t *testing.T) {
    84  	newAssignment := func(changeFns ...func(*OktaAssignmentV1)) *OktaAssignmentV1 {
    85  		assignment := &OktaAssignmentV1{
    86  			ResourceHeader: ResourceHeader{
    87  				Kind:    KindOktaAssignment,
    88  				Version: V1,
    89  				Metadata: Metadata{
    90  					Name: "name",
    91  				},
    92  			},
    93  			Spec: OktaAssignmentSpecV1{
    94  				User: "user",
    95  				Targets: []*OktaAssignmentTargetV1{
    96  					{Id: "1", Type: OktaAssignmentTargetV1_APPLICATION},
    97  					{Id: "2", Type: OktaAssignmentTargetV1_GROUP},
    98  				},
    99  				CleanupTime:    time.Time{},
   100  				Status:         OktaAssignmentSpecV1_PENDING,
   101  				LastTransition: time.Time{},
   102  				Finalized:      true,
   103  			},
   104  		}
   105  		require.NoError(t, assignment.CheckAndSetDefaults())
   106  
   107  		for _, fn := range changeFns {
   108  			fn(assignment)
   109  		}
   110  
   111  		return assignment
   112  	}
   113  	tests := []struct {
   114  		name     string
   115  		o1       *OktaAssignmentV1
   116  		o2       *OktaAssignmentV1
   117  		expected bool
   118  	}{
   119  		{
   120  			name:     "empty equals",
   121  			o1:       &OktaAssignmentV1{},
   122  			o2:       &OktaAssignmentV1{},
   123  			expected: true,
   124  		},
   125  		{
   126  			name:     "nil equals",
   127  			o1:       nil,
   128  			o2:       (*OktaAssignmentV1)(nil),
   129  			expected: true,
   130  		},
   131  		{
   132  			name:     "one is nil",
   133  			o1:       &OktaAssignmentV1{},
   134  			o2:       (*OktaAssignmentV1)(nil),
   135  			expected: false,
   136  		},
   137  		{
   138  			name:     "populated equals",
   139  			o1:       newAssignment(),
   140  			o2:       newAssignment(),
   141  			expected: true,
   142  		},
   143  		{
   144  			name: "resource header is different",
   145  			o1:   newAssignment(),
   146  			o2: newAssignment(func(o *OktaAssignmentV1) {
   147  				o.ResourceHeader.Kind = "different-kind"
   148  			}),
   149  			expected: false,
   150  		},
   151  		{
   152  			name: "user is different",
   153  			o1:   newAssignment(),
   154  			o2: newAssignment(func(o *OktaAssignmentV1) {
   155  				o.Spec.User = "different-user"
   156  			}),
   157  			expected: false,
   158  		},
   159  		{
   160  			name: "targets different id",
   161  			o1:   newAssignment(),
   162  			o2: newAssignment(func(o *OktaAssignmentV1) {
   163  				o.Spec.Targets = []*OktaAssignmentTargetV1{
   164  					{Id: "2", Type: OktaAssignmentTargetV1_APPLICATION},
   165  					{Id: "2", Type: OktaAssignmentTargetV1_GROUP},
   166  				}
   167  			}),
   168  			expected: false,
   169  		},
   170  		{
   171  			name: "targets different type",
   172  			o1:   newAssignment(),
   173  			o2: newAssignment(func(o *OktaAssignmentV1) {
   174  				o.Spec.Targets = []*OktaAssignmentTargetV1{
   175  					{Id: "1", Type: OktaAssignmentTargetV1_GROUP},
   176  					{Id: "2", Type: OktaAssignmentTargetV1_GROUP},
   177  				}
   178  			}),
   179  			expected: false,
   180  		},
   181  		{
   182  			name: "targets different sizes",
   183  			o1:   newAssignment(),
   184  			o2: newAssignment(func(o *OktaAssignmentV1) {
   185  				o.Spec.Targets = []*OktaAssignmentTargetV1{
   186  					{Id: "1", Type: OktaAssignmentTargetV1_APPLICATION},
   187  				}
   188  			}),
   189  			expected: false,
   190  		},
   191  		{
   192  			name: "targets both nil",
   193  			o1: newAssignment(func(o *OktaAssignmentV1) {
   194  				o.Spec.Targets = nil
   195  			}),
   196  			o2: newAssignment(func(o *OktaAssignmentV1) {
   197  				o.Spec.Targets = nil
   198  			}),
   199  			expected: true,
   200  		},
   201  		{
   202  			name: "targets o1 is nil",
   203  			o1: newAssignment(func(o *OktaAssignmentV1) {
   204  				o.Spec.Targets = nil
   205  			}),
   206  			o2:       newAssignment(),
   207  			expected: false,
   208  		},
   209  		{
   210  			name: "targets o2 is nil",
   211  			o1:   newAssignment(),
   212  			o2: newAssignment(func(o *OktaAssignmentV1) {
   213  				o.Spec.Targets = nil
   214  			}),
   215  			expected: false,
   216  		},
   217  		{
   218  			name: "cleanup time is different",
   219  			o1:   newAssignment(),
   220  			o2: newAssignment(func(o *OktaAssignmentV1) {
   221  				o.Spec.CleanupTime = time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC)
   222  			}),
   223  			expected: false,
   224  		},
   225  		{
   226  			name: "status is different",
   227  			o1:   newAssignment(),
   228  			o2: newAssignment(func(o *OktaAssignmentV1) {
   229  				o.Spec.Status = OktaAssignmentSpecV1_PROCESSING
   230  			}),
   231  			expected: false,
   232  		},
   233  		{
   234  			name: "last transition is different",
   235  			o1:   newAssignment(),
   236  			o2: newAssignment(func(o *OktaAssignmentV1) {
   237  				o.Spec.CleanupTime = time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC)
   238  			}),
   239  			expected: false,
   240  		},
   241  		{
   242  			name: "finalized is different",
   243  			o1:   newAssignment(),
   244  			o2: newAssignment(func(o *OktaAssignmentV1) {
   245  				o.Spec.Finalized = false
   246  			}),
   247  			expected: false,
   248  		},
   249  	}
   250  
   251  	for _, test := range tests {
   252  		t.Run(test.name, func(t *testing.T) {
   253  			require.Equal(t, test.expected, test.o1.IsEqual(test.o2))
   254  		})
   255  	}
   256  }
   257  
   258  func newOktaAssignment(t *testing.T, status string) OktaAssignment {
   259  	assignment := &OktaAssignmentV1{}
   260  
   261  	require.NoError(t, assignment.SetStatus(status))
   262  	return assignment
   263  }
   264  
   265  func invalidTransition(startStatus, nextStatus string) require.ErrorAssertionFunc {
   266  	return func(t require.TestingT, err error, _ ...interface{}) {
   267  		require.ErrorIs(t, trace.BadParameter("invalid transition: %s -> %s", startStatus, nextStatus), err)
   268  	}
   269  }