github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/process/deprovisioning/manager_test.go (about)

     1  package deprovisioning
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/kyma-project/kyma-environment-broker/internal"
    12  	"github.com/kyma-project/kyma-environment-broker/internal/event"
    13  	"github.com/kyma-project/kyma-environment-broker/internal/fixture"
    14  	"github.com/kyma-project/kyma-environment-broker/internal/process"
    15  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
    16  	mocks "github.com/kyma-project/kyma-environment-broker/internal/storage/automock"
    17  	"github.com/pivotal-cf/brokerapi/v8/domain"
    18  	"github.com/sirupsen/logrus"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/mock"
    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  	fakeInstanceID     = "fea2c1a1-139d-43f6-910a-a618828a79d5"
    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 repeated": {
    52  			operationID:            operationIDRepeat,
    53  			expectedError:          false,
    54  			expectedRepeat:         time.Duration(10),
    55  			expectedDesc:           "init",
    56  			expectedNumberOfEvents: 1,
    57  		},
    58  	} {
    59  		t.Run(name, func(t *testing.T) {
    60  			// given
    61  			log := logrus.New()
    62  			memoryStorage := storage.NewMemoryStorage()
    63  			operations := memoryStorage.Operations()
    64  			err := operations.InsertDeprovisioningOperation(fixDeprovisionOperation(tc.operationID))
    65  			assert.NoError(t, err)
    66  			err = operations.InsertOperation(fixProvisionOperation())
    67  
    68  			sInit := testStep{t: t, name: "init", storage: operations}
    69  			s1 := testStep{t: t, name: "one", storage: operations}
    70  			s2 := testStep{t: t, name: "two", storage: operations}
    71  			sFinal := testStep{t: t, name: "final", storage: operations}
    72  
    73  			eventBroker := event.NewPubSub(logrus.New())
    74  			eventCollector := &collectingEventHandler{}
    75  			eventBroker.Subscribe(process.DeprovisioningStepProcessed{}, eventCollector.OnEvent)
    76  
    77  			manager := NewManager(operations, eventBroker, log)
    78  			manager.InitStep(&sInit)
    79  
    80  			manager.AddStep(2, &sFinal)
    81  			manager.AddStep(1, &s1)
    82  			manager.AddStep(1, &s2)
    83  
    84  			// when
    85  			repeat, err := manager.Execute(tc.operationID)
    86  
    87  			// then
    88  			if tc.expectedError {
    89  				assert.Error(t, err)
    90  			} else {
    91  				assert.NoError(t, err)
    92  				assert.Equal(t, tc.expectedRepeat, repeat)
    93  
    94  				operation, err := operations.GetOperationByID(tc.operationID)
    95  				assert.NoError(t, err)
    96  				assert.Equal(t, tc.expectedDesc, strings.Trim(operation.Description, " "))
    97  			}
    98  			assert.NoError(t, wait.PollImmediate(20*time.Millisecond, 2*time.Second, func() (bool, error) {
    99  				return len(eventCollector.Events) == tc.expectedNumberOfEvents, nil
   100  			}))
   101  		})
   102  	}
   103  
   104  	t.Run("should fail operation when provisioning operation not found", func(t *testing.T) {
   105  		// given
   106  		log := logrus.New()
   107  		memoryStorage := storage.NewMemoryStorage()
   108  		operations := memoryStorage.Operations()
   109  		err := operations.InsertDeprovisioningOperation(fixDeprovisionOperation(operationIDSuccess))
   110  
   111  		assert.NoError(t, err)
   112  
   113  		eventBroker := event.NewPubSub(logrus.New())
   114  		eventCollector := &collectingEventHandler{}
   115  		eventBroker.Subscribe(process.DeprovisioningStepProcessed{}, eventCollector.OnEvent)
   116  
   117  		manager := NewManager(operations, eventBroker, log)
   118  
   119  		// when
   120  		repeat, err := manager.Execute(operationIDSuccess)
   121  		assert.Equal(t, time.Duration(0), repeat)
   122  		assert.Error(t, err)
   123  
   124  		// assert operation state as failed
   125  		operation, err := memoryStorage.Deprovisioning().
   126  			GetDeprovisioningOperationByID(operationIDSuccess)
   127  
   128  		assert.NoError(t, err)
   129  		assert.Equal(t, domain.Failed, operation.State)
   130  
   131  		assert.NoError(t, wait.PollImmediate(20*time.Millisecond, 2*time.Second, func() (bool, error) {
   132  			return len(eventCollector.Events) == 1, nil
   133  		}))
   134  	})
   135  
   136  	t.Run("should repeat operation when provisioning operation error other than not found", func(t *testing.T) {
   137  		// given
   138  		log := logrus.New()
   139  		memoryStorage := mocks.Operations{}
   140  		operation := fixDeprovisionOperation(operationIDSuccess)
   141  		memoryStorage.On("GetDeprovisioningOperationByID", operationIDSuccess).Return(&operation, nil)
   142  		memoryStorage.On("GetProvisioningOperationByInstanceID", mock.Anything).Return(nil, fmt.Errorf("Error connecting to database"))
   143  
   144  		eventBroker := event.NewPubSub(logrus.New())
   145  		eventCollector := &collectingEventHandler{}
   146  		eventBroker.Subscribe(process.DeprovisioningStepProcessed{}, eventCollector.OnEvent)
   147  
   148  		manager := NewManager(&memoryStorage, eventBroker, log)
   149  
   150  		// when
   151  		repeat, err := manager.Execute(operationIDSuccess)
   152  		assert.Equal(t, retryAfterTime, repeat)
   153  		assert.NoError(t, err)
   154  
   155  		// assert operation state as failed
   156  		assert.NoError(t, err)
   157  		// assert.True(t, dberr.IsNotFound(err))
   158  		assert.Equal(t, domain.InProgress, operation.State)
   159  
   160  		assert.NoError(t, wait.PollImmediate(20*time.Millisecond, 2*time.Second, func() (bool, error) {
   161  			return len(eventCollector.Events) == 1, nil
   162  		}))
   163  	})
   164  
   165  }
   166  
   167  func fixDeprovisionOperation(ID string) internal.DeprovisioningOperation {
   168  	deprovisioningOperation := fixture.FixDeprovisioningOperation(ID, fakeInstanceID)
   169  	deprovisioningOperation.State = domain.InProgress
   170  	deprovisioningOperation.Description = ""
   171  
   172  	return deprovisioningOperation
   173  }
   174  
   175  func fixProvisionOperation() internal.Operation {
   176  	return fixture.FixProvisioningOperation("6bc401aa-2ec4-4303-bf3f-2e04990f6d8f", fakeInstanceID)
   177  }
   178  
   179  type testStep struct {
   180  	t       *testing.T
   181  	name    string
   182  	storage storage.Operations
   183  }
   184  
   185  func (ts *testStep) Name() string {
   186  	return ts.name
   187  }
   188  
   189  func (ts *testStep) Run(operation internal.DeprovisioningOperation, logger logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) {
   190  	logger.Infof("inside %s step", ts.name)
   191  
   192  	operation.Description = fmt.Sprintf("%s %s", operation.Description, ts.name)
   193  	updated, err := ts.storage.UpdateDeprovisioningOperation(operation)
   194  	if err != nil {
   195  		ts.t.Error(err)
   196  	}
   197  
   198  	switch operation.ID {
   199  	case operationIDFailed:
   200  		return *updated, 0, fmt.Errorf("operation %s failed", operation.ID)
   201  	case operationIDRepeat:
   202  		return *updated, time.Duration(10), nil
   203  	default:
   204  		return *updated, 0, nil
   205  	}
   206  }
   207  
   208  type collectingEventHandler struct {
   209  	mu     sync.Mutex
   210  	Events []interface{}
   211  }
   212  
   213  func (h *collectingEventHandler) OnEvent(ctx context.Context, ev interface{}) error {
   214  	h.mu.Lock()
   215  	defer h.mu.Unlock()
   216  
   217  	h.Events = append(h.Events, ev)
   218  	return nil
   219  }