github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/process/upgrade_cluster/manager_test.go (about) 1 package upgrade_cluster 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/kyma-project/kyma-environment-broker/common/orchestration" 10 "github.com/kyma-project/kyma-environment-broker/internal" 11 "github.com/kyma-project/kyma-environment-broker/internal/storage" 12 13 "context" 14 "sync" 15 16 "github.com/kyma-project/kyma-environment-broker/internal/event" 17 "github.com/kyma-project/kyma-environment-broker/internal/process" 18 "github.com/pivotal-cf/brokerapi/v8/domain" 19 "github.com/sirupsen/logrus" 20 "github.com/stretchr/testify/assert" 21 "k8s.io/apimachinery/pkg/util/wait" 22 ) 23 24 const ( 25 operationIDSuccess = "5b954fa8-fc34-4164-96e9-49e3b6741278" 26 operationIDFailed = "69b8ee2b-5c21-4997-9070-4fd356b24c46" 27 operationIDRepeat = "ca317a1e-ddab-44d2-b2ba-7bbd9df9066f" 28 operationIDPanic = "8ffadf20-5fe6-410b-93ce-9d00088e1e17" 29 ) 30 31 func TestManager_Execute(t *testing.T) { 32 for name, tc := range map[string]struct { 33 operationID string 34 expectedError bool 35 expectedRepeat time.Duration 36 expectedDesc string 37 expectedNumberOfEvents int 38 }{ 39 "operation successful": { 40 operationID: operationIDSuccess, 41 expectedError: false, 42 expectedRepeat: time.Duration(0), 43 expectedDesc: "init one two final", 44 expectedNumberOfEvents: 4, 45 }, 46 "operation failed": { 47 operationID: operationIDFailed, 48 expectedError: true, 49 expectedNumberOfEvents: 1, 50 }, 51 "operation panicked": { 52 operationID: operationIDPanic, 53 expectedError: true, 54 expectedNumberOfEvents: 0, 55 }, 56 "operation repeated": { 57 operationID: operationIDRepeat, 58 expectedError: false, 59 expectedRepeat: time.Duration(10), 60 expectedDesc: "init", 61 expectedNumberOfEvents: 1, 62 }, 63 } { 64 t.Run(name, func(t *testing.T) { 65 // given 66 log := logrus.New() 67 memoryStorage := storage.NewMemoryStorage() 68 operations := memoryStorage.Operations() 69 err := operations.InsertUpgradeClusterOperation(fixOperation(tc.operationID)) 70 assert.NoError(t, err) 71 72 sInit := testStep{t: t, name: "init", storage: operations} 73 s1 := testStep{t: t, name: "one", storage: operations} 74 s2 := testStep{t: t, name: "two", storage: operations} 75 s3 := testStep{t: t, name: "to be skipped", storage: operations} 76 sFinal := testStep{t: t, name: "final", storage: operations} 77 78 eventBroker := event.NewPubSub(logrus.New()) 79 eventCollector := &collectingEventHandler{} 80 eventBroker.Subscribe(process.UpgradeClusterStepProcessed{}, eventCollector.OnEvent) 81 82 manager := NewManager(operations, eventBroker, log) 83 manager.InitStep(&sInit) 84 85 manager.AddStep(2, &sFinal, nil) 86 manager.AddStep(1, &s1, nil) 87 manager.AddStep(1, &s2, func(operation internal.Operation) bool { return true }) 88 manager.AddStep(1, &s3, func(operation internal.Operation) bool { return false }) 89 90 // when 91 repeat, err := manager.Execute(tc.operationID) 92 93 // then 94 if tc.expectedError { 95 assert.Error(t, err) 96 } else { 97 assert.NoError(t, err) 98 assert.Equal(t, tc.expectedRepeat, repeat) 99 100 operation, err := operations.GetOperationByID(tc.operationID) 101 assert.NoError(t, err) 102 assert.Equal(t, tc.expectedDesc, strings.Trim(operation.Description, " ")) 103 } 104 assert.NoError(t, wait.PollImmediate(20*time.Millisecond, 2*time.Second, func() (bool, error) { 105 return len(eventCollector.Events) == tc.expectedNumberOfEvents, nil 106 })) 107 }) 108 } 109 } 110 111 func fixOperation(ID string) internal.UpgradeClusterOperation { 112 return internal.UpgradeClusterOperation{ 113 Operation: internal.Operation{ 114 ID: ID, 115 State: domain.InProgress, 116 InstanceID: "fea2c1a1-139d-43f6-910a-a618828a79d5", 117 Description: "", 118 RuntimeOperation: orchestration.RuntimeOperation{}, 119 }, 120 } 121 } 122 123 type testStep struct { 124 t *testing.T 125 name string 126 storage storage.Operations 127 } 128 129 func (ts *testStep) Name() string { 130 return ts.name 131 } 132 133 func (ts *testStep) Run(operation internal.UpgradeClusterOperation, logger logrus.FieldLogger) (internal.UpgradeClusterOperation, time.Duration, error) { 134 logger.Infof("inside %s step", ts.name) 135 136 operation.Description = fmt.Sprintf("%s %s", operation.Description, ts.name) 137 updated, err := ts.storage.UpdateUpgradeClusterOperation(operation) 138 if err != nil { 139 ts.t.Error(err) 140 } 141 142 switch operation.Operation.ID { 143 case operationIDFailed: 144 return *updated, 0, fmt.Errorf("operation %s failed", operation.Operation.ID) 145 case operationIDRepeat: 146 return *updated, time.Duration(10), nil 147 case operationIDPanic: 148 panic("panic during operation") 149 default: 150 return *updated, 0, nil 151 } 152 } 153 154 type collectingEventHandler struct { 155 mu sync.Mutex 156 Events []interface{} 157 } 158 159 func (h *collectingEventHandler) OnEvent(ctx context.Context, ev interface{}) error { 160 h.mu.Lock() 161 defer h.mu.Unlock() 162 163 h.Events = append(h.Events, ev) 164 return nil 165 }