github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/process/update/manager_test.go (about) 1 package update_test 2 3 import ( 4 "context" 5 "sync" 6 "testing" 7 "time" 8 9 "github.com/kyma-project/kyma-environment-broker/internal/process/update" 10 11 "github.com/kyma-project/kyma-environment-broker/internal/fixture" 12 "github.com/kyma-project/kyma-environment-broker/internal/process" 13 "github.com/pivotal-cf/brokerapi/v8/domain" 14 "k8s.io/apimachinery/pkg/util/wait" 15 16 "github.com/kyma-project/kyma-environment-broker/internal" 17 "github.com/kyma-project/kyma-environment-broker/internal/event" 18 "github.com/kyma-project/kyma-environment-broker/internal/storage" 19 "github.com/sirupsen/logrus" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 func always(operation internal.UpdatingOperation) bool { 24 return true 25 } 26 27 func TestHappyPath(t *testing.T) { 28 // given 29 const opID = "op-0001234" 30 operation := FixUpdatingOperation("op-0001234") 31 mgr, operationStorage, eventCollector := SetupStagedManager(operation) 32 mgr.AddStep("stage-1", &testingStep{name: "first", eventPublisher: eventCollector}, always) 33 mgr.AddStep("stage-1", &testingStep{name: "second", eventPublisher: eventCollector}, always) 34 mgr.AddStep("stage-1", &testingStep{name: "third", eventPublisher: eventCollector}, always) 35 mgr.AddStep("stage-2", &testingStep{name: "first-2", eventPublisher: eventCollector}, always) 36 37 // when 38 mgr.Execute(operation.ID) 39 40 // then 41 eventCollector.AssertProcessedSteps(t, []string{"first", "second", "third", "first-2"}) 42 op, _ := operationStorage.GetUpdatingOperationByID(operation.ID) 43 assert.True(t, op.IsStageFinished("stage-1")) 44 assert.True(t, op.IsStageFinished("stage-2")) 45 } 46 47 func TestWithRetry(t *testing.T) { 48 // given 49 const opID = "op-0001234" 50 operation := FixUpdatingOperation("op-0001234") 51 mgr, operationStorage, eventCollector := SetupStagedManager(operation) 52 mgr.AddStep("stage-1", &testingStep{name: "first", eventPublisher: eventCollector}, always) 53 mgr.AddStep("stage-1", &testingStep{name: "second", eventPublisher: eventCollector}, always) 54 mgr.AddStep("stage-1", &testingStep{name: "third", eventPublisher: eventCollector}, always) 55 mgr.AddStep("stage-2", &onceRetryingStep{name: "first-2", eventPublisher: eventCollector}, always) 56 mgr.AddStep("stage-2", &testingStep{name: "second-2", eventPublisher: eventCollector}, always) 57 58 // when 59 retry, _ := mgr.Execute(operation.ID) 60 61 // then 62 assert.Zero(t, retry) 63 eventCollector.AssertProcessedSteps(t, []string{"first", "second", "third", "first-2", "first-2", "second-2"}) 64 op, _ := operationStorage.GetUpdatingOperationByID(operation.ID) 65 assert.True(t, op.IsStageFinished("stage-1")) 66 assert.True(t, op.IsStageFinished("stage-2")) 67 } 68 69 func TestSkipFinishedStage(t *testing.T) { 70 // given 71 operation := FixUpdatingOperation("op-0001234") 72 operation.FinishStage("stage-1") 73 74 mgr, operationStorage, eventCollector := SetupStagedManager(operation) 75 mgr.AddStep("stage-1", &testingStep{name: "first", eventPublisher: eventCollector}, always) 76 mgr.AddStep("stage-1", &testingStep{name: "second", eventPublisher: eventCollector}, always) 77 mgr.AddStep("stage-1", &testingStep{name: "third", eventPublisher: eventCollector}, always) 78 mgr.AddStep("stage-2", &testingStep{name: "first-2", eventPublisher: eventCollector}, always) 79 80 // when 81 retry, _ := mgr.Execute(operation.ID) 82 83 // then 84 assert.Zero(t, retry) 85 eventCollector.WaitForEvents(t, 1) 86 op, _ := operationStorage.GetUpdatingOperationByID(operation.ID) 87 assert.True(t, op.IsStageFinished("stage-1")) 88 assert.True(t, op.IsStageFinished("stage-2")) 89 } 90 91 func SetupStagedManager(op internal.UpdatingOperation) (*update.Manager, storage.Operations, *CollectingEventHandler) { 92 memoryStorage := storage.NewMemoryStorage() 93 memoryStorage.Operations().InsertUpdatingOperation(op) 94 95 eventCollector := &CollectingEventHandler{} 96 l := logrus.New() 97 l.SetLevel(logrus.DebugLevel) 98 mgr := update.NewManager(memoryStorage.Operations(), eventCollector, 3*time.Second, l) 99 mgr.SpeedUp(100000) 100 mgr.DefineStages([]string{"stage-1", "stage-2"}) 101 102 return mgr, memoryStorage.Operations(), eventCollector 103 } 104 105 type testingStep struct { 106 name string 107 eventPublisher event.Publisher 108 } 109 110 func (s *testingStep) Name() string { 111 return s.name 112 } 113 func (s *testingStep) Run(operation internal.UpdatingOperation, logger logrus.FieldLogger) (internal.UpdatingOperation, time.Duration, error) { 114 logger.Infof("Running") 115 s.eventPublisher.Publish(context.Background(), s.name) 116 return operation, 0, nil 117 } 118 119 type onceRetryingStep struct { 120 name string 121 processed bool 122 eventPublisher event.Publisher 123 } 124 125 func (s *onceRetryingStep) Name() string { 126 return s.name 127 } 128 func (s *onceRetryingStep) Run(operation internal.UpdatingOperation, logger logrus.FieldLogger) (internal.UpdatingOperation, time.Duration, error) { 129 s.eventPublisher.Publish(context.Background(), s.name) 130 if !s.processed { 131 s.processed = true 132 return operation, time.Millisecond, nil 133 } 134 logger.Infof("Running") 135 return operation, 0, nil 136 } 137 138 func FixUpdatingOperation(ID string) internal.UpdatingOperation { 139 operation := fixture.FixUpdatingOperation(ID, "fea2c1a1-139d-43f6-910a-a618828a79d5") 140 operation.FinishedStages = make([]string, 0) 141 operation.State = domain.InProgress 142 operation.Description = "" 143 return operation 144 } 145 146 type CollectingEventHandler struct { 147 mu sync.Mutex 148 StepsProcessed []string // collects events from the Manager 149 stepsExecuted []string // collects events from testing steps 150 } 151 152 func (h *CollectingEventHandler) OnStepExecuted(_ context.Context, ev interface{}) error { 153 h.mu.Lock() 154 defer h.mu.Unlock() 155 h.stepsExecuted = append(h.stepsExecuted, ev.(string)) 156 return nil 157 } 158 159 func (h *CollectingEventHandler) OnStepProcessed(_ context.Context, ev interface{}) error { 160 h.mu.Lock() 161 defer h.mu.Unlock() 162 h.StepsProcessed = append(h.StepsProcessed, ev.(process.UpdatingStepProcessed).StepName) 163 return nil 164 } 165 166 func (h *CollectingEventHandler) Publish(ctx context.Context, ev interface{}) { 167 switch ev.(type) { 168 case process.UpdatingStepProcessed: 169 h.OnStepProcessed(ctx, ev) 170 case string: 171 h.OnStepExecuted(ctx, ev) 172 } 173 } 174 175 func (h *CollectingEventHandler) WaitForEvents(t *testing.T, count int) { 176 assert.NoError(t, wait.PollImmediate(time.Millisecond, time.Second, func() (bool, error) { 177 return len(h.StepsProcessed) == count, nil 178 })) 179 } 180 181 func (h *CollectingEventHandler) AssertProcessedSteps(t *testing.T, stepNames []string) { 182 h.WaitForEvents(t, len(stepNames)) 183 h.mu.Lock() 184 defer h.mu.Unlock() 185 186 for i, stepName := range stepNames { 187 processed := h.StepsProcessed[i] 188 executed := h.stepsExecuted[i] 189 assert.Equal(t, stepName, processed) 190 assert.Equal(t, stepName, executed) 191 } 192 assert.Len(t, h.StepsProcessed, len(stepNames)) 193 }