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  }