diff --git a/apptrust/commands/flags.go b/apptrust/commands/flags.go index f6fd02d..49d6a86 100644 --- a/apptrust/commands/flags.go +++ b/apptrust/commands/flags.go @@ -133,6 +133,7 @@ var commandFlags = map[string][]string{ user, accessToken, serverId, + SyncFlag, }, VersionUpdate: { url, diff --git a/apptrust/commands/version/rollback_app_version_cmd.go b/apptrust/commands/version/rollback_app_version_cmd.go index a58f31d..43859f8 100644 --- a/apptrust/commands/version/rollback_app_version_cmd.go +++ b/apptrust/commands/version/rollback_app_version_cmd.go @@ -23,6 +23,7 @@ type rollbackAppVersionCommand struct { version string requestPayload *model.RollbackAppVersionRequest fromStage string + sync bool } func (rv *rollbackAppVersionCommand) Run() error { @@ -31,7 +32,7 @@ func (rv *rollbackAppVersionCommand) Run() error { return err } - return rv.versionService.RollbackAppVersion(ctx, rv.applicationKey, rv.version, rv.requestPayload) + return rv.versionService.RollbackAppVersion(ctx, rv.applicationKey, rv.version, rv.requestPayload, rv.sync) } func (rv *rollbackAppVersionCommand) ServerDetails() (*coreConfig.ServerDetails, error) { @@ -51,6 +52,8 @@ func (rv *rollbackAppVersionCommand) prepareAndRunCommand(ctx *components.Contex rv.version = ctx.Arguments[1] rv.fromStage = ctx.Arguments[2] + rv.sync = ctx.GetBoolTFlagValue(commands.SyncFlag) + serverDetails, err := utils.ServerDetailsByFlags(ctx) if err != nil { return err diff --git a/apptrust/commands/version/rollback_app_version_cmd_test.go b/apptrust/commands/version/rollback_app_version_cmd_test.go index 2986a77..363e72a 100644 --- a/apptrust/commands/version/rollback_app_version_cmd_test.go +++ b/apptrust/commands/version/rollback_app_version_cmd_test.go @@ -13,57 +13,78 @@ import ( ) func TestRollbackAppVersionCommand_Run(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - serverDetails := &config.ServerDetails{Url: "https://example.com"} - applicationKey := "video-encoder" - version := "1.5.0" - requestPayload := &model.RollbackAppVersionRequest{ - FromStage: "qa", + tests := []struct { + name string + applicationKey string + version string + fromStage string + sync bool + mockError error + expectedError bool + }{ + { + name: "successful rollback with sync=false", + applicationKey: "video-encoder", + version: "1.5.0", + fromStage: "qa", + sync: false, + mockError: nil, + expectedError: false, + }, + { + name: "successful rollback with sync=true", + applicationKey: "test-app", + version: "1.0.0", + fromStage: "qa", + sync: true, + mockError: nil, + expectedError: false, + }, + { + name: "failed rollback", + applicationKey: "video-encoder", + version: "1.5.0", + fromStage: "qa", + sync: false, + mockError: errors.New("rollback service error occurred"), + expectedError: true, + }, } - mockVersionService := mockversions.NewMockVersionService(ctrl) - mockVersionService.EXPECT().RollbackAppVersion(gomock.Any(), applicationKey, version, requestPayload). - Return(nil).Times(1) - - cmd := &rollbackAppVersionCommand{ - versionService: mockVersionService, - serverDetails: serverDetails, - applicationKey: applicationKey, - version: version, - requestPayload: requestPayload, - } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() - err := cmd.Run() - assert.NoError(t, err) -} + serverDetails := &config.ServerDetails{Url: "https://example.com"} + requestPayload := &model.RollbackAppVersionRequest{ + FromStage: tt.fromStage, + } -func TestRollbackAppVersionCommand_Run_Error(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() + mockVersionService := mockversions.NewMockVersionService(ctrl) + mockVersionService.EXPECT().RollbackAppVersion(gomock.Any(), tt.applicationKey, tt.version, requestPayload, tt.sync). + Return(tt.mockError).Times(1) - serverDetails := &config.ServerDetails{Url: "https://example.com"} - applicationKey := "video-encoder" - version := "1.5.0" - requestPayload := &model.RollbackAppVersionRequest{ - FromStage: "qa", - } - expectedError := errors.New("rollback service error occurred") + cmd := &rollbackAppVersionCommand{ + versionService: mockVersionService, + serverDetails: serverDetails, + applicationKey: tt.applicationKey, + version: tt.version, + requestPayload: requestPayload, + fromStage: tt.fromStage, + sync: tt.sync, + } - mockVersionService := mockversions.NewMockVersionService(ctrl) - mockVersionService.EXPECT().RollbackAppVersion(gomock.Any(), applicationKey, version, requestPayload). - Return(expectedError).Times(1) + err := cmd.Run() - cmd := &rollbackAppVersionCommand{ - versionService: mockVersionService, - serverDetails: serverDetails, - applicationKey: applicationKey, - version: version, - requestPayload: requestPayload, + if tt.expectedError { + assert.Error(t, err) + if tt.mockError != nil { + assert.Contains(t, err.Error(), tt.mockError.Error()) + } + } else { + assert.NoError(t, err) + } + }) } - - err := cmd.Run() - assert.Error(t, err) - assert.Contains(t, err.Error(), "rollback service error occurred") } diff --git a/apptrust/service/versions/version_service.go b/apptrust/service/versions/version_service.go index c0b5a4f..97b8a38 100644 --- a/apptrust/service/versions/version_service.go +++ b/apptrust/service/versions/version_service.go @@ -17,7 +17,7 @@ type VersionService interface { CreateAppVersion(ctx service.Context, request *model.CreateAppVersionRequest) error PromoteAppVersion(ctx service.Context, applicationKey string, version string, payload *model.PromoteAppVersionRequest, sync bool) error ReleaseAppVersion(ctx service.Context, applicationKey string, version string, request *model.ReleaseAppVersionRequest, sync bool) error - RollbackAppVersion(ctx service.Context, applicationKey string, version string, request *model.RollbackAppVersionRequest) error + RollbackAppVersion(ctx service.Context, applicationKey string, version string, request *model.RollbackAppVersionRequest, sync bool) error DeleteAppVersion(ctx service.Context, applicationKey string, version string) error UpdateAppVersion(ctx service.Context, applicationKey string, version string, request *model.UpdateAppVersionRequest) error } @@ -76,19 +76,25 @@ func (vs *versionService) ReleaseAppVersion(ctx service.Context, applicationKey, return nil } -func (vs *versionService) RollbackAppVersion(ctx service.Context, applicationKey, version string, request *model.RollbackAppVersionRequest) error { +func (vs *versionService) RollbackAppVersion(ctx service.Context, applicationKey, version string, request *model.RollbackAppVersionRequest, sync bool) error { endpoint := fmt.Sprintf("/v1/applications/%s/versions/%s/rollback", applicationKey, version) - response, responseBody, err := ctx.GetHttpClient().Post(endpoint, request, map[string]string{}) + response, responseBody, err := ctx.GetHttpClient().Post(endpoint, request, map[string]string{"async": strconv.FormatBool(!sync)}) if err != nil { return err } - if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusAccepted { + // Validate status code based on sync mode + expectedStatusCode := http.StatusAccepted + if sync { + expectedStatusCode = http.StatusOK + } + + if response.StatusCode != expectedStatusCode { return fmt.Errorf("failed to rollback app version. Status code: %d. \n%s", response.StatusCode, responseBody) } - log.Output("Application version deleted successfully") + log.Output(string(responseBody)) return nil } @@ -114,7 +120,7 @@ func (vs *versionService) UpdateAppVersion(ctx service.Context, applicationKey s return err } - if response.StatusCode != http.StatusAccepted { + if response.StatusCode != http.StatusOK { return fmt.Errorf("failed to update app version. Status code: %d. \n%s", response.StatusCode, responseBody) } diff --git a/apptrust/service/versions/version_service_test.go b/apptrust/service/versions/version_service_test.go index 035e62a..7ff2221 100644 --- a/apptrust/service/versions/version_service_test.go +++ b/apptrust/service/versions/version_service_test.go @@ -314,7 +314,7 @@ func TestUpdateAppVersion(t *testing.T) { request: &model.UpdateAppVersionRequest{ Tag: "release/1.2.3", }, - mockResponse: &http.Response{StatusCode: http.StatusAccepted}, + mockResponse: &http.Response{StatusCode: http.StatusOK}, mockResponseBody: "{}", mockError: nil, expectError: false, @@ -327,7 +327,7 @@ func TestUpdateAppVersion(t *testing.T) { "status": {"rc", "validated"}, }, }, - mockResponse: &http.Response{StatusCode: http.StatusAccepted}, + mockResponse: &http.Response{StatusCode: http.StatusOK}, mockResponseBody: "{}", mockError: nil, expectError: false, @@ -338,7 +338,7 @@ func TestUpdateAppVersion(t *testing.T) { request: &model.UpdateAppVersionRequest{ DeleteProperties: []string{"legacy_param", "toBeDeleted"}, }, - mockResponse: &http.Response{StatusCode: http.StatusAccepted}, + mockResponse: &http.Response{StatusCode: http.StatusOK}, mockResponseBody: "{}", mockError: nil, expectError: false, @@ -353,7 +353,7 @@ func TestUpdateAppVersion(t *testing.T) { }, DeleteProperties: []string{"old_param"}, }, - mockResponse: &http.Response{StatusCode: http.StatusAccepted}, + mockResponse: &http.Response{StatusCode: http.StatusOK}, mockResponseBody: "{}", mockError: nil, expectError: false, @@ -422,26 +422,29 @@ func TestRollbackAppVersion(t *testing.T) { applicationKey string version string payload *model.RollbackAppVersionRequest + sync bool expectedStatus int expectedError bool }{ { - name: "successful rollback with 200", + name: "successful rollback with sync=true", applicationKey: "video-encoder", version: "1.5.0", payload: &model.RollbackAppVersionRequest{ FromStage: "qa", }, + sync: true, expectedStatus: http.StatusOK, expectedError: false, }, { - name: "successful rollback with 204", + name: "successful rollback with sync=false", applicationKey: "video-encoder", version: "1.5.0", payload: &model.RollbackAppVersionRequest{ FromStage: "prod", }, + sync: false, expectedStatus: http.StatusAccepted, expectedError: false, }, @@ -452,9 +455,32 @@ func TestRollbackAppVersion(t *testing.T) { payload: &model.RollbackAppVersionRequest{ FromStage: "nonexistent", }, + sync: true, expectedStatus: http.StatusBadRequest, expectedError: true, }, + { + name: "failed rollback - sync=true but got 202", + applicationKey: "video-encoder", + version: "1.5.0", + payload: &model.RollbackAppVersionRequest{ + FromStage: "qa", + }, + sync: true, + expectedStatus: http.StatusAccepted, + expectedError: true, + }, + { + name: "failed rollback - sync=false but got 200", + applicationKey: "video-encoder", + version: "1.5.0", + payload: &model.RollbackAppVersionRequest{ + FromStage: "prod", + }, + sync: false, + expectedStatus: http.StatusOK, + expectedError: true, + }, } for _, tt := range tests { @@ -467,11 +493,11 @@ func TestRollbackAppVersion(t *testing.T) { mockCtx.EXPECT().GetHttpClient().Return(mockClient) expectedEndpoint := "/v1/applications/" + tt.applicationKey + "/versions/" + tt.version + "/rollback" - mockClient.EXPECT().Post(expectedEndpoint, tt.payload, map[string]string{}). + mockClient.EXPECT().Post(expectedEndpoint, tt.payload, map[string]string{"async": strconv.FormatBool(!tt.sync)}). Return(&http.Response{StatusCode: tt.expectedStatus}, []byte(""), nil) service := NewVersionService() - err := service.RollbackAppVersion(mockCtx, tt.applicationKey, tt.version, tt.payload) + err := service.RollbackAppVersion(mockCtx, tt.applicationKey, tt.version, tt.payload, tt.sync) if tt.expectedError { assert.Error(t, err)