package tests import ( "bytes" "encoding/json" "fmt" "gitea.pena/SQuiz/common/model" "gitea.pena/SQuiz/core/internal/controllers/http_controllers/question" "gitea.pena/SQuiz/core/internal/controllers/http_controllers/quiz" "github.com/pioz/faker" "github.com/stretchr/testify/assert" "net/http" "strings" "sync" "testing" "time" ) // todo нужно перепроверить все тесты связанные с результатами и удалениями раскоментить и переписать var PublicKey = `-----BEGIN PUBLIC KEY-----MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm6980fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6BdA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y+3GyaOY536H47qyXAgMBAAE=-----END PUBLIC KEY-----` var baseURL = "http://127.0.0.1:1488" //os.Getenv("API_BASE_URL") var validToken = CreateJWT(validUserID) // validUserID var expiredToken = CreateExpiredToken(validUserID) // todo var validTokenForDelete = CreateJWT(userIDForDelete) // userIDForDelete var validAdminToken = CreateJWT(validUserID) // os.Getenv("VALID_ADMIN_JWT_TOKEN") var existingUserIDToken = CreateJWT(existingUserID) // existingUserID // Токены для операций удаления // todo var deleteAccountToken = CreateJWT(userIDForDelete) // userIDForDelete var deleteQuestionToken = CreateJWT(userIDForDelete) // userIDForDelete var deleteQuizToken = CreateJWT(userIDForDelete) // userIDForDelete var deleteResultToken = CreateJWT(userIDForDelete) // userIDForDelete var deleteLeadTargetToken = CreateJWT(userIDForDelete) // userIDForDelete var deletedAccountToken = CreateJWT(userIDForDelete) // userIDForDelete var AccountWithOutPrivilegeToken = CreateJWT(userWithoutPrivileges) // userWithoutPrivileges var notFoundAccountToken = CreateJWT("notFound-123") // todo var userIDForDelete = "user_for_delete_789" var existingUserID = "existing_user_456" var testUserID = "test_user_123" var userWithoutPrivileges = "no_privileges_user" var validUserID = "multi_privileges_user" var sqlInjectionInput = "'; DROP TABLE accounts; --" var xssInput = "" func TestGetAccount_Success(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) client := &http.Client{Timeout: 5 * time.Second} resp, err := client.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var acc model.Account err = json.NewDecoder(resp.Body).Decode(&acc) assert.NoError(t, err) assert.NotEmpty(t, acc.ID) assert.NotEmpty(t, acc.UserID) assert.IsType(t, map[string]model.ShortPrivilege{}, acc.Privileges) } func TestGetAccount_Auth(t *testing.T) { t.Run("AccountNoToken", func(t *testing.T) { resp, err := http.Get(baseURL + "/account/get") assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("AccountInvalidToken", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer invalid_token") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("AccountExpiredToken", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+expiredToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestGetAccount_NotFound(t *testing.T) { t.Run("DeletedAccount", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+notFoundAccountToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusNotFound, resp.StatusCode) }) } func TestGetAccount_Privileges(t *testing.T) { t.Run("NoPrivileges", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+AccountWithOutPrivilegeToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var acc model.Account err = json.NewDecoder(resp.Body).Decode(&acc) assert.NoError(t, err) assert.Empty(t, acc.Privileges) }) t.Run("MultiplePrivileges", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var acc model.Account err = json.NewDecoder(resp.Body).Decode(&acc) assert.NoError(t, err) assert.Greater(t, len(acc.Privileges), 1) }) } func TestAccount_Performance(t *testing.T) { t.Run("AccountResponseTime", func(t *testing.T) { start := time.Now() req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() duration := time.Since(start) assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("AccountLoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) resp, err := http.DefaultClient.Do(req) if err == nil { defer resp.Body.Close() } }() } wg.Wait() }) } // todo нужны ли? //func TestGetAccount_Security(t *testing.T) { // t.Run("XSSProtection", func(t *testing.T) { // req, err := http.NewRequest("GET", baseURL+"/account/get", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validToken) // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, "nosniff", resp.Header.Get("X-Content-Type-Options")) // assert.Equal(t, "1; mode=block", resp.Header.Get("X-XSS-Protection")) // assert.Equal(t, "DENY", resp.Header.Get("X-Frame-Options")) // }) // // t.Run("CSRFProtection", func(t *testing.T) { // req, err := http.NewRequest("GET", baseURL+"/account/get", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validToken) // req.Header.Set("X-CSRF-Token", "invalid_token") // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusForbidden, resp.StatusCode) // }) //} func TestGetAccount_BoundaryCases(t *testing.T) { t.Run("LongFieldValues", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) if userID, ok := result["user_id"].(string); ok { assert.LessOrEqual(t, len(userID), 255) } }) // todo //t.Run("UnicodeCharacters", func(t *testing.T) { // req, err := http.NewRequest("GET", baseURL+"/account/get", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validToken) // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // assert.Equal(t, "utf-8", resp.Header.Get("Content-Type")) //}) } func TestGetAccount_SpecialCases(t *testing.T) { t.Run("AccountWithoutPrivileges", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) if privileges, ok := result["privileges"].(map[string]interface{}); ok { assert.NotNil(t, privileges) } }) t.Run("MultiplePrivileges", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/get", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) if privileges, ok := result["privileges"].(map[string]interface{}); ok { assert.NotNil(t, privileges) } }) } // отсмотрено func TestCreateAccount(t *testing.T) { t.Run("Success", func(t *testing.T) { resp := createAccountRequest(t, CreateJWT(faker.String()), map[string]interface{}{ "user_id": testUserID, }) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) }) t.Run("MissingToken", func(t *testing.T) { req, err := http.NewRequest("POST", baseURL+"/account/create", nil) assert.NoError(t, err) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp := createAccountRequest(t, expiredToken, map[string]interface{}{ "user_id": "some-id", }) defer resp.Body.Close() assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp := createAccountRequest(t, expiredToken, map[string]interface{}{ "user_id": "some-id", }) defer resp.Body.Close() assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("Conflict_ExistingUserID", func(t *testing.T) { resp := createAccountRequest(t, validToken, map[string]interface{}{ "user_id": existingUserID, }) defer resp.Body.Close() assert.Equal(t, http.StatusConflict, resp.StatusCode) }) t.Run("SQLInjection", func(t *testing.T) { resp := createAccountRequest(t, CreateJWT(fmt.Sprintf("perf_test_%d", time.Now().Unix())), map[string]interface{}{ "user_id": sqlInjectionInput, }) defer resp.Body.Close() assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) }) t.Run("XSSInjection", func(t *testing.T) { resp := createAccountRequest(t, CreateJWT(fmt.Sprintf("perf_test_%d", time.Now().Unix())), map[string]interface{}{ "user_id": xssInput, }) defer resp.Body.Close() assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) }) t.Run("Performance_CreationTime", func(t *testing.T) { start := time.Now() resp := createAccountRequest(t, CreateJWT(fmt.Sprintf("perf_test_%d", time.Now().Unix())), map[string]interface{}{ "user_id": fmt.Sprintf("perf_test_%d", time.Now().Unix()), }) defer resp.Body.Close() duration := time.Since(start) assert.Less(t, duration.Milliseconds(), int64(1000)) // < 1s assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("Performance_LoadTest", func(t *testing.T) { var wg sync.WaitGroup successCount := 0 var mu sync.Mutex for i := 0; i < 50; i++ { wg.Add(1) go func(index int) { defer wg.Done() resp := createAccountRequest(t, CreateJWT(fmt.Sprintf("load_test_%d_%d", time.Now().Unix(), index)), map[string]interface{}{ "user_id": fmt.Sprintf("load_test_%d_%d", time.Now().Unix(), index), }) defer resp.Body.Close() if resp.StatusCode == http.StatusOK { mu.Lock() successCount++ mu.Unlock() } }(i) } wg.Wait() assert.Greater(t, successCount, 40) // > 80% успешных }) t.Run("BoundaryCases_LongValues", func(t *testing.T) { longUserID := strings.Repeat("a", 1000) // Очень длинный user_id resp := createAccountRequest(t, CreateJWT(longUserID), map[string]interface{}{ "user_id": longUserID, }) defer resp.Body.Close() assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) }) t.Run("BoundaryCases_UnicodeCharacters", func(t *testing.T) { unicodeUserID := "тест_пользователь_123" // Unicode символы resp := createAccountRequest(t, CreateJWT("тест_пользователь_123"), map[string]interface{}{ "user_id": unicodeUserID, }) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err := json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, unicodeUserID, result["user_id"]) }) } func createAccountRequest(t *testing.T, token string, payload map[string]interface{}) *http.Response { body, err := json.Marshal(payload) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/account/create", bytes.NewBuffer(body)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) return resp } // todo //func TestDeleteAccount_Success(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // // client := &http.Client{Timeout: 5 * time.Second} // resp, err := client.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // // var result map[string]string // err = json.NewDecoder(resp.Body).Decode(&result) // assert.NoError(t, err) // assert.NotEmpty(t, result["accountId"]) //} func TestDeleteAccount_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) assert.NoError(t, err) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer invalid_token") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+expiredToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } //func TestDeleteAccount_AlreadyDeleted(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // assert.Equal(t, http.StatusOK, resp.StatusCode) //} // //func TestDeleteAccount_NonExistent(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // assert.Equal(t, http.StatusOK, resp.StatusCode) //} // todo check we have it? //func TestDeleteAccount_CascadeDeletion(t *testing.T) { // t.Run("RelatedDataDeletion", func(t *testing.T) { // createResp := createAccountRequest(t, validToken, map[string]interface{}{ // "user_id": fmt.Sprintf("cascade_test_%d", time.Now().Unix()), // }) // defer createResp.Body.Close() // assert.Equal(t, http.StatusOK, createResp.StatusCode) // // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // // // Проверяем, что связанные данные удалены или помечены как удаленные // }) // // t.Run("StatisticsPreservation", func(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // // // Проверяем, что статистические данные сохранены // }) //} // //func TestDeleteAccount_Security(t *testing.T) { // t.Run("CSRFProtection", func(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // req.Header.Set("X-CSRF-Token", "invalid_token") // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // // Проверяем CSRF защиту // assert.Equal(t, http.StatusForbidden, resp.StatusCode) // }) //} // //func TestDeleteAccount_Performance(t *testing.T) { // t.Run("ResponseTime", func(t *testing.T) { // req, _ := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // // start := time.Now() // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // duration := time.Since(start) // assert.Less(t, duration.Milliseconds(), int64(500)) // }) //} // //func TestDeleteAccount_Load(t *testing.T) { // var wg sync.WaitGroup // for i := 0; i < 50; i++ { // wg.Add(1) // go func() { // defer wg.Done() // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // if resp != nil { // defer resp.Body.Close() // } // }() // } // wg.Wait() //} // //func TestDeleteAccount_BoundaryCases(t *testing.T) { // t.Run("LargeDataDeletion", func(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // // var result map[string]interface{} // err = json.NewDecoder(resp.Body).Decode(&result) // assert.NoError(t, err) // assert.Contains(t, result, "accountId") // }) // t.Run("ConcurrentOperations", func(t *testing.T) { // var wg sync.WaitGroup // successCount := 0 // var mu sync.Mutex // // for i := 0; i < 10; i++ { // wg.Add(1) // go func() { // defer wg.Done() // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // if resp.StatusCode == http.StatusOK { // mu.Lock() // successCount++ // mu.Unlock() // } // }() // } // wg.Wait() // // assert.Greater(t, successCount, 0) // }) //} // // //func TestDeleteAccount_SpecialCases(t *testing.T) { // t.Run("TransactionAtomicity", func(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validTokenForDelete) // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // // // Проверяем, что операция либо полностью выполнена, либо полностью откачена // assert.True(t, resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusInternalServerError) // }) //} // отсмотрено func TestGetAccounts_Success(t *testing.T) { body := map[string]interface{}{ "limit": 10, "page": 1, } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result struct { Count uint64 `json:"count"` Items []model.Account `json:"items"` } err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEqual(t, len(result.Items), 0) for _, acc := range result.Items { assert.NotEmpty(t, acc.ID) assert.NotEmpty(t, acc.UserID) assert.NotEmpty(t, acc.CreatedAt) } } // отсмотрено func TestGetAccounts_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { body := map[string]interface{}{ "limit": 10, "page": 1, } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { body := map[string]interface{}{ "limit": 10, "page": 1, } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer invalid_token") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { body := map[string]interface{}{ "limit": 10, "page": 1, } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+expiredToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestGetAccounts_Pagination(t *testing.T) { t.Run("ValidPagination", func(t *testing.T) { body := map[string]interface{}{"limit": 5, "page": 1} b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) // todo //t.Run("ZeroPagination", func(t *testing.T) { // body := map[string]interface{}{"limit": 0, "page": 0} // b, err := json.Marshal(body) // assert.NoError(t, err) // req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validAdminToken) // req.Header.Set("Content-Type", "application/json") // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) //}) // todo //t.Run("TooHighLimit", func(t *testing.T) { // body := map[string]interface{}{"limit": 1000} // b, err := json.Marshal(body) // assert.NoError(t, err) // req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validAdminToken) // req.Header.Set("Content-Type", "application/json") // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) //}) } // todo func TestGetAccounts_Security(t *testing.T) { t.Run("SQLInjection", func(t *testing.T) { body := map[string]interface{}{ "limit": "10' OR '1'='1", "page": "1' OR '1'='1", } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSSProtection", func(t *testing.T) { body := map[string]interface{}{ "limit": 10, "page": 1, } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, "nosniff", resp.Header.Get("X-Content-Type-Options")) assert.Equal(t, "1; mode=block", resp.Header.Get("X-XSS-Protection")) assert.Equal(t, "DENY", resp.Header.Get("X-Frame-Options")) }) } // отсмотрено func TestGetAccounts_Performance(t *testing.T) { t.Run("ResponseTimeUnder500ms", func(t *testing.T) { body := map[string]interface{}{"limit": 10, "page": 1} b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") start := time.Now() resp, err := http.DefaultClient.Do(req) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest100Requests", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() body := map[string]interface{}{"limit": 10, "page": 1} b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err == nil { resp.Body.Close() } }() } wg.Wait() }) } // отсмотрено func TestGetAccounts_BoundaryCases(t *testing.T) { t.Run("LargeLimit", func(t *testing.T) { body := map[string]interface{}{ "limit": 10000, // Очень большой лимит "page": 1, } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusInternalServerError, resp.StatusCode) }) t.Run("UnicodeCharacters", func(t *testing.T) { body := map[string]interface{}{ "limit": 10, "page": 1, "search": "тест_поиск", } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) }) } // отсмотрено func TestGetAccounts_SpecialCases(t *testing.T) { t.Run("EmptyResult", func(t *testing.T) { body := map[string]interface{}{ "limit": 10, "page": 999999, // Несуществующая страница } b, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) if accounts, ok := result["accounts"].([]interface{}); ok { assert.Empty(t, accounts) } }) // todo не имеем этого //t.Run("Caching", func(t *testing.T) { // body := map[string]interface{}{ // "limit": 10, // "page": 1, // } // b, err := json.Marshal(body) // assert.NoError(t, err) // // // Первый запрос // req1, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) // assert.NoError(t, err) // req1.Header.Set("Authorization", "Bearer "+validAdminToken) // req1.Header.Set("Content-Type", "application/json") // // resp1, err := http.DefaultClient.Do(req1) // assert.NoError(t, err) // defer resp1.Body.Close() // // // Второй запрос (должен быть быстрее из-за кэша) // req2, err := http.NewRequest("GET", baseURL+"/accounts", bytes.NewReader(b)) // assert.NoError(t, err) // req2.Header.Set("Authorization", "Bearer "+validAdminToken) // req2.Header.Set("Content-Type", "application/json") // // resp2, err := http.DefaultClient.Do(req2) // assert.NoError(t, err) // defer resp2.Body.Close() // // assert.Equal(t, http.StatusOK, resp1.StatusCode) // assert.Equal(t, http.StatusOK, resp2.StatusCode) //}) } func TestGetPrivilege_Success(t *testing.T) { body := map[string]string{"userId": existingUserID} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+existingUserID, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+existingUserIDToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var privileges []model.ShortPrivilege err = json.NewDecoder(resp.Body).Decode(&privileges) assert.NoError(t, err) for _, p := range privileges { assert.NotEmpty(t, p.ID) assert.NotEmpty(t, p.PrivilegeID) assert.NotEmpty(t, p.PrivilegeName) } } // отсмотрено func TestGetPrivilege_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/privilege/"+existingUserID, nil) assert.NoError(t, err) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/privilege/"+existingUserID, nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer invalid_token") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/privilege/"+existingUserID, nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+expiredToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestGetPrivilege_InputValidation(t *testing.T) { t.Run("MissingUserID", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/privilege/", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusNotFound, resp.StatusCode) }) t.Run("InvalidUserID", func(t *testing.T) { body := map[string]int{"userId": 111} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/!!!", bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentUserID", func(t *testing.T) { nonExistentID := "non_existent_user_123" body := map[string]string{"userId": nonExistentID} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+nonExistentID, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var privileges []model.ShortPrivilege err = json.NewDecoder(resp.Body).Decode(&privileges) assert.NoError(t, err) assert.Empty(t, privileges) }) } // отсмотрено func TestGetPrivilege_BoundaryCases(t *testing.T) { t.Run("LongUserID", func(t *testing.T) { longUserID := strings.Repeat("a", 1000) body := map[string]string{"userId": longUserID} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+longUserID, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusInternalServerError, resp.StatusCode) }) t.Run("UnicodeUserID", func(t *testing.T) { unicodeUserID := "тест_пользователь_123" body := map[string]string{"userId": unicodeUserID} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+unicodeUserID, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) }) } // todo func TestGetPrivilege_Security(t *testing.T) { t.Run("SQLInjection", func(t *testing.T) { injection := "1' OR '1'='1" body := map[string]string{"userId": injection} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+injection, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSS", func(t *testing.T) { body := map[string]string{"userId": xssInput} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+xssInput, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestGetPrivilege_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { body := map[string]string{"userId": existingUserID} data, err := json.Marshal(body) assert.NoError(t, err) start := time.Now() req, err := http.NewRequest("GET", baseURL+"/privilege/"+existingUserID, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+existingUserIDToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, time.Since(start).Milliseconds(), int64(300)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() body := map[string]string{"userId": existingUserID} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+existingUserID, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+existingUserIDToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) if resp != nil { defer resp.Body.Close() } }() } wg.Wait() }) } // отсмотрено func TestGetPrivilege_SpecialCases(t *testing.T) { t.Run("UserWithoutPrivileges", func(t *testing.T) { body := map[string]string{"userId": userWithoutPrivileges} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+userWithoutPrivileges, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var privileges []model.ShortPrivilege err = json.NewDecoder(resp.Body).Decode(&privileges) assert.NoError(t, err) assert.Empty(t, privileges) }) t.Run("MultiplePrivileges", func(t *testing.T) { body := map[string]string{"userId": existingUserID} data, err := json.Marshal(body) assert.NoError(t, err) req, err := http.NewRequest("GET", baseURL+"/privilege/"+existingUserID, bytes.NewBuffer(data)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+existingUserIDToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var privileges []model.ShortPrivilege err = json.NewDecoder(resp.Body).Decode(&privileges) assert.NoError(t, err) for _, privilege := range privileges { assert.NotEmpty(t, privilege.ID) assert.NotEmpty(t, privilege.PrivilegeID) assert.NotEmpty(t, privilege.PrivilegeName) } }) } func deleteAccountByUserIDRequest(token string, body interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("DELETE", baseURL+"/account/"+body.(map[string]string)["userId"], bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // todo delete //func TestDeleteAccountByUserID_Success(t *testing.T) { // resp, err := deleteAccountByUserIDRequest(validAdminToken, map[string]string{"userId": userIDForDelete}) // assert.NoError(t, err) // assert.Equal(t, http.StatusOK, resp.StatusCode) // assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // // var result map[string]string // err = json.NewDecoder(resp.Body).Decode(&result) // assert.NoError(t, err) // assert.Equal(t, testUserID, result["userId"]) //} // //func TestDeleteAccountByUserID_Auth(t *testing.T) { // t.Run("NoToken", func(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/"+userIDForDelete, nil) // assert.NoError(t, err) // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("InvalidToken", func(t *testing.T) { // resp, err := deleteAccountByUserIDRequest("invalid_token", map[string]string{"userId": userIDForDelete}) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("ExpiredToken", func(t *testing.T) { // resp, err := deleteAccountByUserIDRequest(expiredToken, map[string]string{"userId": userIDForDelete}) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) //} // //func TestDeleteAccountByUserID_Validation(t *testing.T) { // t.Run("EmptyBody", func(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/account/", bytes.NewReader([]byte(`{}`))) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validAdminToken) // req.Header.Set("Content-Type", "application/json") // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("InvalidUserID", func(t *testing.T) { // resp, err := deleteAccountByUserIDRequest(validAdminToken, map[string]string{"userId": "invalid_id"}) // assert.NoError(t, err) // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestDeleteAccountByUserID_BoundaryCases(t *testing.T) { // t.Run("LongUserID", func(t *testing.T) { // longUserID := strings.Repeat("a", 1000) // Очень длинный user_id // resp, err := deleteAccountByUserIDRequest(validAdminToken, map[string]string{"userId": longUserID}) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.NotEqual(t, http.StatusInternalServerError, resp.StatusCode) // }) // // t.Run("UnicodeUserID", func(t *testing.T) { // unicodeUserID := "тест_пользователь_123" // Unicode символы // resp, err := deleteAccountByUserIDRequest(validAdminToken, map[string]string{"userId": unicodeUserID}) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // }) //} // todo check //func TestDeleteAccountByUserID_Performance(t *testing.T) { // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := deleteAccountByUserIDRequest(deleteAccountToken, map[string]string{"userId": userIDForDelete}) // assert.NoError(t, err) // defer resp.Body.Close() // // duration := time.Since(start) // assert.Less(t, duration.Milliseconds(), int64(1000)) // < 1s // assert.Equal(t, http.StatusOK, resp.StatusCode) // }) // // t.Run("LoadTest", func(t *testing.T) { // var wg sync.WaitGroup // successCount := 0 // var mu sync.Mutex // // for i := 0; i < 10; i++ { // wg.Add(1) // go func(index int) { // defer wg.Done() // testUserID := fmt.Sprintf("load_test_user_%d", index) // resp, err := deleteAccountByUserIDRequest(deleteAccountToken, map[string]string{"userId": testUserID}) // if err == nil && resp != nil { // defer resp.Body.Close() // if resp.StatusCode == http.StatusOK { // mu.Lock() // successCount++ // mu.Unlock() // } // } // }(i) // } // wg.Wait() // // assert.Greater(t, successCount, 5) // > 50% успешных // }) //} // func TestDeleteAccountByUserID_SQLInjection_XSS(t *testing.T) { // t.Run("SQLInjection", func(t *testing.T) { // resp, err := deleteAccountByUserIDRequest(deleteAccountToken, map[string]string{"userId": sqlInjectionInput}) // assert.NoError(t, err) // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("XSS", func(t *testing.T) { // resp, err := deleteAccountByUserIDRequest(deleteAccountToken, map[string]string{"userId": xssInput}) // assert.NoError(t, err) // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // } // // todo //func TestDeleteAccountByUserID_SpecialCases(t *testing.T) { // t.Run("TransactionAtomicity", func(t *testing.T) { // resp, err := deleteAccountByUserIDRequest(deleteAccountToken, map[string]string{"userId": userIDForDelete}) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.True(t, resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusInternalServerError) // }) // // t.Run("CascadeDeletion", func(t *testing.T) { // resp, err := deleteAccountByUserIDRequest(deleteAccountToken, map[string]string{"userId": testUserID}) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // // // Для тестов просто проверяем успешность операции // }) //} func manualDoneRequest(token string, body map[string]string) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/account/manualdone", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // todo func TestManualDone_Success(t *testing.T) { resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": testUserID}) assert.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, testUserID, result["id"]) } // отсмотрено func TestManualDone_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]string{"id": testUserID}) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/account/manualdone", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := manualDoneRequest("invalid_token", map[string]string{"id": testUserID}) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := manualDoneRequest(expiredToken, map[string]string{"id": testUserID}) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestManualDone_Validation(t *testing.T) { t.Run("EmptyBody", func(t *testing.T) { payload := []byte(`{}`) req, err := http.NewRequest("POST", baseURL+"/account/manualdone", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validAdminToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": "invalid_id"}) assert.NoError(t, err) assert.Equal(t, http.StatusNotFound, resp.StatusCode) }) t.Run("NonExistentID", func(t *testing.T) { resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": "nonexistent_id"}) assert.NoError(t, err) assert.Equal(t, http.StatusNotFound, resp.StatusCode) }) } // отсмотрено func TestManualDone_BoundaryCases(t *testing.T) { t.Run("LongID", func(t *testing.T) { longID := strings.Repeat("a", 1000) // Очень длинный ID resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": longID}) assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusInternalServerError, resp.StatusCode) }) // todo t.Run("UnicodeID", func(t *testing.T) { unicodeID := "тест_id_123" // Unicode символы resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": unicodeID}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) }) } // отсмотрено func TestManualDone_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": validUserID}) assert.NoError(t, err) defer resp.Body.Close() duration := time.Since(start) assert.Less(t, duration.Milliseconds(), int64(500)) // < 500ms assert.Equal(t, http.StatusOK, resp.StatusCode) }) } // todo func TestManualDone_Security(t *testing.T) { t.Run("SQLInjection", func(t *testing.T) { resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": sqlInjectionInput}) assert.NoError(t, err) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSSAttack", func(t *testing.T) { resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": xssInput}) assert.NoError(t, err) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestManualDone_SpecialCases(t *testing.T) { t.Run("TransactionAtomicity", func(t *testing.T) { resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": validUserID}) assert.NoError(t, err) defer resp.Body.Close() assert.True(t, resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusInternalServerError) }) t.Run("Idempotency", func(t *testing.T) { resp1, err := manualDoneRequest(validAdminToken, map[string]string{"id": validUserID}) assert.NoError(t, err) defer resp1.Body.Close() resp2, err := manualDoneRequest(validAdminToken, map[string]string{"id": validUserID}) assert.NoError(t, err) defer resp2.Body.Close() assert.Equal(t, resp1.StatusCode, resp2.StatusCode) }) } // TODO ВСЕ ЧТО НИЖЕ ДЕЛАЛ КУРСОР НАДО ВСЕ ТЕСТЫ ПЕРЕПРОВЕРИТЬ ПОКА ЧТО ПРОВЕРЕННО ТОЛЬКО НАЛИЧИЕ ДЛЯ КАЖДОГО ТЕСТ КЕЙСА func createLeadTargetRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/account/leadtarget", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestCreateLeadTarget_Success(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 123, "target": "example@mail.com", "name": "Example Channel", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) } // отсмотрено func TestCreateLeadTarget_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "type": "mail", "quizID": 123, "target": "example@mail.com", }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/account/leadtarget", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := createLeadTargetRequest("invalid_token", map[string]interface{}{ "type": "mail", "quizID": 123, "target": "example@mail.com", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := createLeadTargetRequest(expiredToken, map[string]interface{}{ "type": "mail", "quizID": 123, "target": "example@mail.com", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestCreateLeadTarget_InputValidation(t *testing.T) { t.Run("MissingRequiredFields", func(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidType", func(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "invalid", "quizID": 123, "target": "example@mail.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("EmptyBody", func(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // todo func TestCreateLeadTarget_Security(t *testing.T) { t.Run("SQLInjection", func(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": "1' OR '1'='1", "target": "example@mail.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSSAttack", func(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 123, "target": xssInput, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestCreateLeadTarget_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 999, "target": "perf@mail.com", }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(1000)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 50; i++ { wg.Add(1) go func(index int) { defer wg.Done() resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 1000 + index, "target": fmt.Sprintf("load%d@mail.com", index), }) if err == nil && resp != nil { resp.Body.Close() } }(i) } wg.Wait() }) } // отсмотрено func TestCreateLeadTarget_BoundaryCases(t *testing.T) { t.Run("MaxLengthFields", func(t *testing.T) { longEmail := strings.Repeat("a", 100) + "@domain.com" longName := strings.Repeat("b", 200) resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 123, "target": longEmail, "name": longName, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("SpecialCharacters", func(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 123, "target": "special!@#$%^&*()@domain.com", "name": "Special Name!", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } // отсмотрено func TestCreateLeadTarget_SpecialCases(t *testing.T) { t.Run("TransactionAtomicity", func(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 123, "target": "atomic@mail.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.True(t, resp.StatusCode == http.StatusOK) }) t.Run("DataValidation", func(t *testing.T) { resp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 123, "target": "validation@mail.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } func updateLeadTargetRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("PUT", baseURL+"/account/leadtarget", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestUpdateLeadTarget_Success(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "old@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(validToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": getRespLead[0].ID, "target": "new_target@mail.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, float64(getRespLead[0].ID), result["id"]) assert.Equal(t, "new_target@mail.com", result["target"]) } // отсмотрено func TestUpdateLeadTarget_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": 123, "target": "example@mail.com", }) assert.NoError(t, err) req, err := http.NewRequest("PUT", baseURL+"/account/leadtarget", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := updateLeadTargetRequest("invalid_token", map[string]interface{}{ "id": 123, "target": "example@mail.com", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := updateLeadTargetRequest(expiredToken, map[string]interface{}{ "id": 123, "target": "example@mail.com", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestUpdateLeadTarget_InputValidation(t *testing.T) { t.Run("MissingRequiredFields", func(t *testing.T) { resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": 123, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": "invalid", "target": "example@mail.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo такого нет у нас //t.Run("InvalidTargetFormat", func(t *testing.T) { // resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ // "id": 123, // "target": "invalid_email", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) //}) t.Run("EmptyBody", func(t *testing.T) { resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestUpdateLeadTarget_Existence(t *testing.T) { t.Run("NonExistentID", func(t *testing.T) { resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": 999999, "target": "example@mail.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotFound, resp.StatusCode) }) } // todo func TestUpdateLeadTarget_Security(t *testing.T) { t.Run("SQLInjection", func(t *testing.T) { resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": "1' OR '1'='1", "target": "example@mail.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSSAttack", func(t *testing.T) { resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": 123, "target": xssInput, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestUpdateLeadTarget_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "perf@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(validToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) start := time.Now() resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": getRespLead[0].ID, "target": "updated_perf@mail.com", }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(1000)) }) } // отсмотрено func TestUpdateLeadTarget_BoundaryCases(t *testing.T) { t.Run("MaxLengthTarget", func(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "perf@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(validToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) longEmail := strings.Repeat("a", 100) + "@domain.com" resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": getRespLead[0].ID, "target": longEmail, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("SpecialCharacters", func(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "perf@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(validToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) resp, err := updateLeadTargetRequest(validToken, map[string]interface{}{ "id": getRespLead[0].ID, "target": "special!@#$%^&*()@domain.com", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } // отсмотрено func TestDeleteLeadTarget_SpecialCases(t *testing.T) { t.Run("TransactionAtomicity", func(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(deleteLeadTargetToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "atomic@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() getResp, err := getLeadTargetByQuizIDRequest(validToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) resp, err := deleteLeadTargetRequest(validToken, getRespLead[0].ID) assert.NoError(t, err) defer resp.Body.Close() assert.True(t, resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusInternalServerError) }) } func deleteLeadTargetRequest(token string, targetID int64) (*http.Response, error) { req, err := http.NewRequest("DELETE", baseURL+"/account/leadtarget/"+fmt.Sprintf("%d", targetID), nil) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) return http.DefaultClient.Do(req) } // отсмотрено func TestDeleteLeadTarget_Success(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(deleteLeadTargetToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "delete@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(deleteLeadTargetToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) resp, err := deleteLeadTargetRequest(deleteLeadTargetToken, getRespLead[0].ID) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) } // отсмотрено func TestDeleteLeadTarget_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { req, err := http.NewRequest("DELETE", baseURL+"/account/leadtarget/123", nil) assert.NoError(t, err) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := deleteLeadTargetRequest("invalid_token", 123) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := deleteLeadTargetRequest(expiredToken, 123) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestDeleteLeadTarget_InputValidation(t *testing.T) { t.Run("InvalidID", func(t *testing.T) { resp, err := deleteLeadTargetRequest(deleteLeadTargetToken, 999999) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("EmptyID", func(t *testing.T) { req, err := http.NewRequest("DELETE", baseURL+"/account/leadtarget/", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+deleteLeadTargetToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentID", func(t *testing.T) { resp, err := deleteLeadTargetRequest(deleteLeadTargetToken, 999999) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } // отсмотрено func TestDeleteLeadTarget_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(deleteLeadTargetToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "perf_delete@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(deleteLeadTargetToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) start := time.Now() resp, err := deleteLeadTargetRequest(deleteLeadTargetToken, getRespLead[0].ID) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(1000)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 30; i++ { wg.Add(1) go func(index int) { defer wg.Done() quizID := faker.Int32() createResp, err := createLeadTargetRequest(deleteLeadTargetToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": fmt.Sprintf("load_delete%d@mail.com", index), }) if err != nil { return } defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(deleteLeadTargetToken, fmt.Sprintf("%d", quizID)) if err != nil { return } defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) if err != nil || len(getRespLead) == 0 { return } resp, err := deleteLeadTargetRequest(deleteLeadTargetToken, getRespLead[0].ID) if err == nil && resp != nil { resp.Body.Close() } }(i) } wg.Wait() }) } // отсмотрено func TestDeleteLeadTarget_AlreadyDeleted(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(deleteLeadTargetToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "already_deleted@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(deleteLeadTargetToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) resp1, err := deleteLeadTargetRequest(deleteLeadTargetToken, getRespLead[0].ID) assert.NoError(t, err) resp1.Body.Close() resp2, err := deleteLeadTargetRequest(deleteLeadTargetToken, getRespLead[0].ID) assert.NoError(t, err) defer resp2.Body.Close() assert.Equal(t, http.StatusOK, resp2.StatusCode) } func getLeadTargetByQuizIDRequest(token string, quizID string) (*http.Response, error) { req, err := http.NewRequest("GET", baseURL+"/account/leadtarget/"+quizID, nil) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) return http.DefaultClient.Do(req) } // отсмотрено func TestGetLeadTargetByQuizID_Success(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "get@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) resp, err := getLeadTargetByQuizIDRequest(validToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result []model.LeadTarget err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.True(t, len(result) > 0) assert.Equal(t, quizID, result[0].QuizID) assert.Equal(t, model.LeadTargetType("mail"), result[0].Type) assert.Equal(t, "get@mail.com", result[0].Target) } // отсмотрено func TestGetLeadTargetByQuizID_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/leadtarget/123", nil) assert.NoError(t, err) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getLeadTargetByQuizIDRequest("invalid_token", "123") assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := getLeadTargetByQuizIDRequest(expiredToken, "123") assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestGetLeadTargetByQuizID_InputValidation(t *testing.T) { t.Run("InvalidQuizID", func(t *testing.T) { resp, err := getLeadTargetByQuizIDRequest(validToken, "invalid_id") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("EmptyQuizID", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/account/leadtarget/", nil) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusMethodNotAllowed, resp.StatusCode) }) } // todo func TestGetLeadTargetByQuizID_Security(t *testing.T) { t.Run("SQLInjection", func(t *testing.T) { resp, err := getLeadTargetByQuizIDRequest(validToken, "1' OR '1'='1") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSSAttack", func(t *testing.T) { resp, err := getLeadTargetByQuizIDRequest(validToken, xssInput) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestGetLeadTargetByQuizID_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { createResp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 456, "target": "perf_get@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() start := time.Now() resp, err := getLeadTargetByQuizIDRequest(validToken, "456") duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(300)) }) t.Run("LoadTest", func(t *testing.T) { createResp, err := createLeadTargetRequest(validToken, map[string]interface{}{ "type": "mail", "quizID": 789, "target": "load_get@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getLeadTargetByQuizIDRequest(validToken, "789") if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } // отсмотрено func TestGetLeadTargetByQuizID_DeletedTarget(t *testing.T) { quizID := faker.Int32() createResp, err := createLeadTargetRequest(deleteLeadTargetToken, map[string]interface{}{ "type": "mail", "quizID": quizID, "target": "deleted@mail.com", }) assert.NoError(t, err) defer createResp.Body.Close() assert.Equal(t, http.StatusOK, createResp.StatusCode) getResp, err := getLeadTargetByQuizIDRequest(deleteLeadTargetToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer getResp.Body.Close() assert.Equal(t, http.StatusOK, getResp.StatusCode) var getRespLead []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead) assert.NoError(t, err) assert.True(t, len(getRespLead) > 0) deleteResp, err := deleteLeadTargetRequest(deleteLeadTargetToken, getRespLead[0].ID) assert.NoError(t, err) deleteResp.Body.Close() resp, err := getLeadTargetByQuizIDRequest(deleteLeadTargetToken, fmt.Sprintf("%d", quizID)) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) //todo сомнительное надо бы там на len проверять ответ из бдшки var getRespLead2 []model.LeadTarget err = json.NewDecoder(getResp.Body).Decode(&getRespLead2) assert.Error(t, err) } func createQuestionRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/question/create", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestCreateQuestion_Success(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования вопросов", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Какой основной компонент воздуха?", "type": "variant", "description": "Выберите один правильный ответ.", "required": true, "page": 1, "content": "{}", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result model.Question err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result.Id) assert.Equal(t, quizResult.Id, result.QuizId) assert.Equal(t, "Какой основной компонент воздуха?", result.Title) assert.Equal(t, "variant", result.Type) assert.Equal(t, "Выберите один правильный ответ.", result.Description) assert.Equal(t, true, result.Required) assert.Equal(t, 1, result.Page) assert.Equal(t, "{}", result.Content) assert.NotEmpty(t, result.CreatedAt) } // отсмотрено func TestCreateQuestion_Auth(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования аутентификации вопросов", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/question/create", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := createQuestionRequest("invalid_token", map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := createQuestionRequest(expiredToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestCreateQuestion_InputValidation(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования валидации вопросов", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) t.Run("MissingRequiredFields", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "title": "Test Question", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotAcceptable, resp.StatusCode) }) t.Run("InvalidQuizID", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": "invalid", "title": "Test Question", "type": "variant", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidType", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "invalid_type", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotAcceptable, resp.StatusCode) }) t.Run("InvalidRequired", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", "required": "not_boolean", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidPage", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", "page": "not_number", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("EmptyBody", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotAcceptable, resp.StatusCode) }) } // отсмотрено func TestCreateQuestion_DifferentTypes(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования разных типов вопросов", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) // todo "result" questionTypes := []string{"text", "variant", "images", "select", "varimg", "emoji", "date", "number", "page", "rating", "file"} // "result" for _, questionType := range questionTypes { t.Run(questionType, func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": fmt.Sprintf("Test %s Question", questionType), "type": questionType, "content": "{}", }) assert.NoError(t, err) defer resp.Body.Close() fmt.Println(questionType) assert.Equal(t, http.StatusOK, resp.StatusCode) }) } } func TestCreateQuestion_Security(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования безопасности вопросов", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) t.Run("SQLInjection", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": "1' OR '1'='1", "title": "Test Question", "type": "variant", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo t.Run("XSSAttack", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": xssInput, "type": "variant", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestCreateQuestion_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования производительности", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) start := time.Now() resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.CreatedAt, "title": "Performance Test Question", "type": "variant", }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 50; i++ { wg.Add(1) go func(index int) { defer wg.Done() quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": fmt.Sprintf("Load Test Quiz %d", index), "status": "draft", }) if err != nil { return } defer quizResp.Body.Close() if quizResp.StatusCode != http.StatusCreated { return } var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": fmt.Sprintf("Load Test Question %d", index), "type": "variant", }) if err == nil && resp != nil { resp.Body.Close() } }(i) } wg.Wait() }) } // отсмотрено func TestCreateQuestion_BoundaryCases(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования граничных случаев", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) t.Run("MaxLengthTitle", func(t *testing.T) { longTitle := strings.Repeat("a", 511) resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": longTitle, "type": "variant", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("LongDescription", func(t *testing.T) { longDescription := strings.Repeat("b", 1000) resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", "description": longDescription, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("SpecialCharacters", func(t *testing.T) { resp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Special!@#$%^&*() Question", "type": "variant", "description": "Description with special chars: !@#$%^&*()", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } func getQuestionListRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/question/getList", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestGetQuestionList_Success(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования списка вопросов", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) fmt.Println(quizResult.Id) for i := 0; i < 3; i++ { createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": fmt.Sprintf("Test Question %d", i), "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() } resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "limit": 10, "page": 0, "quiz_id": quizResult.Id, "type": "variant", "deleted": false, "required": false, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result question.GetQuestionListResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result.Count) assert.NotEmpty(t, result.Items) assert.LessOrEqual(t, len(result.Items), 10) if len(result.Items) > 0 { assert.NotEmpty(t, result.Items[0].Id) assert.Equal(t, quizResult.Id, result.Items[0].QuizId) assert.Equal(t, "variant", result.Items[0].Type) } } // отсмотрено func TestGetQuestionList_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "limit": 10, "page": 1, }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/question/getList", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getQuestionListRequest("invalid_token", map[string]interface{}{ "limit": 10, "page": 1, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := getQuestionListRequest(expiredToken, map[string]interface{}{ "limit": 10, "page": 1, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestGetQuestionList_InputValidation(t *testing.T) { t.Run("InvalidPagination", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "limit": "invalid", "page": "invalid", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidQuizID", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "quiz_id": "invalid", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidType", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "type": "invalid_type", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotAcceptable, resp.StatusCode) }) t.Run("InvalidBoolean", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "deleted": "not_boolean", "required": "not_boolean", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo //t.Run("InvalidTimeRange", func(t *testing.T) { // resp, err := getQuestionListRequest(validToken, map[string]interface{}{ // "from": 1000, // "to": 500, // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) //}) } // отсмотрено func TestGetQuestionList_Pagination(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования пагинации", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) for i := 0; i < 15; i++ { createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": fmt.Sprintf("Pagination Question %d", i), "type": "text", }) assert.NoError(t, err) createResp.Body.Close() } t.Run("FirstPage", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "limit": 5, "page": 1, "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result question.GetQuestionListResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.LessOrEqual(t, len(result.Items), 5) }) t.Run("SecondPage", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "limit": 5, "page": 2, "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result question.GetQuestionListResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.LessOrEqual(t, len(result.Items), 5) }) t.Run("EmptyPage", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "limit": 5, "page": 1000, "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result question.GetQuestionListResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Empty(t, result.Items) }) } // отсмотрено func TestGetQuestionList_Filters(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования фильтров", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) questionTypes := []string{"text", "variant", "select"} for _, questionType := range questionTypes { createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": fmt.Sprintf("Filter Question %s", questionType), "type": questionType, }) assert.NoError(t, err) createResp.Body.Close() } t.Run("FilterByType", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "type": "text", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result question.GetQuestionListResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) for _, item := range result.Items { assert.Equal(t, "text", item.Type) } }) //todo //t.Run("FilterBySearch", func(t *testing.T) { // resp, err := getQuestionListRequest(validToken, map[string]interface{}{ // "quiz_id": quizResult.Id, // "search": "ф", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // var result question.GetQuestionListResp // err = json.NewDecoder(resp.Body).Decode(&result) // assert.NoError(t, err) // // assert.NotEmpty(t, result.Items) //}) t.Run("FilterByRequired", func(t *testing.T) { resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "required": true, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result question.GetQuestionListResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) for _, item := range result.Items { assert.Equal(t, true, item.Required) } }) } // отсмотрено func TestGetQuestionList_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "limit": 10, "page": 1, }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getQuestionListRequest(validToken, map[string]interface{}{ "limit": 5, "page": 1, }) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func editQuestionRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("PATCH", baseURL+"/question/edit", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestEditQuestion_Success(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования редактирования", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Original Question", "type": "variant", "required": true, }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": "Обновленный заголовок вопроса?", "desc": "Новое описание для вопроса.", "type": "text", "required": false, "content": "{\"placeholder\":\"Введите ваш ответ здесь\"}", "page": 2, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result question.UpdateResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, createResult.Id, result.Updated) } // отсмотрено func TestEditQuestion_SingleField(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования редактирования одного поля", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Single Field Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": "Только заголовок обновлен", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result question.UpdateResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, createResult.Id, result.Updated) } // отсмотрено func TestEditQuestion_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": 123, "title": "Test Question", }) assert.NoError(t, err) req, err := http.NewRequest("PATCH", baseURL+"/question/edit", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := editQuestionRequest("invalid_token", map[string]interface{}{ "id": 123, "title": "Test Question", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := editQuestionRequest(expiredToken, map[string]interface{}{ "id": 123, "title": "Test Question", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestEditQuestion_InputValidation(t *testing.T) { t.Run("MissingID", func(t *testing.T) { resp, err := editQuestionRequest(validToken, map[string]interface{}{ "title": "Запрос без ID", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusFailedDependency, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": "not_an_integer", "title": "Невалидный ID", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo если нет то надо 404 //t.Run("NonExistentID", func(t *testing.T) { // resp, err := editQuestionRequest(validToken, map[string]interface{}{ // "id": 99999, // "title": "Несуществующий вопрос", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusNotFound, resp.StatusCode) //}) t.Run("InvalidTitle", func(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования невалидного заголовка", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) longTitle := strings.Repeat("a", 513) resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": longTitle, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusUnprocessableEntity, resp.StatusCode) }) t.Run("InvalidType", func(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования невалидного типа", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "type": "invalid_type", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotAcceptable, resp.StatusCode) }) t.Run("InvalidRequired", func(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования невалидного required", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "required": "not_boolean", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // todo func TestEditQuestion_Security(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования невалидного required", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("SQLInjection", func(t *testing.T) { resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": "1' OR '1'='1", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSSAttack", func(t *testing.T) { resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": xssInput, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestEditQuestion_Performance(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования невалидного required", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Performance Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": "Updated Performance Test Question", }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 30; i++ { wg.Add(1) go func(index int) { defer wg.Done() createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": fmt.Sprintf("Load Test Question %d", index), "type": "variant", }) if err != nil { return } defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": fmt.Sprintf("Updated Load Test Question %d", index), }) if err == nil && resp != nil { resp.Body.Close() } }(i) } wg.Wait() }) } func copyQuestionRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/question/copy", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestCopyQuestion_Success(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Исходный квиз для копирования", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Какой основной компонент воздуха?", "type": "variant", "description": "Выберите один правильный ответ из предложенных.", "required": true, "page": 1, "content": "{}", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) targetQuizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Целевой квиз для копирования", "status": "draft", }) assert.NoError(t, err) defer targetQuizResp.Body.Close() assert.Equal(t, http.StatusCreated, targetQuizResp.StatusCode) var targetQuizResult model.Quiz err = json.NewDecoder(targetQuizResp.Body).Decode(&targetQuizResult) assert.NoError(t, err) resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "quiz_id": targetQuizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var resultCopy question.UpdateResp err = json.NewDecoder(resp.Body).Decode(&resultCopy) assert.NoError(t, err) assert.NoError(t, err) assert.NotEmpty(t, resultCopy.Updated) assert.NotEqual(t, createResult.Id, resultCopy.Updated) } // отсмотрено func TestCopyQuestion_Auth(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования аутентификации копирования", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question for Copy", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": createResult.Id, "quiz_id": quizResult.Id, }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/question/copy", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := copyQuestionRequest("invalid_token", map[string]interface{}{ "id": createResult.Id, "quiz_id": quizResult.Id, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := copyQuestionRequest(expiredToken, map[string]interface{}{ "id": createResult.Id, "quiz_id": quizResult.Id, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено todo func TestCopyQuestion_InputValidation(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования валидации копирования", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question for Validation", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("MissingID", func(t *testing.T) { resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusFailedDependency, resp.StatusCode) }) // todo как проходит? надо фиксить t.Run("MissingQuizID", func(t *testing.T) { resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": "invalid", "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidQuizID", func(t *testing.T) { resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "quiz_id": "invalid", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo надо возвращать 404 t.Run("NonExistentID", func(t *testing.T) { resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": 99999, "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // todo func TestCopyQuestion_Security(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования безопасности копирования", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Security Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("SQLInjection", func(t *testing.T) { resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": "1' OR '1'='1", "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSSAttack", func(t *testing.T) { resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestCopyQuestion_Performance(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования производительности копирования", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Performance Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "quiz_id": quizResult.Id, }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 30; i++ { wg.Add(1) go func(index int) { defer wg.Done() quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": fmt.Sprintf("Load Test Quiz %d", index), "status": "draft", }) if err != nil { return } defer quizResp.Body.Close() if quizResp.StatusCode != http.StatusCreated { return } var quizResult map[string]interface{} err = json.NewDecoder(quizResp.Body).Decode(&quizResult) if err != nil { return } quizID := quizResult["id"] createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizID, "title": fmt.Sprintf("Load Test Question %d", index), "type": "variant", }) if err != nil { return } defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) if err != nil { return } originalID := createResult["id"] resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": originalID, "quiz_id": quizID, }) if err == nil && resp != nil { resp.Body.Close() } }(i) } wg.Wait() }) } // отсмотрено func TestCopyQuestion_OriginalPreserved(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Исходный квиз для проверки сохранения оригинала", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Original Question", "type": "variant", "required": true, }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := copyQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "quiz_id": quizResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var copyResult question.UpdateResp err = json.NewDecoder(resp.Body).Decode(©Result) assert.NoError(t, err) assert.NotEqual(t, createResult.Id, copyResult.Updated) } func getQuestionHistoryRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/question/history", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestGetQuestionHistory_Success(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования истории вопросов", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Original Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) for i := 1; i <= 3; i++ { editResp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": fmt.Sprintf("Updated Question Version %d", i), }) assert.NoError(t, err) editResp.Body.Close() } resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": createResult.Id, "l": 10, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result []model.Question err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) fmt.Println(result) if len(result) > 0 { assert.Equal(t, createResult.Id, result[0].Id) assert.Equal(t, quizResult.Id, result[0].QuizId) assert.NotEmpty(t, result[0].Version) } } // отсмотрено func TestGetQuestionHistory_Auth(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования аутентификации истории", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question for History", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": createResult.Id, "l": 10, "p": 0, }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/question/history", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getQuestionHistoryRequest("invalid_token", map[string]interface{}{ "id": createResult.Id, "l": 10, "p": 0, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := getQuestionHistoryRequest(expiredToken, map[string]interface{}{ "id": createResult.Id, "l": 10, "p": 0, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestGetQuestionHistory_InputValidation(t *testing.T) { t.Run("MissingID", func(t *testing.T) { resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "l": 10, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusFailedDependency, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": "not_an_integer", "l": 10, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidLimit", func(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования невалидного лимита", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult map[string]interface{} err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) quizID := quizResult["id"] createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizID, "title": "Test Question for Invalid Limit", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) questionID := createResult["id"] resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": questionID, "l": "ten", "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidPage", func(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования невалидной страницы", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult map[string]interface{} err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) quizID := quizResult["id"] createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizID, "title": "Test Question for Invalid Page", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) questionID := createResult["id"] resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": questionID, "l": 10, "p": "one", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NegativeLimit", func(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования отрицательного лимита", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult map[string]interface{} err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) quizID := quizResult["id"] createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizID, "title": "Test Question for Negative Limit", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) questionID := createResult["id"] resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": questionID, "l": -5, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentID", func(t *testing.T) { resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": 99999, "l": 10, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } // отсмотрено func TestGetQuestionHistory_Pagination(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования пагинации истории", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult map[string]interface{} err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) quizID := quizResult["id"] createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizID, "title": "Pagination Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) questionID := createResult["id"] for i := 1; i <= 15; i++ { editResp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": questionID, "title": fmt.Sprintf("Version %d", i), }) assert.NoError(t, err) editResp.Body.Close() } t.Run("FirstPage", func(t *testing.T) { resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": questionID, "l": 5, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result []model.Question err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.LessOrEqual(t, len(result), 5) }) t.Run("SecondPage", func(t *testing.T) { resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": questionID, "l": 5, "p": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result []model.Question err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.LessOrEqual(t, len(result), 5) }) t.Run("EmptyPage", func(t *testing.T) { resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": questionID, "l": 5, "p": 100, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result []model.Question err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Empty(t, len(result), 5) }) } // отсмотрено func TestGetQuestionHistory_NewQuestion(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования нового вопроса", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "New Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result []model.Question err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Len(t, result, 0) } // отсмотрено func TestGetQuestionHistory_Performance(t *testing.T) { quizResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для тестирования производительности истории", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(validToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Performance Test Question", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) for i := 1; i <= 5; i++ { editResp, err := editQuestionRequest(validToken, map[string]interface{}{ "id": createResult.Id, "title": fmt.Sprintf("Version %d", i), }) assert.NoError(t, err) editResp.Body.Close() } t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": createResult.Id, "l": 10, "p": 1, }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getQuestionHistoryRequest(validToken, map[string]interface{}{ "id": createResult.Id, "l": 5, "p": 1, }) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func deleteQuestionRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("DELETE", baseURL+"/question/delete", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestDeleteQuestion_Success(t *testing.T) { quizResp, err := createQuizRequest(deleteQuestionToken, map[string]interface{}{ "name": "Квиз для тестирования удаления", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(deleteQuestionToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Question to Delete", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result question.DeactivateResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, createResult.Id, result.Deactivated) } // отсмотрено func TestDeleteQuestion_Idempotency(t *testing.T) { quizResp, err := createQuizRequest(deleteQuestionToken, map[string]interface{}{ "name": "Квиз для тестирования идемпотентности удаления", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(deleteQuestionToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Question for Idempotency Test", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp1, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) defer resp1.Body.Close() assert.Equal(t, http.StatusOK, resp1.StatusCode) resp2, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) defer resp2.Body.Close() assert.Equal(t, http.StatusOK, resp2.StatusCode) var result1, result2 question.DeactivateResp err = json.NewDecoder(resp1.Body).Decode(&result1) assert.NoError(t, err) err = json.NewDecoder(resp2.Body).Decode(&result2) assert.NoError(t, err) assert.Equal(t, createResult.Id, result1.Deactivated) assert.Equal(t, createResult.Id, result2.Deactivated) } // отсмотрено func TestDeleteQuestion_Auth(t *testing.T) { quizResp, err := createQuizRequest(deleteQuestionToken, map[string]interface{}{ "name": "Квиз для тестирования аутентификации удаления", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(deleteQuestionToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Test Question for Delete Auth", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) req, err := http.NewRequest("DELETE", baseURL+"/question/delete", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := deleteQuestionRequest("invalid_token", map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := deleteQuestionRequest(expiredToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestDeleteQuestion_InputValidation(t *testing.T) { t.Run("MissingID", func(t *testing.T) { resp, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusFailedDependency, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": "not_an_integer", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo 404? t.Run("NonExistentID", func(t *testing.T) { resp, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": 99999, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestDeleteQuestion_AlreadyDeleted(t *testing.T) { quizResp, err := createQuizRequest(deleteQuestionToken, map[string]interface{}{ "name": "Квиз для тестирования повторного удаления", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) createResp, err := createQuestionRequest(deleteQuestionToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": "Question to Delete Twice", "type": "variant", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Question err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp1, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) defer resp1.Body.Close() assert.Equal(t, http.StatusOK, resp1.StatusCode) resp2, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) defer resp2.Body.Close() assert.Equal(t, http.StatusOK, resp2.StatusCode) var result1, result2 question.DeactivateResp err = json.NewDecoder(resp1.Body).Decode(&result1) assert.NoError(t, err) err = json.NewDecoder(resp2.Body).Decode(&result2) assert.NoError(t, err) assert.Equal(t, createResult.Id, result1.Deactivated) assert.Equal(t, createResult.Id, result2.Deactivated) } // отсмотрено func TestDeleteQuestion_Performance(t *testing.T) { quizResp, err := createQuizRequest(deleteQuestionToken, map[string]interface{}{ "name": "Квиз для тестирования производительности удаления", "status": "draft", }) assert.NoError(t, err) defer quizResp.Body.Close() assert.Equal(t, http.StatusCreated, quizResp.StatusCode) var quizResult model.Quiz err = json.NewDecoder(quizResp.Body).Decode(&quizResult) assert.NoError(t, err) var questionIDs []uint64 for i := 0; i < 10; i++ { createResp, err := createQuestionRequest(deleteQuestionToken, map[string]interface{}{ "quiz_id": quizResult.Id, "title": fmt.Sprintf("Performance Test Question %d", i), "type": "variant", }) assert.NoError(t, err) var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) createResp.Body.Close() assert.NoError(t, err) questionIDs = append(questionIDs, createResult.Id) } t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": questionIDs[0], }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("BulkDelete", func(t *testing.T) { var wg sync.WaitGroup for i := 1; i < len(questionIDs); i++ { wg.Add(1) go func(id interface{}) { defer wg.Done() resp, err := deleteQuestionRequest(deleteQuestionToken, map[string]interface{}{ "id": id, }) if err == nil && resp != nil { resp.Body.Close() } }(questionIDs[i]) } wg.Wait() }) } func createQuizRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/quiz/create", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // todo если у нас квиз без статуса передается, то будет ошибка func TestCreateQuiz_Success(t *testing.T) { t.Run("MinimalQuiz", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Новый квиз по истории", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result.Id) assert.NotEmpty(t, result.Qid) assert.NotEmpty(t, result.AccountId) assert.Equal(t, "Новый квиз по истории", result.Name) assert.Equal(t, "draft", result.Status) assert.Equal(t, false, result.Deleted) assert.Equal(t, false, result.Archived) assert.Equal(t, 1, result.Version) }) // отсмотрено t.Run("FullQuiz", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Полный квиз по географии", "description": "Детальный тест на знание столиц и стран.", "fingerprinting": true, "repeatable": true, "note_prevented": false, "mail_notifications": true, "unique_answers": false, "config": "{\"showCorrectAnswers\": true}", "status": "start", "limit": 100, "question_cnt": 10, "time_of_passing": 3600, "pausable": true, "super": false, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result.Id) assert.Equal(t, "Полный квиз по географии", result.Name) assert.Equal(t, "Детальный тест на знание столиц и стран.", result.Description) assert.Equal(t, true, result.Fingerprinting) assert.Equal(t, true, result.Repeatable) assert.Equal(t, false, result.NotePrevented) assert.Equal(t, true, result.MailNotifications) assert.Equal(t, false, result.UniqueAnswers) assert.Equal(t, "{\"showCorrectAnswers\": true}", result.Config) assert.Equal(t, "start", result.Status) assert.Equal(t, uint64(100), result.Limit) assert.Equal(t, uint64(10), result.QuestionsCount) assert.Equal(t, uint64(3600), result.TimeOfPassing) assert.Equal(t, true, result.Pausable) assert.Equal(t, false, result.Super) }) } // отсмотрено func TestCreateQuiz_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "name": "Test Quiz", }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/quiz/create", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := createQuizRequest("invalid_token", map[string]interface{}{ "name": "Test Quiz", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := createQuizRequest(expiredToken, map[string]interface{}{ "name": "Test Quiz", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestCreateQuiz_InputValidation(t *testing.T) { t.Run("NameTooLong", func(t *testing.T) { longName := strings.Repeat("a", 701) // Больше 700 символов resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": longName, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusUnprocessableEntity, resp.StatusCode) }) t.Run("InvalidStatus", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Test Quiz", "status": "invalid_status", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotAcceptable, resp.StatusCode) }) t.Run("InvalidFingerprinting", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Test Quiz", "fingerprinting": "not_boolean", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NegativeLimit", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Test Quiz", "limit": -5, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidDueTo", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Test Quiz", "due_to": "not_timestamp", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestCreateQuiz_StatusValues(t *testing.T) { statuses := []string{"draft", "template", "stop", "start"} for _, status := range statuses { t.Run("Status_"+status, func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": fmt.Sprintf("Quiz with status %s", status), "status": status, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, status, result["status"]) }) } } // отсмотрено func TestCreateQuiz_DefaultValues(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Quiz with defaults", "status": "draft", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, "draft", result["status"]) assert.Equal(t, false, result["fingerprinting"]) assert.Equal(t, false, result["repeatable"]) assert.Equal(t, false, result["note_prevented"]) assert.Equal(t, false, result["pausable"]) assert.Equal(t, false, result["super"]) } // отсмотрено func TestCreateQuiz_Conflict(t *testing.T) { resp1, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Duplicate Quiz Name", "status": "draft", "pausable": true, "time_of_passing": 0, }) assert.NoError(t, err) defer resp1.Body.Close() assert.Equal(t, http.StatusConflict, resp1.StatusCode) } // todo func TestCreateQuiz_Security(t *testing.T) { t.Run("SQLInjection", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": sqlInjectionInput, "description": sqlInjectionInput, "status": "draft", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSS", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": xssInput, "description": xssInput, "status": "draft", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestCreateQuiz_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Performance Test Quiz", "status": "draft", }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 50; i++ { wg.Add(1) go func(index int) { defer wg.Done() resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": fmt.Sprintf("Load Test Quiz %d", index), "status": "draft", }) if err == nil && resp != nil { resp.Body.Close() } }(i) } wg.Wait() }) } // отсмотрено func TestCreateQuiz_SuperQuiz(t *testing.T) { t.Run("SuperQuizWithoutGroup", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Super Quiz", "super": true, "status": "draft", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, true, result.Super) assert.Equal(t, uint64(0), result.GroupId) }) t.Run("NonSuperQuizWithGroup", func(t *testing.T) { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Group Quiz", "super": false, "group_id": 123, "status": "draft", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, false, result.Super) assert.Equal(t, uint64(123), result.GroupId) }) } func getQuizListRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/quiz/getList", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // todo чекнуть запрос в бд что то не то res [] 27 ! ? pq: argument of OFFSET must be type bigint, not type text "sessions_count": converting NULL to uint64 is unsupported func TestGetQuizList_Success(t *testing.T) { quizNames := []string{"Квиз по географии", "Квиз по истории", "Квиз по математике"} var quizIDs []uint64 for _, name := range quizNames { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": name, "status": "start", }) assert.NoError(t, err) var result model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) resp.Body.Close() assert.NoError(t, err) quizIDs = append(quizIDs, result.Id) } t.Run("BasicList", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 5, "page": 1, "status": "start", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result quiz.GetQuizListResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result.Count) assert.NotEmpty(t, result.Items) assert.LessOrEqual(t, len(result.Items), 5) if len(result.Items) > 0 { assert.NotEmpty(t, result.Items[0].Id) assert.NotEmpty(t, result.Items[0].Name) assert.NotEmpty(t, result.Items[0].Status) } }) t.Run("WithFilters", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 10, "page": 1, "search": "география", "status": "start", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) items, ok := result["items"].([]interface{}) assert.True(t, ok) for _, item := range items { quiz, ok := item.(map[string]interface{}) assert.True(t, ok) name, ok := quiz["name"].(string) assert.True(t, ok) assert.Contains(t, strings.ToLower(name), "география") } }) } // отсмотрено func TestGetQuizList_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "limit": 10, "page": 1, }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/quiz/getList", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getQuizListRequest("invalid_token", map[string]interface{}{ "limit": 10, "page": 1, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := getQuizListRequest(expiredToken, map[string]interface{}{ "limit": 10, "page": 1, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestGetQuizList_InputValidation(t *testing.T) { t.Run("InvalidLimit", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": "not_integer", "page": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidPage", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 10, "page": "not_integer", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("ZeroLimit", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 0, "page": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("ZeroPage", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 10, "page": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("InvalidFrom", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "from": "not_timestamp", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidTo", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "to": "not_timestamp", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidStatus", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "status": "invalid_status", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotAcceptable, resp.StatusCode) }) t.Run("InvalidDeleted", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "deleted": "not_boolean", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidArchived", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "archived": "not_boolean", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidSuper", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "super": "not_boolean", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidGroupID", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "group_id": "not_integer", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено // todo "sessions_count": converting NULL to uint64 is unsupported func TestGetQuizList_Pagination(t *testing.T) { for i := 0; i < 15; i++ { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": fmt.Sprintf("Pagination Test Quiz %d", i), "status": "draft", }) assert.NoError(t, err) resp.Body.Close() } t.Run("FirstPage", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 5, "page": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) items, ok := result["items"].([]interface{}) assert.True(t, ok) assert.LessOrEqual(t, len(items), 5) }) t.Run("SecondPage", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 5, "page": 2, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) items, ok := result["items"].([]interface{}) assert.True(t, ok) assert.LessOrEqual(t, len(items), 5) }) } // todo res [] 0 ! pq: syntax error in tsquery: "Filter Test" ? pq: argument of LIMIT must be type bigint, not type text func TestGetQuizList_Filters(t *testing.T) { statuses := []string{"draft", "start", "stop", "template"} for _, status := range statuses { resp, err := createQuizRequest(validToken, map[string]interface{}{ "name": fmt.Sprintf("Filter Test Quiz %s", status), "status": status, }) assert.NoError(t, err) resp.Body.Close() } t.Run("StatusFilter", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "status": "draft", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) items, ok := result["items"].([]interface{}) assert.True(t, ok) for _, item := range items { quiz, ok := item.(map[string]interface{}) assert.True(t, ok) assert.Equal(t, "draft", quiz["status"]) } }) t.Run("SearchFilter", func(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{ "search": "Filter Test", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) items, ok := result["items"].([]interface{}) assert.True(t, ok) for _, item := range items { quiz, ok := item.(map[string]interface{}) assert.True(t, ok) name, ok := quiz["name"].(string) assert.True(t, ok) assert.Contains(t, name, "Filter Test") } }) t.Run("TimeRangeFilter", func(t *testing.T) { now := time.Now().Unix() resp, err := getQuizListRequest(validToken, map[string]interface{}{ "from": now - 86400, "to": now, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) items, ok := result["items"].([]interface{}) assert.True(t, ok) assert.GreaterOrEqual(t, len(items), 0) }) } // отсмотрено func TestGetQuizList_DefaultValues(t *testing.T) { resp, err := getQuizListRequest(validToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result quiz.GetQuizListResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.LessOrEqual(t, len(result.Items), 10) } // отсмотрено func TestGetQuizList_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 10, "page": 1, }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(1000)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getQuizListRequest(validToken, map[string]interface{}{ "limit": 5, "page": 1, }) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func editQuizRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("PATCH", baseURL+"/quiz/edit", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestEditQuiz_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для редактирования", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": createResult.Id, "name": "Обновленное название квиза", "desc": "Новое описание", "status": "start", "limit": 150, "fp": true, "rep": false, "conf": "{}", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result quiz.UpdateResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, createResult.Id, result.Updated) } // отсмотрено func TestEditQuiz_OneField(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для смены статуса", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": createResult.Id, "status": "stop", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result quiz.UpdateResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, createResult.Id, result.Updated) } // отсмотрено func TestEditQuiz_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": 101, "name": "Test Quiz", }) assert.NoError(t, err) req, err := http.NewRequest("PATCH", baseURL+"/quiz/edit", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := editQuizRequest("invalid_token", map[string]interface{}{ "id": 101, "name": "Test Quiz", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := editQuizRequest(expiredToken, map[string]interface{}{ "id": 101, "name": "Test Quiz", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestEditQuiz_InputValidation(t *testing.T) { t.Run("MissingID", func(t *testing.T) { resp, err := editQuizRequest(validToken, map[string]interface{}{ "name": "Без ID", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusFailedDependency, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": "not_an_integer", "name": "Невалидный ID", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo нужен ответ 404 t.Run("NonExistentID", func(t *testing.T) { resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": 99999, "name": "Несуществующий квиз", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotFound, resp.StatusCode) }) t.Run("NameTooLong", func(t *testing.T) { longName := strings.Repeat("a", 701) resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": 101, "name": longName, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusUnprocessableEntity, resp.StatusCode) }) t.Run("InvalidStatus", func(t *testing.T) { resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": 101, "status": "invalid_status", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusNotAcceptable, resp.StatusCode) }) t.Run("InvalidFP", func(t *testing.T) { resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": 101, "fp": "not_boolean", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidLimit", func(t *testing.T) { resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": 101, "limit": -5, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // todo func TestEditQuiz_Security(t *testing.T) { t.Run("SQLInjection", func(t *testing.T) { resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": 101, "name": sqlInjectionInput, "desc": sqlInjectionInput, "conf": "{}", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("XSS", func(t *testing.T) { resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": 101, "name": xssInput, "desc": xssInput, "conf": "{}", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestEditQuiz_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": createResult.Id, "name": "Быстрое обновление", }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 50; i++ { wg.Add(1) go func(index int) { defer wg.Done() resp, err := editQuizRequest(validToken, map[string]interface{}{ "id": createResult.Id, "name": fmt.Sprintf("Load Test Quiz %d", index), }) if err == nil && resp != nil { resp.Body.Close() } assert.Equal(t, http.StatusOK, resp.StatusCode) }(i) } wg.Wait() }) } func copyQuizRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/quiz/copy", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestCopyQuiz_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Оригинальный квиз для копирования", "description": "Описание оригинала", "status": "start", "limit": 50, "config": "{}", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) resp, err := copyQuizRequest(validToken, map[string]interface{}{ "id": createResult.Id, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result quiz.UpdateResp err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEqual(t, createResult.Id, result.Updated) } // отсмотрено func TestCopyQuiz_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": 101, }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/quiz/copy", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := copyQuizRequest("invalid_token", map[string]interface{}{ "id": 101, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := copyQuizRequest(expiredToken, map[string]interface{}{ "id": 101, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestCopyQuiz_InputValidation(t *testing.T) { t.Run("MissingID", func(t *testing.T) { resp, err := copyQuizRequest(validToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusFailedDependency, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := copyQuizRequest(validToken, map[string]interface{}{ "id": "not_an_integer", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo 404 t.Run("NonExistentID", func(t *testing.T) { resp, err := copyQuizRequest(validToken, map[string]interface{}{ "id": 99999, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } // отсмотрено func TestCopyQuiz_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для копирования (перфоманс)", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := copyQuizRequest(validToken, map[string]interface{}{ "id": createResult.Id, }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := copyQuizRequest(validToken, map[string]interface{}{ "id": createResult.Id, }) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func getQuizHistoryRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/quiz/history", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } // отсмотрено func TestGetQuizHistory_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для истории", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) for i := 1; i <= 3; i++ { editResp, err := editQuizRequest(validToken, map[string]interface{}{ "id": createResult.Id, "name": fmt.Sprintf("Обновленный квиз версия %d", i), "status": "start", }) assert.NoError(t, err) editResp.Body.Close() } resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": createResult.Id, "l": 5, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result []model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) fmt.Println(result) assert.LessOrEqual(t, len(result), 5) assert.Greater(t, len(result), 0) if len(result) > 0 { firstItem := result[0] assert.Equal(t, createResult.Id, firstItem.Id) } } // отсмотрено func TestGetQuizHistory_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": 101, "l": 10, "p": 1, }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/quiz/history", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getQuizHistoryRequest("invalid_token", map[string]interface{}{ "id": 101, "l": 10, "p": 1, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := getQuizHistoryRequest(expiredToken, map[string]interface{}{ "id": 101, "l": 10, "p": 1, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } // отсмотрено func TestGetQuizHistory_InputValidation(t *testing.T) { t.Run("MissingID", func(t *testing.T) { resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "l": 10, "p": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusFailedDependency, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": "not_an_integer", "l": 10, "p": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidLimit", func(t *testing.T) { resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": 101, "l": "ten", "p": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidPage", func(t *testing.T) { resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": 101, "l": 10, "p": "one", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentID", func(t *testing.T) { resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": 99999, "l": 10, "p": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result []model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Empty(t, result) }) } // отсмотрено func TestGetQuizHistory_Pagination(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для пагинации истории", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult.Id for i := 1; i <= 15; i++ { editResp, err := editQuizRequest(validToken, map[string]interface{}{ "id": quizID, "name": fmt.Sprintf("Версия %d", i), }) assert.NoError(t, err) editResp.Body.Close() } t.Run("FirstPage", func(t *testing.T) { resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": quizID, "l": 5, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result []model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.LessOrEqual(t, len(result), 5) }) t.Run("SecondPage", func(t *testing.T) { resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": quizID, "l": 5, "p": 1, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result []model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.LessOrEqual(t, len(result), 5) }) t.Run("EmptyPage", func(t *testing.T) { resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": quizID, "l": 5, "p": 100, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result []model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Empty(t, result) }) } // отсмотрено func TestGetQuizHistory_NewQuiz(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Новый квиз для истории", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult.Id resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": quizID, "l": 5, "p": 0, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode) var result []model.Quiz err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Len(t, result, 1) // Должна быть только одна запись для нового квиза if len(result) > 0 { firstItem := result[0] assert.Equal(t, quizID, firstItem.Id) } } // отсмотрено func TestGetQuizHistory_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности истории", "status": "draft", }) assert.NoError(t, err) assert.Equal(t, http.StatusCreated, createResp.StatusCode) defer createResp.Body.Close() var createResult model.Quiz err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult.Id for i := 1; i <= 5; i++ { editResp, err := editQuizRequest(validToken, map[string]interface{}{ "id": quizID, "name": fmt.Sprintf("Версия %d", i), }) assert.NoError(t, err) assert.Equal(t, http.StatusOK, editResp.StatusCode) editResp.Body.Close() } t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": quizID, "l": 10, "p": 0, }) duration := time.Since(start) assert.NoError(t, err) assert.Equal(t, http.StatusCreated, resp.StatusCode) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("LoadTest", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getQuizHistoryRequest(validToken, map[string]interface{}{ "id": quizID, "l": 5, "p": 0, }) if err == nil && resp != nil { assert.Equal(t, http.StatusCreated, resp.StatusCode) resp.Body.Close() } }() } wg.Wait() }) } func deleteQuizRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("DELETE", baseURL+"/quiz/delete", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestDeleteQuiz_Success(t *testing.T) { createResp, err := createQuizRequest(deleteQuizToken, map[string]interface{}{ "name": "Квиз для удаления", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := deleteQuizRequest(deleteQuizToken, map[string]interface{}{ "id": quizID, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, quizID, result["deactivated"]) } func TestDeleteQuiz_Idempotency(t *testing.T) { createResp, err := createQuizRequest(deleteQuizToken, map[string]interface{}{ "name": "Квиз для идемпотентности", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp1, err := deleteQuizRequest(deleteQuizToken, map[string]interface{}{ "id": quizID, }) assert.NoError(t, err) defer resp1.Body.Close() assert.Equal(t, http.StatusOK, resp1.StatusCode) resp2, err := deleteQuizRequest(deleteQuizToken, map[string]interface{}{ "id": quizID, }) assert.NoError(t, err) defer resp2.Body.Close() assert.Equal(t, http.StatusOK, resp2.StatusCode) var result1, result2 map[string]interface{} err = json.NewDecoder(resp1.Body).Decode(&result1) assert.NoError(t, err) err = json.NewDecoder(resp2.Body).Decode(&result2) assert.NoError(t, err) assert.Equal(t, quizID, result1["deactivated"]) assert.Equal(t, quizID, result2["deactivated"]) } func TestDeleteQuiz_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": 101, }) assert.NoError(t, err) req, err := http.NewRequest("DELETE", baseURL+"/quiz/delete", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := deleteQuizRequest("invalid_token", map[string]interface{}{ "id": 101, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := deleteQuizRequest(expiredToken, map[string]interface{}{ "id": 101, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestDeleteQuiz_InputValidation(t *testing.T) { t.Run("MissingID", func(t *testing.T) { resp, err := deleteQuizRequest(deleteQuizToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := deleteQuizRequest(deleteQuizToken, map[string]interface{}{ "id": "not_an_integer", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentID", func(t *testing.T) { resp, err := deleteQuizRequest(deleteQuizToken, map[string]interface{}{ "id": 99999, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) // Идемпотентность }) } func TestDeleteQuiz_Performance(t *testing.T) { var quizIDs []interface{} for i := 0; i < 10; i++ { createResp, err := createQuizRequest(deleteQuizToken, map[string]interface{}{ "name": fmt.Sprintf("Квиз для удаления %d", i), "status": "draft", }) assert.NoError(t, err) var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) createResp.Body.Close() assert.NoError(t, err) quizIDs = append(quizIDs, createResult["id"]) } t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := deleteQuizRequest(deleteQuizToken, map[string]interface{}{ "id": quizIDs[0], }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("BulkDelete", func(t *testing.T) { var wg sync.WaitGroup for i := 1; i < len(quizIDs); i++ { wg.Add(1) go func(id interface{}) { defer wg.Done() resp, err := deleteQuizRequest(deleteQuizToken, map[string]interface{}{ "id": id, }) if err == nil && resp != nil { resp.Body.Close() } }(quizIDs[i]) } wg.Wait() }) } func archiveQuizRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("PATCH", baseURL+"/quiz/archive", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestArchiveQuiz_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для архивации", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := archiveQuizRequest(validToken, map[string]interface{}{ "id": quizID, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, quizID, result["deactivated"]) } func TestArchiveQuiz_Idempotency(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для архивации (идемпотентность)", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp1, err := archiveQuizRequest(validToken, map[string]interface{}{ "id": quizID, }) assert.NoError(t, err) defer resp1.Body.Close() assert.Equal(t, http.StatusOK, resp1.StatusCode) resp2, err := archiveQuizRequest(validToken, map[string]interface{}{ "id": quizID, }) assert.NoError(t, err) defer resp2.Body.Close() assert.Equal(t, http.StatusOK, resp2.StatusCode) var result1, result2 map[string]interface{} err = json.NewDecoder(resp1.Body).Decode(&result1) assert.NoError(t, err) err = json.NewDecoder(resp2.Body).Decode(&result2) assert.NoError(t, err) assert.Equal(t, quizID, result1["deactivated"]) assert.Equal(t, quizID, result2["deactivated"]) } func TestArchiveQuiz_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "id": 101, }) assert.NoError(t, err) req, err := http.NewRequest("PATCH", baseURL+"/quiz/archive", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := archiveQuizRequest("invalid_token", map[string]interface{}{ "id": 101, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("ExpiredToken", func(t *testing.T) { resp, err := archiveQuizRequest(expiredToken, map[string]interface{}{ "id": 101, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestArchiveQuiz_InputValidation(t *testing.T) { t.Run("MissingID", func(t *testing.T) { resp, err := archiveQuizRequest(validToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidID", func(t *testing.T) { resp, err := archiveQuizRequest(validToken, map[string]interface{}{ "id": "not_an_integer", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentID", func(t *testing.T) { resp, err := archiveQuizRequest(validToken, map[string]interface{}{ "id": 99999, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) // Идемпотентность }) } func TestArchiveQuiz_Performance(t *testing.T) { var quizIDs []interface{} for i := 0; i < 10; i++ { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": fmt.Sprintf("Квиз для архивации %d", i), "status": "draft", }) assert.NoError(t, err) var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) createResp.Body.Close() assert.NoError(t, err) quizIDs = append(quizIDs, createResult["id"]) } t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := archiveQuizRequest(validToken, map[string]interface{}{ "id": quizIDs[0], }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("BulkArchive", func(t *testing.T) { var wg sync.WaitGroup for i := 1; i < len(quizIDs); i++ { wg.Add(1) go func(id interface{}) { defer wg.Done() resp, err := archiveQuizRequest(validToken, map[string]interface{}{ "id": id, }) if err == nil && resp != nil { resp.Body.Close() } }(quizIDs[i]) } wg.Wait() }) } func TestMoveQuiz_BoundaryCases(t *testing.T) { t.Run("EmptyQIDAndAccountID", func(t *testing.T) { resp, err := moveQuizRequest(validToken, map[string]interface{}{ "qid": "", "accountID": "", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("LongQIDAndAccountID", func(t *testing.T) { longStr := make([]byte, 1025) for i := range longStr { longStr[i] = 'a' } resp, err := moveQuizRequest(validToken, map[string]interface{}{ "qid": string(longStr), "accountID": string(longStr), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } func TestMoveQuiz_ErrorHandling(t *testing.T) { t.Run("MalformedJSON", func(t *testing.T) { req, err := http.NewRequest("POST", baseURL+"/quiz/move", bytes.NewReader([]byte("{invalid_json}"))) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } func moveQuizRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/quiz/move", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestMoveQuiz_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для переноса", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizQID := createResult["qid"] resp, err := moveQuizRequest(validToken, map[string]interface{}{ "qid": quizQID, "accountID": "new-account-id", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) } func TestMoveQuiz_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "qid": "test-qid", "accountID": "new-account", }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/quiz/move", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := moveQuizRequest("invalid_token", map[string]interface{}{ "qid": "test-qid", "accountID": "new-account", }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestMoveQuiz_InputValidation(t *testing.T) { t.Run("MissingQID", func(t *testing.T) { resp, err := moveQuizRequest(validToken, map[string]interface{}{ "accountID": "new-account", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("MissingAccountID", func(t *testing.T) { resp, err := moveQuizRequest(validToken, map[string]interface{}{ "qid": "test-qid", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentQID", func(t *testing.T) { resp, err := moveQuizRequest(validToken, map[string]interface{}{ "qid": "non-existent-qid", "accountID": "new-account", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentAccountID", func(t *testing.T) { resp, err := moveQuizRequest(validToken, map[string]interface{}{ "qid": "test-qid", "accountID": "non-existent-account", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } func TestMoveQuiz_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности переноса", "status": "draft", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizQID := createResult["qid"] t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := moveQuizRequest(validToken, map[string]interface{}{ "qid": quizQID, "accountID": "performance-test-account", }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) } func TestCreateQuizTemplate_BoundaryCases(t *testing.T) { t.Run("ManyRequests", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := createQuizTemplateRequest(validToken) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func createQuizTemplateRequest(token string) (*http.Response, error) { req, err := http.NewRequest("POST", baseURL+"/quiz/template", nil) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestCreateQuizTemplate_Success(t *testing.T) { resp, err := createQuizTemplateRequest(validToken) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result["id"]) assert.IsType(t, float64(0), result["id"]) } func TestCreateQuizTemplate_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { req, err := http.NewRequest("POST", baseURL+"/quiz/template", nil) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := createQuizTemplateRequest("invalid_token") assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestCreateQuizTemplate_Performance(t *testing.T) { t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := createQuizTemplateRequest(validToken) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("MultipleTemplates", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := createQuizTemplateRequest(validToken) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func getResultsRequest(token string, quizId string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/results/getResults/"+quizId, bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestGetResults_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotNil(t, result["total_count"]) assert.NotNil(t, result["results"]) } func TestGetResults_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/results/getResults/12345", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getResultsRequest("invalid_token", "12345", map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestGetResults_InputValidation(t *testing.T) { t.Run("InvalidQuizID", func(t *testing.T) { resp, err := getResultsRequest(validToken, "invalid-quiz-id", map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentQuizID", func(t *testing.T) { resp, err := getResultsRequest(validToken, "99999", map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.Equal(t, float64(0), result["total_count"]) assert.Empty(t, result["results"]) }) } // todo func TestGetResults_Pagination(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для пагинации результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("FirstPage", func(t *testing.T) { resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 5, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) //results := result["results"].([]interface{}) //assert.LessOrEqual(t, len(results), 5) }) t.Run("SecondPage", func(t *testing.T) { resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 2, "Limit": 5, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("EmptyPage", func(t *testing.T) { resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 100, "Limit": 5, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) //results := result["results"].([]interface{}) //assert.Empty(t, results) }) } func TestGetResults_Filtering(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для фильтрации результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("WithDateRange", func(t *testing.T) { resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": "2023-01-01", "To": "2023-12-31", "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("NewResultsOnly", func(t *testing.T) { resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "New": true, "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } func TestGetResults_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 10, }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("ConcurrentRequests", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 5, }) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func TestGetResults_ErrorHandling(t *testing.T) { t.Run("MalformedJSON", func(t *testing.T) { req, err := http.NewRequest("POST", baseURL+"/results/getResults/12345", bytes.NewReader([]byte("{invalid_json}"))) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("ServerError", func(t *testing.T) { // Тестируем с некорректным quizId, который может вызвать серверную ошибку resp, err := getResultsRequest(validToken, "invalid-id", map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusOK, resp.StatusCode) }) } func deleteResultRequest(token string, resultId string) (*http.Response, error) { req, err := http.NewRequest("DELETE", baseURL+"/results/"+resultId, nil) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestDeleteResult_Success(t *testing.T) { createResp, err := createQuizRequest(deleteResultToken, map[string]interface{}{ "name": "Квиз для удаления результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] getResultsResp, err := getResultsRequest(deleteResultToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer getResultsResp.Body.Close() var resultsData map[string]interface{} err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData) assert.NoError(t, err) //results := resultsData["results"].([]interface{}) //if len(results) > 0 { // firstResult := results[0].(map[string]interface{}) // resultID := fmt.Sprintf("%v", firstResult["id"]) // // resp, err := deleteResultRequest(deleteResultToken, resultID) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) //} } func TestDeleteResult_Idempotency(t *testing.T) { createResp, err := createQuizRequest(deleteResultToken, map[string]interface{}{ "name": "Квиз для идемпотентности удаления результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] getResultsResp, err := getResultsRequest(deleteResultToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 5, }) assert.NoError(t, err) defer getResultsResp.Body.Close() var resultsData map[string]interface{} err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData) assert.NoError(t, err) //results := resultsData["results"].([]interface{}) // //if len(results) > 0 { // firstResult := results[0].(map[string]interface{}) // resultID := fmt.Sprintf("%v", firstResult["id"]) // // resp1, err := deleteResultRequest(deleteResultToken, resultID) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // resp2, err := deleteResultRequest(deleteResultToken, resultID) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) //} } func TestDeleteResult_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { req, err := http.NewRequest("DELETE", baseURL+"/results/123456", nil) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := deleteResultRequest("invalid_token", "123456") assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestDeleteResult_InputValidation(t *testing.T) { t.Run("InvalidResultID", func(t *testing.T) { resp, err := deleteResultRequest(deleteResultToken, "not_a_number") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentResultID", func(t *testing.T) { resp, err := deleteResultRequest(deleteResultToken, "99999999") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } func TestDeleteResult_Performance(t *testing.T) { createResp, err := createQuizRequest(deleteResultToken, map[string]interface{}{ "name": "Квиз для теста производительности удаления результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] getResultsResp, err := getResultsRequest(deleteResultToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer getResultsResp.Body.Close() var resultsData map[string]interface{} err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData) assert.NoError(t, err) //results := resultsData["results"].([]interface{}) // //if len(results) > 0 { // firstResult := results[0].(map[string]interface{}) // resultID := fmt.Sprintf("%v", firstResult["id"]) // // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := deleteResultRequest(deleteResultToken, resultID) // duration := time.Since(start) // // assert.NoError(t, err) // defer resp.Body.Close() // assert.Less(t, duration.Milliseconds(), int64(500)) // }) //} t.Run("BulkDelete", func(t *testing.T) { getMoreResultsResp, err := getResultsRequest(deleteResultToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 20, }) assert.NoError(t, err) defer getMoreResultsResp.Body.Close() var moreResultsData map[string]interface{} err = json.NewDecoder(getMoreResultsResp.Body).Decode(&moreResultsData) assert.NoError(t, err) //moreResults := moreResultsData["results"].([]interface{}) // //var wg sync.WaitGroup //for i := 0; i < len(moreResults) && i < 5; i++ { // wg.Add(1) // go func(result interface{}) { // defer wg.Done() // resultMap := result.(map[string]interface{}) // resultID := fmt.Sprintf("%v", resultMap["id"]) // resp, err := deleteResultRequest(deleteResultToken, resultID) // if err == nil && resp != nil { // resp.Body.Close() // } // }(moreResults[i]) //} //wg.Wait() }) } func TestDeleteResult_BoundaryCases(t *testing.T) { t.Run("VeryLongResultID", func(t *testing.T) { longID := make([]byte, 1025) for i := range longID { longID[i] = '1' } resp, err := deleteResultRequest(deleteResultToken, string(longID)) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NegativeResultID", func(t *testing.T) { resp, err := deleteResultRequest(deleteResultToken, "-123") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } func TestDeleteResult_ErrorHandling(t *testing.T) { t.Run("MalformedRequest", func(t *testing.T) { req, err := http.NewRequest("DELETE", baseURL+"/results/invalid-id", bytes.NewReader([]byte("invalid_body"))) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+deleteResultToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusOK, resp.StatusCode) }) t.Run("ServerError", func(t *testing.T) { resp, err := deleteResultRequest(deleteResultToken, "invalid-id") assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusOK, resp.StatusCode) }) } func updateResultsStatusRequest(token string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("PATCH", baseURL+"/result/seen", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestUpdateResultsStatus_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для обновления статуса результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer getResultsResp.Body.Close() var resultsData map[string]interface{} err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData) assert.NoError(t, err) //results := resultsData["results"].([]interface{}) // //if len(results) >= 3 { // var answerIDs []int64 // for i := 0; i < 3; i++ { // result := results[i].(map[string]interface{}) // answerIDs = append(answerIDs, int64(result["id"].(float64))) // } // // resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ // "Answers": answerIDs, // }) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) //} } func TestUpdateResultsStatus_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "Answers": []int64{101, 102, 103}, }) assert.NoError(t, err) req, err := http.NewRequest("PATCH", baseURL+"/result/seen", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := updateResultsStatusRequest("invalid_token", map[string]interface{}{ "Answers": []int64{101, 102, 103}, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestUpdateResultsStatus_InputValidation(t *testing.T) { t.Run("MissingAnswers", func(t *testing.T) { resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("EmptyAnswers", func(t *testing.T) { resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ "Answers": []int64{}, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidAnswersType", func(t *testing.T) { resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ "Answers": "not_an_array", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentAnswers", func(t *testing.T) { resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ "Answers": []int64{999999, 999998, 999997}, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) // Идемпотентность }) } func TestUpdateResultsStatus_Idempotency(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для идемпотентности обновления статуса", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 5, }) assert.NoError(t, err) defer getResultsResp.Body.Close() var resultsData map[string]interface{} err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData) assert.NoError(t, err) //results := resultsData["results"].([]interface{}) // //if len(results) >= 2 { // var answerIDs []int64 // for i := 0; i < 2; i++ { // result := results[i].(map[string]interface{}) // answerIDs = append(answerIDs, int64(result["id"].(float64))) // } // // resp1, err := updateResultsStatusRequest(validToken, map[string]interface{}{ // "Answers": answerIDs, // }) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // resp2, err := updateResultsStatusRequest(validToken, map[string]interface{}{ // "Answers": answerIDs, // }) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) //} } func TestUpdateResultsStatus_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности обновления статуса", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 20, }) assert.NoError(t, err) defer getResultsResp.Body.Close() var resultsData map[string]interface{} err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData) assert.NoError(t, err) //results := resultsData["results"].([]interface{}) // //if len(results) > 0 { // var answerIDs []int64 // for i := 0; i < len(results) && i < 10; i++ { // result := results[i].(map[string]interface{}) // answerIDs = append(answerIDs, int64(result["id"].(float64))) // } // // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ // "Answers": answerIDs, // }) // duration := time.Since(start) // // assert.NoError(t, err) // defer resp.Body.Close() // assert.Less(t, duration.Milliseconds(), int64(500)) // }) // // t.Run("LargeBatch", func(t *testing.T) { // largeBatch := make([]int64, 100) // for i := 0; i < 100; i++ { // largeBatch[i] = int64(1000000 + i) // Используем несуществующие ID // } // // resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ // "Answers": largeBatch, // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // }) //} } func TestUpdateResultsStatus_BoundaryCases(t *testing.T) { t.Run("VeryLargeAnswersArray", func(t *testing.T) { largeAnswers := make([]int64, 10000) for i := 0; i < 10000; i++ { largeAnswers[i] = int64(1000000 + i) } resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ "Answers": largeAnswers, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("NegativeAnswerIDs", func(t *testing.T) { resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ "Answers": []int64{-1, -2, -3}, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } func TestUpdateResultsStatus_ErrorHandling(t *testing.T) { t.Run("MalformedJSON", func(t *testing.T) { req, err := http.NewRequest("PATCH", baseURL+"/result/seen", bytes.NewReader([]byte("{invalid_json}"))) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("ServerError", func(t *testing.T) { resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ "Answers": "not_an_array", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } func TestUpdateResultsStatus_SpecialCases(t *testing.T) { t.Run("DuplicateAnswerIDs", func(t *testing.T) { resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{ "Answers": []int64{101, 101, 102, 102, 103}, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } func exportResultsRequest(token string, quizID string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/results/"+quizID+"/export", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestExportResults_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для экспорта результатов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": "2023-01-01T00:00:00Z", "To": "2023-12-31T23:59:59Z", "New": false, "Page": 1, "Limit": 100, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", resp.Header.Get("Content-Type")) } func TestExportResults_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/results/123/export", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := exportResultsRequest("invalid_token", "123", map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestExportResults_InputValidation(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для валидации экспорта", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("InvalidDateFormat", func(t *testing.T) { resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": "not-a-date", }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidQuizID", func(t *testing.T) { resp, err := exportResultsRequest(validToken, "invalid-quiz-id", map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentQuizID", func(t *testing.T) { resp, err := exportResultsRequest(validToken, "99999", map[string]interface{}{ "Page": 1, "Limit": 10, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) // Возвращает пустой файл }) } // todo nned check //func TestExportResults_Performance(t *testing.T) { // // Создаем квиз для тестирования производительности // createResp, err := createQuizRequest(validToken, map[string]interface{}{ // "name": "Квиз для теста производительности экспорта", // "status": "start", // }) // assert.NoError(t, err) // defer createResp.Body.Close() // var createResult map[string]interface{} // err = json.NewDecoder(createResp.Body).Decode(&createResult) // assert.NoError(t, err) // quizID := createResult["id"] // // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "Page": 1, // "Limit": 100, // }) // duration := time.Since(start) // // assert.NoError(t, err) // defer resp.Body.Close() // assert.Less(t, duration.Milliseconds(), int64(2000)) // Экспорт может занимать больше времени // }) // // t.Run("LargeExport", func(t *testing.T) { // resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "Page": 1, // "Limit": 1000, // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // }) //} // //func TestExportResults_BoundaryCases(t *testing.T) { // t.Run("VeryLargeLimit", func(t *testing.T) { // // Создаем квиз для тестирования // createResp, err := createQuizRequest(validToken, map[string]interface{}{ // "name": "Квиз для граничных случаев экспорта", // "status": "start", // }) // assert.NoError(t, err) // defer createResp.Body.Close() // var createResult map[string]interface{} // err = json.NewDecoder(createResp.Body).Decode(&createResult) // assert.NoError(t, err) // quizID := createResult["id"] // // resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "Page": 1, // "Limit": 100000, // Очень большой лимит // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // }) // // t.Run("VeryOldDateRange", func(t *testing.T) { // // Создаем квиз для тестирования // createResp, err := createQuizRequest(validToken, map[string]interface{}{ // "name": "Квиз для старых дат экспорта", // "status": "start", // }) // assert.NoError(t, err) // defer createResp.Body.Close() // var createResult map[string]interface{} // err = json.NewDecoder(createResp.Body).Decode(&createResult) // assert.NoError(t, err) // quizID := createResult["id"] // // resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "From": "1900-01-01T00:00:00Z", // "To": "1950-12-31T23:59:59Z", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // }) //} // //func TestExportResults_ErrorHandling(t *testing.T) { // t.Run("MalformedJSON", func(t *testing.T) { // req, err := http.NewRequest("POST", baseURL+"/results/123/export", bytes.NewReader([]byte("{invalid_json}"))) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validToken) // req.Header.Set("Content-Type", "application/json") // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("ServerError", func(t *testing.T) { // // Тестируем с некорректным quizId, который может вызвать серверную ошибку // resp, err := exportResultsRequest(validToken, "invalid-id", map[string]interface{}{ // "Page": 1, // "Limit": 10, // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) //} // //func TestExportResults_AuditMetricsConsistency(t *testing.T) { // t.Run("AuditLog", func(t *testing.T) { // // Создаем квиз для тестирования аудита // createResp, err := createQuizRequest(validToken, map[string]interface{}{ // "name": "Квиз для аудита экспорта", // "status": "start", // }) // assert.NoError(t, err) // defer createResp.Body.Close() // var createResult map[string]interface{} // err = json.NewDecoder(createResp.Body).Decode(&createResult) // assert.NoError(t, err) // quizID := createResult["id"] // // resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "Page": 1, // "Limit": 50, // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // Здесь можно добавить проверку на появление записи аудита, если есть доступ к логам/БД // }) // // t.Run("Consistency", func(t *testing.T) { // // Проверяем консистентность данных при повторных экспортах // createResp, err := createQuizRequest(validToken, map[string]interface{}{ // "name": "Квиз для консистентности экспорта", // "status": "start", // }) // assert.NoError(t, err) // defer createResp.Body.Close() // var createResult map[string]interface{} // err = json.NewDecoder(createResp.Body).Decode(&createResult) // assert.NoError(t, err) // quizID := createResult["id"] // // // Первый экспорт // resp1, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "Page": 1, // "Limit": 10, // }) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // // Второй экспорт с теми же параметрами // resp2, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "Page": 1, // "Limit": 10, // }) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) // // // Проверяем, что размеры файлов одинаковые (консистентность) // body1, err := io.ReadAll(resp1.Body) // assert.NoError(t, err) // body2, err := io.ReadAll(resp2.Body) // assert.NoError(t, err) // assert.Equal(t, len(body1), len(body2)) // }) //} // //func TestExportResults_IdempotencyAndTransactions(t *testing.T) { // t.Run("Idempotency", func(t *testing.T) { // // Создаем квиз для тестирования идемпотентности // createResp, err := createQuizRequest(validToken, map[string]interface{}{ // "name": "Квиз для идемпотентности экспорта", // "status": "start", // }) // assert.NoError(t, err) // defer createResp.Body.Close() // var createResult map[string]interface{} // err = json.NewDecoder(createResp.Body).Decode(&createResult) // assert.NoError(t, err) // quizID := createResult["id"] // // // Первый экспорт // resp1, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "Page": 1, // "Limit": 5, // }) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // // Повторный экспорт с теми же параметрами // resp2, err := exportResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ // "Page": 1, // "Limit": 5, // }) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) // assert.Equal(t, resp1.StatusCode, resp2.StatusCode) // }) // // t.Run("TransactionRollback", func(t *testing.T) { // // Пытаемся экспортировать результаты несуществующего квиза // resp, err := exportResultsRequest(validToken, "999999", map[string]interface{}{ // "Page": 1, // "Limit": 10, // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // // Проверяем, что файл пустой или содержит заголовки // body, err := io.ReadAll(resp.Body) // assert.NoError(t, err) // // Файл может быть пустым или содержать только заголовки // assert.NotNil(t, body) // }) //} func getResultRequest(token string, resultID string) (*http.Response, error) { req, err := http.NewRequest("GET", baseURL+"/result/"+resultID, nil) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestGetResult_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для получения результата", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 5, }) assert.NoError(t, err) defer getResultsResp.Body.Close() var resultsData map[string]interface{} err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData) assert.NoError(t, err) //results := resultsData["results"].([]interface{}) // //if len(results) > 0 { // firstResult := results[0].(map[string]interface{}) // resultID := fmt.Sprintf("%v", firstResult["id"]) // // resp, err := getResultRequest(validToken, resultID) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // // var answers []map[string]interface{} // err = json.NewDecoder(resp.Body).Decode(&answers) // assert.NoError(t, err) // // if len(answers) > 0 { // answer := answers[0] // assert.NotEmpty(t, answer["Id"]) // assert.NotEmpty(t, answer["content"]) // assert.NotEmpty(t, answer["question_id"]) // assert.NotEmpty(t, answer["QuizId"]) // assert.NotEmpty(t, answer["CreatedAt"]) // assert.IsType(t, false, answer["Result"]) // assert.IsType(t, false, answer["new"]) // assert.IsType(t, false, answer["Deleted"]) // assert.IsType(t, false, answer["Start"]) // } //} } func TestGetResult_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/result/abc123xyz", nil) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getResultRequest("invalid_token", "abc123xyz") assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestGetResult_InputValidation(t *testing.T) { t.Run("EmptyResultID", func(t *testing.T) { resp, err := getResultRequest(validToken, "") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentResultID", func(t *testing.T) { resp, err := getResultRequest(validToken, "nonexistent123") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var answers []map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&answers) assert.NoError(t, err) assert.Empty(t, answers) }) t.Run("InvalidResultID", func(t *testing.T) { resp, err := getResultRequest(validToken, "invalid-result-id!") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } func TestGetResult_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности результата", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "Page": 1, "Limit": 1, }) assert.NoError(t, err) defer getResultsResp.Body.Close() var resultsData map[string]interface{} err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData) assert.NoError(t, err) //results := resultsData["results"].([]interface{}) // //if len(results) > 0 { // firstResult := results[0].(map[string]interface{}) // resultID := fmt.Sprintf("%v", firstResult["id"]) // // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := getResultRequest(validToken, resultID) // duration := time.Since(start) // // assert.NoError(t, err) // defer resp.Body.Close() // assert.Less(t, duration.Milliseconds(), int64(500)) // }) //} } func TestGetResult_BoundaryCases(t *testing.T) { t.Run("VeryLongResultID", func(t *testing.T) { longID := make([]byte, 1025) for i := range longID { longID[i] = 'a' } resp, err := getResultRequest(validToken, string(longID)) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NegativeResultID", func(t *testing.T) { resp, err := getResultRequest(validToken, "-123") assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) // todo //t.Run("SpecialCharactersInResultID", func(t *testing.T) { // resp, err := getResultRequest(validToken, "result@#$%^&*()") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) //}) } func TestGetResult_ErrorHandling(t *testing.T) { t.Run("MalformedRequest", func(t *testing.T) { req, err := http.NewRequest("GET", baseURL+"/result/invalid-id", bytes.NewReader([]byte("invalid_body"))) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusOK, resp.StatusCode) }) t.Run("ServerError", func(t *testing.T) { resp, err := getResultRequest(validToken, "invalid-id") assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusOK, resp.StatusCode) }) } func getDeviceStatsRequest(token string, quizID string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/statistic/"+quizID+"/devices", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestGetDeviceStats_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для статистики устройств", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotNil(t, result["Device"]) assert.NotNil(t, result["OS"]) assert.NotNil(t, result["Browser"]) deviceStats := result["Device"].(map[string]interface{}) osStats := result["OS"].(map[string]interface{}) browserStats := result["Browser"].(map[string]interface{}) for _, value := range deviceStats { assert.IsType(t, float64(0), value) } for _, value := range osStats { assert.IsType(t, float64(0), value) } for _, value := range browserStats { assert.IsType(t, float64(0), value) } } func TestGetDeviceStats_WithoutDateRange(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для статистики без диапазона дат", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotNil(t, result["Device"]) assert.NotNil(t, result["OS"]) assert.NotNil(t, result["Browser"]) } func TestGetDeviceStats_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/statistic/12345/devices", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getDeviceStatsRequest("invalid_token", "12345", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestGetDeviceStats_InputValidation(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для валидации статистики устройств", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("InvalidDateFormat", func(t *testing.T) { resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": "not_a_timestamp", "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidQuizID", func(t *testing.T) { resp, err := getDeviceStatsRequest(validToken, "invalid-quiz-id", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentQuizID", func(t *testing.T) { resp, err := getDeviceStatsRequest(validToken, "99999", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) deviceStats := result["Device"].(map[string]interface{}) osStats := result["OS"].(map[string]interface{}) browserStats := result["Browser"].(map[string]interface{}) assert.Empty(t, deviceStats) assert.Empty(t, osStats) assert.Empty(t, browserStats) }) } func TestGetDeviceStats_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности статистики устройств", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("ConcurrentRequests", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func TestGetDeviceStats_ErrorHandling(t *testing.T) { t.Run("MalformedJSON", func(t *testing.T) { req, err := http.NewRequest("POST", baseURL+"/statistic/12345/devices", bytes.NewReader([]byte("{invalid_json}"))) assert.NoError(t, err) req.Header.Set("Authorization", "Bearer "+validToken) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("ServerError", func(t *testing.T) { resp, err := getDeviceStatsRequest(validToken, "invalid-id", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.NotEqual(t, http.StatusOK, resp.StatusCode) }) } func getGeneralStatsRequest(token string, quizID string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/statistic/"+quizID+"/general", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestGetGeneralStats_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для общей статистики", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotNil(t, result["Open"]) assert.NotNil(t, result["Result"]) assert.NotNil(t, result["AvTime"]) assert.NotNil(t, result["Conversion"]) openStats := result["Open"].(map[string]interface{}) resultStats := result["Result"].(map[string]interface{}) avTimeStats := result["AvTime"].(map[string]interface{}) conversionStats := result["Conversion"].(map[string]interface{}) for _, value := range openStats { assert.IsType(t, float64(0), value) assert.GreaterOrEqual(t, value.(float64), float64(0)) } for _, value := range resultStats { assert.IsType(t, float64(0), value) assert.GreaterOrEqual(t, value.(float64), float64(0)) } for _, value := range avTimeStats { assert.IsType(t, float64(0), value) assert.GreaterOrEqual(t, value.(float64), float64(0)) } for _, value := range conversionStats { assert.IsType(t, float64(0), value) assert.GreaterOrEqual(t, value.(float64), float64(0)) assert.LessOrEqual(t, value.(float64), float64(100)) } } func TestGetGeneralStats_WithoutDateRange(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для общей статистики без диапазона", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotNil(t, result["Open"]) assert.NotNil(t, result["Result"]) assert.NotNil(t, result["AvTime"]) assert.NotNil(t, result["Conversion"]) } func TestGetGeneralStats_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/statistic/12345/general", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getGeneralStatsRequest("invalid_token", "12345", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestGetGeneralStats_InputValidation(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для валидации общей статистики", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("InvalidDateFormat", func(t *testing.T) { resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": "not_a_timestamp", "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidQuizID", func(t *testing.T) { resp, err := getGeneralStatsRequest(validToken, "invalid-quiz-id", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentQuizID", func(t *testing.T) { resp, err := getGeneralStatsRequest(validToken, "99999", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) openStats := result["Open"].(map[string]interface{}) resultStats := result["Result"].(map[string]interface{}) avTimeStats := result["AvTime"].(map[string]interface{}) conversionStats := result["Conversion"].(map[string]interface{}) assert.Empty(t, openStats) assert.Empty(t, resultStats) assert.Empty(t, avTimeStats) assert.Empty(t, conversionStats) }) } func TestGetGeneralStats_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности общей статистики", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("ConcurrentRequests", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func TestGetGeneralStats_BoundaryCases(t *testing.T) { t.Run("VeryLargeDateRange", func(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для граничных случаев общей статистики", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": 0, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("NegativeTimestamps", func(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для отрицательных временных меток", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": -1000000, "To": -500000, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } func getQuestionStatsRequest(token string, quizID string, body map[string]interface{}) (*http.Response, error) { payload, err := json.Marshal(body) if err != nil { return nil, err } req, err := http.NewRequest("POST", baseURL+"/statistic/"+quizID+"/questions", bytes.NewReader(payload)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) } func TestGetQuestionStats_Success(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для статистики вопросов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result []map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result) if len(result) > 0 { questionStat := result[0] assert.NotNil(t, questionStat["Funnel"]) assert.NotNil(t, questionStat["FunnelData"]) assert.NotNil(t, questionStat["Results"]) assert.NotNil(t, questionStat["Questions"]) funnel := questionStat["Funnel"].([]interface{}) funnelData := questionStat["FunnelData"].([]interface{}) results := questionStat["Results"].(map[string]interface{}) questions := questionStat["Questions"].(map[string]interface{}) assert.LessOrEqual(t, len(funnel), 3) assert.LessOrEqual(t, len(funnelData), 4) for _, value := range funnel { assert.IsType(t, float64(0), value) assert.GreaterOrEqual(t, value.(float64), float64(0)) assert.LessOrEqual(t, value.(float64), float64(100)) } for _, value := range funnelData { assert.IsType(t, float64(0), value) assert.GreaterOrEqual(t, value.(float64), float64(0)) } for _, value := range results { assert.IsType(t, float64(0), value) assert.GreaterOrEqual(t, value.(float64), float64(0)) assert.LessOrEqual(t, value.(float64), float64(100)) } for _, questionData := range questions { questionMap := questionData.(map[string]interface{}) for _, percentage := range questionMap { assert.IsType(t, float64(0), percentage) assert.GreaterOrEqual(t, percentage.(float64), float64(0)) assert.LessOrEqual(t, percentage.(float64), float64(100)) } } } } func TestGetQuestionStats_WithoutDateRange(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для статистики вопросов без диапазона", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{}) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) var result []map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result) } func TestGetQuestionStats_Auth(t *testing.T) { t.Run("NoToken", func(t *testing.T) { payload, err := json.Marshal(map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) req, err := http.NewRequest("POST", baseURL+"/statistic/12345/questions", bytes.NewReader(payload)) assert.NoError(t, err) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) t.Run("InvalidToken", func(t *testing.T) { resp, err := getQuestionStatsRequest("invalid_token", "12345", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }) } func TestGetQuestionStats_InputValidation(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для валидации статистики вопросов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("InvalidDateFormat", func(t *testing.T) { resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": "not_a_timestamp", "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("InvalidQuizID", func(t *testing.T) { resp, err := getQuestionStatsRequest(validToken, "invalid-quiz-id", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("NonExistentQuizID", func(t *testing.T) { resp, err := getQuestionStatsRequest(validToken, "99999", map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) var result []map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) assert.NoError(t, err) assert.NotEmpty(t, result) if len(result) > 0 { questionStat := result[0] funnel := questionStat["Funnel"].([]interface{}) funnelData := questionStat["FunnelData"].([]interface{}) results := questionStat["Results"].(map[string]interface{}) questions := questionStat["Questions"].(map[string]interface{}) assert.Empty(t, funnel) assert.Empty(t, funnelData) assert.Empty(t, results) assert.Empty(t, questions) } }) } func TestGetQuestionStats_Performance(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для теста производительности статистики вопросов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] t.Run("ResponseTime", func(t *testing.T) { start := time.Now() resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) duration := time.Since(start) assert.NoError(t, err) defer resp.Body.Close() assert.Less(t, duration.Milliseconds(), int64(500)) }) t.Run("ConcurrentRequests", func(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": time.Now().Unix() - 100, "To": time.Now().Unix(), }) if err == nil && resp != nil { resp.Body.Close() } }() } wg.Wait() }) } func TestGetQuestionStats_BoundaryCases(t *testing.T) { t.Run("VeryLargeDateRange", func(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для граничных случаев статистики вопросов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": 0, "To": time.Now().Unix(), }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) t.Run("NegativeTimestamps", func(t *testing.T) { createResp, err := createQuizRequest(validToken, map[string]interface{}{ "name": "Квиз для отрицательных временных меток вопросов", "status": "start", }) assert.NoError(t, err) defer createResp.Body.Close() var createResult map[string]interface{} err = json.NewDecoder(createResp.Body).Decode(&createResult) assert.NoError(t, err) quizID := createResult["id"] resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{ "From": -1000000, "To": -500000, }) assert.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) } // todo ПРОПУСК 35 36 тест кесов // todo ждет когда будет применятся //func getTelegramPoolRequest(token string) (*http.Response, error) { // req, err := http.NewRequest("GET", baseURL+"/telegram/pool", nil) // if err != nil { // return nil, err // } // req.Header.Set("Authorization", "Bearer "+token) // req.Header.Set("Content-Type", "application/json") // return http.DefaultClient.Do(req) //} // //func TestGetTelegramPool_Success(t *testing.T) { // resp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // // var accounts []map[string]interface{} // err = json.NewDecoder(resp.Body).Decode(&accounts) // assert.NoError(t, err) // // for _, account := range accounts { // assert.NotEmpty(t, account["ID"]) // assert.NotEmpty(t, account["ApiID"]) // assert.NotEmpty(t, account["ApiHash"]) // assert.NotEmpty(t, account["PhoneNumber"]) // assert.NotEmpty(t, account["Status"]) // assert.NotEmpty(t, account["CreatedAt"]) // // assert.IsType(t, float64(0), account["ID"]) // assert.IsType(t, float64(0), account["ApiID"]) // assert.IsType(t, "", account["ApiHash"]) // assert.IsType(t, "", account["PhoneNumber"]) // assert.IsType(t, "", account["Status"]) // assert.IsType(t, "", account["CreatedAt"]) // assert.IsType(t, false, account["Deleted"]) // // assert.Equal(t, false, account["Deleted"]) // // status := account["Status"].(string) // assert.Contains(t, []string{"active", "inactive", "ban"}, status) // // createdAt := account["CreatedAt"].(string) // _, err := time.Parse(time.RFC3339, createdAt) // assert.NoError(t, err) // } //} // //func TestGetTelegramPool_Auth(t *testing.T) { // t.Run("NoToken", func(t *testing.T) { // req, err := http.NewRequest("GET", baseURL+"/telegram/pool", nil) // assert.NoError(t, err) // req.Header.Set("Content-Type", "application/json") // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("InvalidToken", func(t *testing.T) { // resp, err := getTelegramPoolRequest("invalid_token") // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("ExpiredToken", func(t *testing.T) { // resp, err := getTelegramPoolRequest(expiredToken) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) //} // //func TestGetTelegramPool_Security(t *testing.T) { // t.Run("SQLInjectionAttempt", func(t *testing.T) { // resp, err := getTelegramPoolRequest("' OR 1=1 --") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("XSSAttempt", func(t *testing.T) { // resp, err := getTelegramPoolRequest("") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) //} // //func TestGetTelegramPool_Performance(t *testing.T) { // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := getTelegramPoolRequest(validToken) // duration := time.Since(start) // // assert.NoError(t, err) // defer resp.Body.Close() // assert.Less(t, duration.Milliseconds(), int64(1000)) // Менее 1 секунды // }) // // t.Run("ConcurrentRequests", func(t *testing.T) { // var wg sync.WaitGroup // for i := 0; i < 10; i++ { // wg.Add(1) // go func() { // defer wg.Done() // resp, err := getTelegramPoolRequest(validToken) // if err == nil && resp != nil { // resp.Body.Close() // } // }() // } // wg.Wait() // }) //} // //func TestGetTelegramPool_BoundaryCases(t *testing.T) { // t.Run("EmptyPool", func(t *testing.T) { // resp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // var accounts []map[string]interface{} // err = json.NewDecoder(resp.Body).Decode(&accounts) // assert.NoError(t, err) // assert.NotNil(t, accounts) // }) // // t.Run("LargePool", func(t *testing.T) { // resp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // var accounts []map[string]interface{} // err = json.NewDecoder(resp.Body).Decode(&accounts) // assert.NoError(t, err) // // Проверяем, что система может обработать большое количество аккаунтов // assert.NotNil(t, accounts) // }) //} // //func TestGetTelegramPool_ErrorHandling(t *testing.T) { // t.Run("MalformedRequest", func(t *testing.T) { // // Тестируем с некорректным запросом // req, err := http.NewRequest("GET", baseURL+"/telegram/pool", bytes.NewReader([]byte("invalid_body"))) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validToken) // req.Header.Set("Content-Type", "application/json") // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) // // t.Run("ServerError", func(t *testing.T) { // // Тестируем с некорректным токеном, который может вызвать серверную ошибку // resp, err := getTelegramPoolRequest("invalid-token-with-special-chars@#$%") // assert.NoError(t, err) // defer resp.Body.Close() // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) //} // //func TestGetTelegramPool_AuditMetricsConsistency(t *testing.T) { // t.Run("AuditLog", func(t *testing.T) { // resp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // Здесь можно добавить проверку на появление записи аудита, если есть доступ к логам/БД // }) // // t.Run("Consistency", func(t *testing.T) { // // Проверяем консистентность данных при повторных запросах // // Первый запрос // resp1, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // // Второй запрос с теми же параметрами // resp2, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) // // // Проверяем, что результаты консистентны // var accounts1, accounts2 []map[string]interface{} // err = json.NewDecoder(resp1.Body).Decode(&accounts1) // assert.NoError(t, err) // err = json.NewDecoder(resp2.Body).Decode(&accounts2) // assert.NoError(t, err) // assert.Equal(t, len(accounts1), len(accounts2)) // }) //} // //func TestGetTelegramPool_IdempotencyAndTransactions(t *testing.T) { // t.Run("Idempotency", func(t *testing.T) { // // Первый запрос // resp1, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // // Повторный запрос с теми же параметрами // resp2, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) // assert.Equal(t, resp1.StatusCode, resp2.StatusCode) // }) // // t.Run("TransactionRollback", func(t *testing.T) { // // Пытаемся получить пул с некорректным токеном // resp, err := getTelegramPoolRequest("invalid-token") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // // // Проверяем, что система корректно обрабатывает ошибки авторизации // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) //} // //func createTelegramRequest(token string, body map[string]interface{}) (*http.Response, error) { // payload, err := json.Marshal(body) // if err != nil { // return nil, err // } // req, err := http.NewRequest("POST", baseURL+"/telegram/create", bytes.NewReader(payload)) // if err != nil { // return nil, err // } // req.Header.Set("Authorization", "Bearer "+token) // req.Header.Set("Content-Type", "application/json") // return http.DefaultClient.Do(req) //} // //func TestCreateTelegram_Success(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // // var result map[string]interface{} // err = json.NewDecoder(resp.Body).Decode(&result) // assert.NoError(t, err) // // // Проверяем, что возвращается signature // assert.NotEmpty(t, result["signature"]) // assert.IsType(t, "", result["signature"]) //} // //func TestCreateTelegram_Auth(t *testing.T) { // t.Run("NoToken", func(t *testing.T) { // payload, err := json.Marshal(map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // // req, err := http.NewRequest("POST", baseURL+"/telegram/create", bytes.NewReader(payload)) // assert.NoError(t, err) // req.Header.Set("Content-Type", "application/json") // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("InvalidToken", func(t *testing.T) { // resp, err := createTelegramRequest("invalid_token", map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) //} // //func TestCreateTelegram_InputValidation(t *testing.T) { // t.Run("MissingApiID", func(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("MissingApiHash", func(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("MissingPhoneNumber", func(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("InvalidApiID", func(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": "not_a_number", // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("InvalidPhoneNumber", func(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "invalid_phone", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestCreateTelegram_Performance(t *testing.T) { // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // duration := time.Since(start) // // assert.NoError(t, err) // defer resp.Body.Close() // assert.Less(t, duration.Milliseconds(), int64(500)) // }) //} // //func TestCreateTelegram_ErrorHandling(t *testing.T) { // t.Run("MalformedJSON", func(t *testing.T) { // req, err := http.NewRequest("POST", baseURL+"/telegram/create", bytes.NewReader([]byte("{invalid_json}"))) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validToken) // req.Header.Set("Content-Type", "application/json") // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("ServerError", func(t *testing.T) { // // Тестируем с некорректными данными, которые могут вызвать серверную ошибку // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": "invalid_api_id", // "api_hash": "invalid_hash", // "phone_number": "invalid_phone", // "password": "invalid_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) //} // //func TestCreateTelegram_BoundaryCases(t *testing.T) { // t.Run("VeryLongApiHash", func(t *testing.T) { // longHash := make([]byte, 1025) // for i := range longHash { // longHash[i] = 'a' // } // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": string(longHash), // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("VeryLongPhoneNumber", func(t *testing.T) { // longPhone := make([]byte, 1025) // for i := range longPhone { // longPhone[i] = '1' // } // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": string(longPhone), // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("NegativeApiID", func(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": -123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestCreateTelegram_SpecialCases(t *testing.T) { // t.Run("DuplicatePhoneNumber", func(t *testing.T) { // // Создаем первый аккаунт // resp1, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // // Пытаемся создать второй аккаунт с тем же номером телефона // resp2, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp2.StatusCode) // }) // // t.Run("SpecialCharactersInPassword", func(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "pass@#$%^&*()word", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // }) //} // //func TestCreateTelegram_AuditMetricsConsistency(t *testing.T) { // t.Run("AuditLog", func(t *testing.T) { // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678901", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // Здесь можно добавить проверку на появление записи аудита, если есть доступ к логам/БД // }) // // t.Run("Consistency", func(t *testing.T) { // // Проверяем консистентность данных при создании аккаунтов // resp1, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678902", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // var result1 map[string]interface{} // err = json.NewDecoder(resp1.Body).Decode(&result1) // assert.NoError(t, err) // assert.NotEmpty(t, result1["signature"]) // // // Проверяем, что signature уникален // resp2, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678903", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) // // var result2 map[string]interface{} // err = json.NewDecoder(resp2.Body).Decode(&result2) // assert.NoError(t, err) // assert.NotEmpty(t, result2["signature"]) // assert.NotEqual(t, result1["signature"], result2["signature"]) // }) //} // //func TestCreateTelegram_IdempotencyAndTransactions(t *testing.T) { // t.Run("Idempotency", func(t *testing.T) { // // Создаем аккаунт // resp1, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678904", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // // Повторно создаем аккаунт с теми же данными // resp2, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": 123456, // "api_hash": "abcdef1234567890abcdef1234567890", // "phone_number": "+12345678904", // "password": "secure_password", // }) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp2.StatusCode) // Дубликат не должен создаваться // }) // // t.Run("TransactionRollback", func(t *testing.T) { // // Пытаемся создать аккаунт с некорректными данными // resp, err := createTelegramRequest(validToken, map[string]interface{}{ // "api_id": "invalid", // "api_hash": "invalid", // "phone_number": "invalid", // "password": "invalid", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // // // Проверяем, что транзакция откатилась и аккаунт не создался // poolResp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer poolResp.Body.Close() // assert.Equal(t, http.StatusOK, poolResp.StatusCode) // }) //} // //func deleteTelegramRequest(token string, id string) (*http.Response, error) { // req, err := http.NewRequest("DELETE", baseURL+"/telegram/"+id, nil) // if err != nil { // return nil, err // } // req.Header.Set("Authorization", "Bearer "+token) // req.Header.Set("Content-Type", "application/json") // return http.DefaultClient.Do(req) //} // //func TestDeleteTelegram_Success(t *testing.T) { // // Сначала получаем список аккаунтов, чтобы найти существующий ID // poolResp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer poolResp.Body.Close() // // var accounts []map[string]interface{} // err = json.NewDecoder(poolResp.Body).Decode(&accounts) // assert.NoError(t, err) // // // Если есть аккаунты, удаляем первый // if len(accounts) > 0 { // firstAccount := accounts[0] // accountID := fmt.Sprintf("%v", firstAccount["ID"]) // // // Удаляем аккаунт // resp, err := deleteTelegramRequest(validToken, accountID) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // } //} // //func TestDeleteTelegram_Auth(t *testing.T) { // t.Run("NoToken", func(t *testing.T) { // req, err := http.NewRequest("DELETE", baseURL+"/telegram/123", nil) // assert.NoError(t, err) // req.Header.Set("Content-Type", "application/json") // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("InvalidToken", func(t *testing.T) { // resp, err := deleteTelegramRequest("invalid_token", "123") // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("ExpiredToken", func(t *testing.T) { // resp, err := deleteTelegramRequest(expiredToken, "123") // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) //} // //func TestDeleteTelegram_InputValidation(t *testing.T) { // t.Run("NonExistentID", func(t *testing.T) { // resp, err := deleteTelegramRequest(validToken, "99999") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("InvalidID", func(t *testing.T) { // resp, err := deleteTelegramRequest(validToken, "!@#") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("EmptyID", func(t *testing.T) { // resp, err := deleteTelegramRequest(validToken, "") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestDeleteTelegram_Security(t *testing.T) { // t.Run("SQLInjectionAttempt", func(t *testing.T) { // resp, err := deleteTelegramRequest(validToken, "' OR 1=1 --") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("XSSAttempt", func(t *testing.T) { // resp, err := deleteTelegramRequest(validToken, "") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestDeleteTelegram_Performance(t *testing.T) { // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := deleteTelegramRequest(validToken, "123") // duration := time.Since(start) // // assert.NoError(t, err) // defer resp.Body.Close() // assert.Less(t, duration.Milliseconds(), int64(500)) // }) //} // //func TestDeleteTelegram_BoundaryCases(t *testing.T) { // t.Run("VeryLongID", func(t *testing.T) { // longID := make([]byte, 1025) // for i := range longID { // longID[i] = '1' // } // resp, err := deleteTelegramRequest(validToken, string(longID)) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("NegativeID", func(t *testing.T) { // resp, err := deleteTelegramRequest(validToken, "-123") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("ZeroID", func(t *testing.T) { // resp, err := deleteTelegramRequest(validToken, "0") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestDeleteTelegram_ErrorHandling(t *testing.T) { // t.Run("MalformedRequest", func(t *testing.T) { // // Тестируем с некорректным запросом // req, err := http.NewRequest("DELETE", baseURL+"/telegram/123", bytes.NewReader([]byte("invalid_body"))) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validToken) // req.Header.Set("Content-Type", "application/json") // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) // // t.Run("ServerError", func(t *testing.T) { // // Тестируем с некорректным ID, который может вызвать серверную ошибку // resp, err := deleteTelegramRequest(validToken, "invalid-id-with-special-chars@#$%") // assert.NoError(t, err) // defer resp.Body.Close() // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) //} // //func TestDeleteTelegram_AuditMetricsConsistency(t *testing.T) { // t.Run("AuditLog", func(t *testing.T) { // // Сначала получаем список аккаунтов, чтобы найти существующий ID // poolResp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer poolResp.Body.Close() // // var accounts []map[string]interface{} // err = json.NewDecoder(poolResp.Body).Decode(&accounts) // assert.NoError(t, err) // // // Если есть аккаунты, удаляем первый для тестирования аудита // if len(accounts) > 0 { // firstAccount := accounts[0] // accountID := fmt.Sprintf("%v", firstAccount["ID"]) // // resp, err := deleteTelegramRequest(validToken, accountID) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // Здесь можно добавить проверку на появление записи аудита, если есть доступ к логам/БД // } // }) // // t.Run("Consistency", func(t *testing.T) { // // Проверяем консистентность данных при удалении // // Сначала получаем список аккаунтов // poolResp1, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer poolResp1.Body.Close() // // var accounts1 []map[string]interface{} // err = json.NewDecoder(poolResp1.Body).Decode(&accounts1) // assert.NoError(t, err) // // // Если есть аккаунты, удаляем один // if len(accounts1) > 0 { // firstAccount := accounts1[0] // accountID := fmt.Sprintf("%v", firstAccount["ID"]) // // resp, err := deleteTelegramRequest(validToken, accountID) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // // Проверяем, что аккаунт действительно удален // poolResp2, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer poolResp2.Body.Close() // // var accounts2 []map[string]interface{} // err = json.NewDecoder(poolResp2.Body).Decode(&accounts2) // assert.NoError(t, err) // // // Проверяем, что количество аккаунтов уменьшилось // assert.LessOrEqual(t, len(accounts2), len(accounts1)) // } // }) //} // //func TestDeleteTelegram_IdempotencyAndTransactions(t *testing.T) { // t.Run("Idempotency", func(t *testing.T) { // // Сначала получаем список аккаунтов, чтобы найти существующий ID // poolResp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer poolResp.Body.Close() // // var accounts []map[string]interface{} // err = json.NewDecoder(poolResp.Body).Decode(&accounts) // assert.NoError(t, err) // // // Если есть аккаунты, удаляем первый // if len(accounts) > 0 { // firstAccount := accounts[0] // accountID := fmt.Sprintf("%v", firstAccount["ID"]) // // // Первое удаление // resp1, err := deleteTelegramRequest(validToken, accountID) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // // Повторное удаление того же аккаунта // resp2, err := deleteTelegramRequest(validToken, accountID) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp2.StatusCode) // Уже удален // } // }) // // t.Run("TransactionRollback", func(t *testing.T) { // // Пытаемся удалить несуществующий аккаунт // resp, err := deleteTelegramRequest(validToken, "999999") // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // // // Проверяем, что система корректно обрабатывает ошибки // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) //} // //func setTelegramCodeRequest(token string, body map[string]interface{}) (*http.Response, error) { // payload, err := json.Marshal(body) // if err != nil { // return nil, err // } // req, err := http.NewRequest("POST", baseURL+"/telegram/setCode", bytes.NewReader(payload)) // if err != nil { // return nil, err // } // req.Header.Set("Authorization", "Bearer "+token) // req.Header.Set("Content-Type", "application/json") // return http.DefaultClient.Do(req) //} // //func TestSetTelegramCode_Success(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // // assert.Equal(t, http.StatusOK, resp.StatusCode) // assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // // var result map[string]interface{} // err = json.NewDecoder(resp.Body).Decode(&result) // assert.NoError(t, err) // // // Проверяем, что возвращается ID // assert.NotEmpty(t, result["id"]) // assert.IsType(t, float64(0), result["id"]) //} // //func TestSetTelegramCode_Auth(t *testing.T) { // t.Run("NoToken", func(t *testing.T) { // payload, err := json.Marshal(map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // assert.NoError(t, err) // // req, err := http.NewRequest("POST", baseURL+"/telegram/setCode", bytes.NewReader(payload)) // assert.NoError(t, err) // req.Header.Set("Content-Type", "application/json") // // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("InvalidToken", func(t *testing.T) { // resp, err := setTelegramCodeRequest("invalid_token", map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) // // t.Run("ExpiredToken", func(t *testing.T) { // resp, err := setTelegramCodeRequest(expiredToken, map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // assert.NoError(t, err) // assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) // }) //} // //func TestSetTelegramCode_InputValidation(t *testing.T) { // t.Run("MissingCode", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("MissingSignature", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("InvalidCodeType", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": 123456, // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("InvalidSignatureType", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": 12345, // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestSetTelegramCode_Security(t *testing.T) { // t.Run("XSSInCode", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("SQLInjectionInCode", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "' OR 1=1 --", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("XSSInSignature", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": "", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestSetTelegramCode_Performance(t *testing.T) { // t.Run("ResponseTime", func(t *testing.T) { // start := time.Now() // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // duration := time.Since(start) // // assert.NoError(t, err) // defer resp.Body.Close() // assert.Less(t, duration.Milliseconds(), int64(500)) // }) // // t.Run("ConcurrentRequests", func(t *testing.T) { // var wg sync.WaitGroup // for i := 0; i < 10; i++ { // wg.Add(1) // go func(index int) { // defer wg.Done() // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": fmt.Sprintf("12345%d", index), // "signature": fmt.Sprintf("signature%d", index), // }) // if err == nil && resp != nil { // resp.Body.Close() // } // }(i) // } // wg.Wait() // }) //} // //func TestSetTelegramCode_BoundaryCases(t *testing.T) { // t.Run("VeryLongCode", func(t *testing.T) { // longCode := make([]byte, 1025) // for i := range longCode { // longCode[i] = '1' // } // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": string(longCode), // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("VeryLongSignature", func(t *testing.T) { // longSignature := make([]byte, 1025) // for i := range longSignature { // longSignature[i] = 'a' // } // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": string(longSignature), // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("EmptyCode", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("EmptySignature", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": "", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) //} // //func TestSetTelegramCode_ErrorHandling(t *testing.T) { // t.Run("MalformedJSON", func(t *testing.T) { // req, err := http.NewRequest("POST", baseURL+"/telegram/setCode", bytes.NewReader([]byte("{invalid_json}"))) // assert.NoError(t, err) // req.Header.Set("Authorization", "Bearer "+validToken) // req.Header.Set("Content-Type", "application/json") // resp, err := http.DefaultClient.Do(req) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // }) // // t.Run("ServerError", func(t *testing.T) { // // Тестируем с некорректными данными, которые могут вызвать серверную ошибку // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "invalid_code", // "signature": "invalid_signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.NotEqual(t, http.StatusOK, resp.StatusCode) // }) //} // //func TestSetTelegramCode_AuditMetricsConsistency(t *testing.T) { // t.Run("AuditLog", func(t *testing.T) { // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusOK, resp.StatusCode) // // Здесь можно добавить проверку на появление записи аудита, если есть доступ к логам/БД // }) // // t.Run("Consistency", func(t *testing.T) { // // Проверяем консистентность данных при установке кода // resp1, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // var result1 map[string]interface{} // err = json.NewDecoder(resp1.Body).Decode(&result1) // assert.NoError(t, err) // assert.NotEmpty(t, result1["id"]) // // // Проверяем, что ID уникален при разных кодах // resp2, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "654321", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) // // var result2 map[string]interface{} // err = json.NewDecoder(resp2.Body).Decode(&result2) // assert.NoError(t, err) // assert.NotEmpty(t, result2["id"]) // assert.NotEqual(t, result1["id"], result2["id"]) // }) //} // //func TestSetTelegramCode_IdempotencyAndTransactions(t *testing.T) { // t.Run("Idempotency", func(t *testing.T) { // // Первая установка кода // resp1, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp1.Body.Close() // assert.Equal(t, http.StatusOK, resp1.StatusCode) // // // Повторная установка того же кода // resp2, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "123456", // "signature": "abc123signature", // }) // assert.NoError(t, err) // defer resp2.Body.Close() // assert.Equal(t, http.StatusOK, resp2.StatusCode) // assert.Equal(t, resp1.StatusCode, resp2.StatusCode) // }) // // t.Run("TransactionRollback", func(t *testing.T) { // // Пытаемся установить код с некорректными данными // resp, err := setTelegramCodeRequest(validToken, map[string]interface{}{ // "code": "invalid", // "signature": "invalid", // }) // assert.NoError(t, err) // defer resp.Body.Close() // assert.Equal(t, http.StatusBadRequest, resp.StatusCode) // // // Проверяем, что транзакция откатилась и код не установился // poolResp, err := getTelegramPoolRequest(validToken) // assert.NoError(t, err) // defer poolResp.Body.Close() // assert.Equal(t, http.StatusOK, poolResp.StatusCode) // }) //}