package amocrm_test import ( "bytes" "errors" "fmt" "net/http" "net/url" "testing" "github.com/labstack/echo" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "penahub.gitlab.yandexcloud.net/pena-services/pena-social-auth/internal/controller/amocrm" "penahub.gitlab.yandexcloud.net/pena-services/pena-social-auth/internal/controller/amocrm/mocks" "penahub.gitlab.yandexcloud.net/pena-services/pena-social-auth/internal/models" "penahub.gitlab.yandexcloud.net/pena-services/pena-social-auth/pkg/json" "penahub.gitlab.yandexcloud.net/pena-services/pena-social-auth/pkg/testifyhelper" ) func TestAmocrmCallback(t *testing.T) { code := "testCode" accessToken := "accessttttoken" testifyHelper := testifyhelper.NewEchoTestifyHelper() tokens := models.Tokens{ AccessToken: "access-token", RefreshToken: "refresh-token", } t.Run("Неверный state", func(t *testing.T) { oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), OAuthService: oauthService, }) preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, Headers: map[string]string{echo.HeaderContentType: echo.MIMEApplicationJSON}, QueryParams: map[string]string{ "state": "invalid_state", "code": code, }, }) oauthService.EXPECT().ValidateState("invalid_state").Return(false).Once() assert.NoError(t, amocrmAuthController.Callback(preparedRequest.EchoContext)) assert.Equal(t, http.StatusBadRequest, preparedRequest.Recorder.Code) }) t.Run("Сервис вернул ошибку (accessToken отсутствует)", func(t *testing.T) { amocrmService := mocks.NewAmocrmService(t) oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), AmocrmService: amocrmService, OAuthService: oauthService, }) preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, Headers: map[string]string{echo.HeaderContentType: echo.MIMEApplicationJSON}, QueryParams: map[string]string{ "state": "random_state", "code": code, }, }) oauthService.EXPECT().ValidateState("random_state").Return(true).Once() amocrmService.EXPECT().Auth(mock.Anything, code).Return(nil, errors.New("")).Once() assert.NoError(t, amocrmAuthController.Callback(preparedRequest.EchoContext)) assert.Equal(t, http.StatusInternalServerError, preparedRequest.Recorder.Code) }) t.Run("Сервис вернул ошибку (accessToken имеется)", func(t *testing.T) { amocrmService := mocks.NewAmocrmService(t) oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), AmocrmService: amocrmService, OAuthService: oauthService, }) preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, Headers: map[string]string{echo.HeaderContentType: echo.MIMEApplicationJSON}, QueryParams: map[string]string{ "state": "state", "code": code, "accessToken": accessToken, }, }) oauthService.EXPECT().ValidateState("state").Return(true).Once() amocrmService.AssertNotCalled(t, "Auth") amocrmService.EXPECT().Link(mock.Anything, code, accessToken).Return(false, errors.New("")).Once() assert.NoError(t, amocrmAuthController.Callback(preparedRequest.EchoContext)) assert.Equal(t, http.StatusInternalServerError, preparedRequest.Recorder.Code) }) t.Run("Сервис успешно отработал (accessToken отсутствует)", func(t *testing.T) { amocrmService := mocks.NewAmocrmService(t) oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), AmocrmService: amocrmService, OAuthService: oauthService, }) jsonBuffer, err := json.EncodeBuffer(tokens) if err != nil { t.Errorf("failed to encode json tokens: %v", err) } preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, Body: bytes.NewReader(jsonBuffer.Bytes()), Headers: map[string]string{echo.HeaderContentType: echo.MIMEApplicationJSON}, QueryParams: map[string]string{ "state": "some_state", "code": code, }, }) oauthService.EXPECT().ValidateState("some_state").Return(true).Once() amocrmService.EXPECT().Auth(mock.Anything, code).Return(&tokens, nil).Once() assert.NoError(t, amocrmAuthController.Callback(preparedRequest.EchoContext)) assert.Equal(t, http.StatusOK, preparedRequest.Recorder.Code) }) t.Run("Сервис успешно отработал (accessToken имеется)", func(t *testing.T) { amocrmService := mocks.NewAmocrmService(t) oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), AmocrmService: amocrmService, OAuthService: oauthService, }) jsonBuffer, err := json.EncodeBuffer(tokens) if err != nil { t.Errorf("failed to encode json tokens: %v", err) } preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, Body: bytes.NewReader(jsonBuffer.Bytes()), Headers: map[string]string{echo.HeaderContentType: echo.MIMEApplicationJSON}, QueryParams: map[string]string{ "state": "login_state", "code": code, "accessToken": accessToken, }, }) oauthService.EXPECT().ValidateState("login_state").Return(true).Once() amocrmService.AssertNotCalled(t, "Auth") amocrmService.EXPECT().Link(mock.Anything, code, accessToken).Return(true, nil).Once() assert.NoError(t, amocrmAuthController.Callback(preparedRequest.EchoContext)) assert.Equal(t, http.StatusOK, preparedRequest.Recorder.Code) }) } func TestAmocrmGenerateAuthURL(t *testing.T) { testifyHelper := testifyhelper.NewEchoTestifyHelper() t.Run("Успешная генерация ссылки авторизации", func(t *testing.T) { oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), OAuthService: oauthService, }) preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, }) url := url.URL{ Scheme: "https", Host: "www.amocrm.ru", Path: "/oauth", RawQuery: "access_type=offline&client_id=&response_type=code&state=555", } oauthService.EXPECT().GenerateAuthURL().Return(url.String()).Once() assert.NoError(t, amocrmAuthController.GenerateAuthURL(preparedRequest.EchoContext)) unmarsled, err := json.Unmarshal[models.GenerateURLResponse](preparedRequest.Recorder.Body.Bytes()) assert.NoError(t, err) assert.Equal(t, http.StatusOK, preparedRequest.Recorder.Code) assert.EqualValues(t, url.String(), unmarsled.URL) }) } func TestAmocrmRedirectAuthURL(t *testing.T) { testifyHelper := testifyhelper.NewEchoTestifyHelper() t.Run("Успешная генерация ссылки авторизации", func(t *testing.T) { oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), OAuthService: oauthService, }) preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, }) url := url.URL{ Scheme: "https", Host: "www.amocrm.ru", Path: "/oauth", RawQuery: "access_type=offline&client_id=&response_type=code&state=555", } oauthService.EXPECT().GenerateAuthURL().Return(url.String()).Once() assert.NoError(t, amocrmAuthController.RedirectAuthURL(preparedRequest.EchoContext)) assert.Equal(t, http.StatusTemporaryRedirect, preparedRequest.Recorder.Code) result := preparedRequest.Recorder.Result() if result != nil { defer result.Body.Close() } if isNotNil := assert.NotNil(t, result); isNotNil { redirectURL, err := result.Location() assert.NoError(t, err) assert.Equal(t, &url, redirectURL) } }) } func TestAmocrmRedirectLinkAccountURL(t *testing.T) { testifyHelper := testifyhelper.NewEchoTestifyHelper() accessToken := "access-tokenasg" redirectURL := url.URL{ Scheme: "https", Host: "www.amocrm.ru", Path: "/oauth", RawQuery: fmt.Sprintf( "accessToken=%s&access_type=offline&client_id=&response_type=code&state=555", accessToken, ), } t.Run("Успешная генерация ссылки авторизации с токеном доступа", func(t *testing.T) { oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), OAuthService: oauthService, }) preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, QueryParams: map[string]string{"accessToken": accessToken}, }) oauthService.EXPECT().GenerateLinkURL(accessToken).Return(redirectURL.String()).Once() assert.NoError(t, amocrmAuthController.RedirectLinkAccountURL(preparedRequest.EchoContext)) assert.Equal(t, http.StatusTemporaryRedirect, preparedRequest.Recorder.Code) result := preparedRequest.Recorder.Result() if result != nil { defer result.Body.Close() } if isNotNil := assert.NotNil(t, result); isNotNil { redirectURL, err := result.Location() assert.NoError(t, err) assert.Equal(t, redirectURL, redirectURL) } }) } func TestAmocrmGenerateLinkAccountURL(t *testing.T) { testifyHelper := testifyhelper.NewEchoTestifyHelper() accessToken := "access-token" redirectURL := url.URL{ Scheme: "https", Host: "www.amocrm.ru", Path: "/oauth", RawQuery: fmt.Sprintf( "accessToken=%s&access_type=offline&client_id=&response_type=code&state=555", accessToken, ), } t.Run("Успешная генерация ссылки авторизации с токеном доступа", func(t *testing.T) { oauthService := mocks.NewOauthService(t) amocrmAuthController := amocrm.New(&amocrm.Deps{ Logger: logrus.New(), OAuthService: oauthService, }) preparedRequest := testifyHelper.PrepareRequest(testifyhelper.RequestConfiguration{ Method: http.MethodGet, QueryParams: map[string]string{"accessToken": accessToken}, }) oauthService.EXPECT().GenerateLinkURL(accessToken).Return(redirectURL.String()).Once() assert.NoError(t, amocrmAuthController.GenerateLinkAccountURL(preparedRequest.EchoContext)) assert.Equal(t, http.StatusOK, preparedRequest.Recorder.Code) unmarsled, err := json.Unmarshal[models.GenerateURLResponse](preparedRequest.Recorder.Body.Bytes()) assert.NoError(t, err) assert.Equal(t, http.StatusOK, preparedRequest.Recorder.Code) assert.EqualValues(t, redirectURL.String(), unmarsled.URL) }) }