10172 lines
308 KiB
Go
10172 lines
308 KiB
Go
package tests
|
||
|
||
import (
|
||
"bytes"
|
||
"database/sql"
|
||
"encoding/json"
|
||
"fmt"
|
||
"gitea.pena/SQuiz/common/model"
|
||
"gitea.pena/SQuiz/common/repository/statistics"
|
||
"gitea.pena/SQuiz/core/internal/controllers/http_controllers/account"
|
||
"gitea.pena/SQuiz/core/internal/controllers/http_controllers/question"
|
||
"gitea.pena/SQuiz/core/internal/controllers/http_controllers/quiz"
|
||
result2 "gitea.pena/SQuiz/core/internal/controllers/http_controllers/result"
|
||
"github.com/pioz/faker"
|
||
"github.com/stretchr/testify/assert"
|
||
"net/http"
|
||
"strings"
|
||
"sync"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
// todo нужно определить из кликхауса на чем будем тестировать статистику
|
||
|
||
var validQuizIDForTestingClickHouse = 21211
|
||
var PublicKey = `-----BEGIN PUBLIC KEY-----MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm6980fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6BdA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y+3GyaOY536H47qyXAgMBAAE=-----END PUBLIC KEY-----`
|
||
var postgresCred = "postgres://squiz:Redalert2@10.7.0.2:35432/squiz?sslmode=disable" //os.Getenv("POSTGRES_CRED")
|
||
var baseURL = "http://localhost:1488" //os.Getenv("API_BASE_URL")
|
||
var validToken = CreateJWT(validUserID) // validUserID
|
||
var expiredToken = CreateExpiredToken(validUserID)
|
||
|
||
// todo
|
||
var validAdminToken = CreateJWT(validUserID) // os.Getenv("VALID_ADMIN_JWT_TOKEN")
|
||
var existingUserIDToken = CreateJWT(existingUserID) // existingUserID
|
||
var AccountWithOutPrivilegeToken = CreateJWT(userWithoutPrivileges) // userWithoutPrivileges
|
||
var notFoundAccountToken = CreateJWT("notFound-123")
|
||
|
||
// todo
|
||
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 = "<script>alert('xss')</script>"
|
||
|
||
// отсмотрено
|
||
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)
|
||
}
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
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()
|
||
userID := faker.String()
|
||
resp := createAccountRequest(t, CreateJWT(userID), map[string]interface{}{
|
||
"user_id": fmt.Sprintf(userID),
|
||
})
|
||
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 := fmt.Sprintf("тест_%d", faker.Int32()) // Unicode символы
|
||
resp := createAccountRequest(t, CreateJWT(unicodeUserID), map[string]interface{}{
|
||
"user_id": unicodeUserID,
|
||
})
|
||
defer resp.Body.Close()
|
||
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result account.CreateAccountResp
|
||
err := json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
assert.Equal(t, unicodeUserID, result.CreatedAccount.UserID)
|
||
})
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestDeleteAccount_Success(t *testing.T) {
|
||
testDeleteUserID := faker.String()
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
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 "+testDeleteUserIDJWT)
|
||
|
||
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 account.DeleteAccountResp
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
assert.NotEmpty(t, result.DeletedAccountID)
|
||
}
|
||
|
||
// отсмотрено
|
||
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) {
|
||
testDeleteUserID := faker.String()
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
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 "+testDeleteUserIDJWT)
|
||
resp, err := http.DefaultClient.Do(req)
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
// 404
|
||
req2, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil)
|
||
assert.NoError(t, err)
|
||
req2.Header.Set("Authorization", "Bearer "+testDeleteUserIDJWT)
|
||
resp2, err := http.DefaultClient.Do(req2)
|
||
assert.NoError(t, err)
|
||
defer resp2.Body.Close()
|
||
// 404
|
||
assert.Equal(t, http.StatusInternalServerError, resp2.StatusCode)
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestDeleteAccount_NonExistent(t *testing.T) {
|
||
nonExistentUserID := faker.String()
|
||
req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil)
|
||
assert.NoError(t, err)
|
||
req.Header.Set("Authorization", "Bearer "+CreateJWT(nonExistentUserID))
|
||
resp, err := http.DefaultClient.Do(req)
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.True(t, resp.StatusCode == http.StatusInternalServerError)
|
||
}
|
||
|
||
// todo
|
||
func TestDeleteAccount_CascadeDeletion(t *testing.T) {
|
||
t.Run("RelatedDataDeletion", func(t *testing.T) {
|
||
testDeleteUserID := faker.String()
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
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 "+testDeleteUserIDJWT)
|
||
|
||
resp, err := http.DefaultClient.Do(req)
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
// Проверяем, что связанные данные удалены или помечены как удаленные
|
||
// Здесь можно добавить дополнительные проверки, если есть API для проверки связанных данных
|
||
})
|
||
|
||
t.Run("StatisticsPreservation", func(t *testing.T) {
|
||
testDeleteUserID := faker.String()
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
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 "+testDeleteUserIDJWT)
|
||
|
||
resp, err := http.DefaultClient.Do(req)
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
// Проверяем, что статистические данные сохранены
|
||
// Здесь можно добавить проверки статистики, если есть соответствующий API
|
||
})
|
||
}
|
||
|
||
// todo
|
||
//func TestDeleteAccount_Security(t *testing.T) {
|
||
// t.Run("CSRFProtection", func(t *testing.T) {
|
||
// testDeleteUserID := faker.String()
|
||
// testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
// createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
// "user_id": testDeleteUserID,
|
||
// })
|
||
// 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 "+testDeleteUserIDJWT)
|
||
// req.Header.Set("X-CSRF-Token", "invalid_token")
|
||
//
|
||
// resp, err := http.DefaultClient.Do(req)
|
||
// assert.NoError(t, err)
|
||
// defer resp.Body.Close()
|
||
//
|
||
// assert.True(t, resp.StatusCode == http.StatusBadRequest)
|
||
// })
|
||
//}
|
||
|
||
// отсмотрено
|
||
func TestDeleteAccount_Performance(t *testing.T) {
|
||
t.Run("ResponseTime", func(t *testing.T) {
|
||
testDeleteUserID := faker.String()
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
|
||
defer createResp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, createResp.StatusCode)
|
||
|
||
req, _ := http.NewRequest("DELETE", baseURL+"/account/delete", nil)
|
||
req.Header.Set("Authorization", "Bearer "+testDeleteUserIDJWT)
|
||
|
||
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 < 10; i++ {
|
||
wg.Add(1)
|
||
go func(index int) {
|
||
defer wg.Done()
|
||
|
||
testDeleteUserID := fmt.Sprintf(faker.String(), "%d", index)
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
defer createResp.Body.Close()
|
||
|
||
if createResp.StatusCode == http.StatusOK {
|
||
req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil)
|
||
assert.NoError(t, err)
|
||
req.Header.Set("Authorization", "Bearer "+testDeleteUserIDJWT)
|
||
resp, err := http.DefaultClient.Do(req)
|
||
assert.NoError(t, err)
|
||
if resp != nil {
|
||
defer resp.Body.Close()
|
||
}
|
||
}
|
||
}(i)
|
||
}
|
||
wg.Wait()
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestDeleteAccount_BoundaryCases(t *testing.T) {
|
||
t.Run("ConcurrentOperations", func(t *testing.T) {
|
||
var wg sync.WaitGroup
|
||
successCount := 0
|
||
var mu sync.Mutex
|
||
|
||
for i := 0; i < 5; i++ {
|
||
wg.Add(1)
|
||
go func(index int) {
|
||
defer wg.Done()
|
||
|
||
testDeleteUserID := fmt.Sprintf(faker.String())
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
|
||
defer createResp.Body.Close()
|
||
|
||
if createResp.StatusCode == http.StatusOK {
|
||
req, err := http.NewRequest("DELETE", baseURL+"/account/delete", nil)
|
||
assert.NoError(t, err)
|
||
req.Header.Set("Authorization", "Bearer "+testDeleteUserIDJWT)
|
||
|
||
resp, err := http.DefaultClient.Do(req)
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode == http.StatusOK {
|
||
mu.Lock()
|
||
successCount++
|
||
mu.Unlock()
|
||
}
|
||
}
|
||
}(i)
|
||
}
|
||
wg.Wait()
|
||
|
||
assert.Greater(t, successCount, 0)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
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.StatusOK, 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.StatusOK, 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)
|
||
}
|
||
})
|
||
}
|
||
|
||
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)
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestDeleteAccountByUserID_Success(t *testing.T) {
|
||
testDeleteUserID := faker.String()
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
defer createResp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, createResp.StatusCode)
|
||
|
||
resp, err := deleteAccountByUserIDRequest(testDeleteUserIDJWT, map[string]string{"userId": testDeleteUserID})
|
||
assert.NoError(t, err)
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
assert.Equal(t, "application/json", resp.Header.Get("Content-Type"))
|
||
|
||
var result account.DeleteAccountByUserIDResp
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
assert.Equal(t, testDeleteUserID, result.DeletedAccountUserID)
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestDeleteAccountByUserID_Auth(t *testing.T) {
|
||
t.Run("NoToken", func(t *testing.T) {
|
||
req, err := http.NewRequest("DELETE", baseURL+"/account/"+testUserID, 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": testUserID})
|
||
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": testUserID})
|
||
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.StatusNotFound, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestDeleteAccountByUserID_Performance(t *testing.T) {
|
||
t.Run("ResponseTime", func(t *testing.T) {
|
||
testDeleteUserID := faker.String()
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
defer createResp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, createResp.StatusCode)
|
||
|
||
start := time.Now()
|
||
resp, err := deleteAccountByUserIDRequest(testDeleteUserIDJWT, map[string]string{"userId": testDeleteUserID})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
|
||
duration := time.Since(start)
|
||
assert.Less(t, duration.Milliseconds(), int64(1000))
|
||
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 < 5; i++ {
|
||
wg.Add(1)
|
||
go func(index int) {
|
||
defer wg.Done()
|
||
|
||
testDeleteUserID := faker.String()
|
||
testDeleteUserIDJWT := CreateJWT(testDeleteUserID)
|
||
createResp := createAccountRequest(t, testDeleteUserIDJWT, map[string]interface{}{
|
||
"user_id": testDeleteUserID,
|
||
})
|
||
defer createResp.Body.Close()
|
||
|
||
if createResp.StatusCode == http.StatusOK {
|
||
resp, err := deleteAccountByUserIDRequest(testDeleteUserIDJWT, map[string]string{"userId": testDeleteUserID})
|
||
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, 2)
|
||
})
|
||
}
|
||
|
||
// todo
|
||
//func TestDeleteAccountByUserID_SQLInjection_XSS(t *testing.T) {
|
||
// t.Run("SQLInjection", func(t *testing.T) {
|
||
// resp, err := deleteAccountByUserIDRequest(validAdminToken, 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(validAdminToken, map[string]string{"userId": xssInput})
|
||
// assert.NoError(t, err)
|
||
// assert.Equal(t, http.StatusBadRequest, 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)
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestManualDone_Success(t *testing.T) {
|
||
resp, err := manualDoneRequest(validAdminToken, map[string]string{"id": validUserID})
|
||
assert.NoError(t, err)
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
}
|
||
|
||
// отсмотрено
|
||
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 символы
|
||
_, err := manualDoneRequest(validAdminToken, map[string]string{"id": unicodeID})
|
||
assert.NoError(t, err)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
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)
|
||
})
|
||
|
||
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)
|
||
})
|
||
}
|
||
|
||
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(validToken, 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(validToken, 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(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.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(validToken, 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 "+validToken)
|
||
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(validToken, 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(validToken, 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(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 := deleteLeadTargetRequest(validToken, 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(validToken, 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(validToken, 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(validToken, 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(validToken, 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(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)
|
||
|
||
resp1, err := deleteLeadTargetRequest(validToken, getRespLead[0].ID)
|
||
assert.NoError(t, err)
|
||
resp1.Body.Close()
|
||
|
||
resp2, err := deleteLeadTargetRequest(validToken, 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(validToken, 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(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)
|
||
|
||
deleteResp, err := deleteLeadTargetRequest(validToken, getRespLead[0].ID)
|
||
assert.NoError(t, err)
|
||
deleteResp.Body.Close()
|
||
|
||
resp, err := getLeadTargetByQuizIDRequest(validToken, 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"} // "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": "Квиз",
|
||
// "limit": 1,
|
||
// "page": 6,
|
||
// })
|
||
// 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.StatusInternalServerError, 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.StatusInternalServerError, 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(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": "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(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 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(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": "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(validToken, map[string]interface{}{
|
||
"id": createResult.Id,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp1.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp1.StatusCode)
|
||
|
||
resp2, err := deleteQuestionRequest(validToken, 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(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 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(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 := deleteQuestionRequest(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 := deleteQuestionRequest(validToken, map[string]interface{}{
|
||
"id": 99999,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestDeleteQuestion_AlreadyDeleted(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": "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(validToken, map[string]interface{}{
|
||
"id": createResult.Id,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp1.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp1.StatusCode)
|
||
|
||
resp2, err := deleteQuestionRequest(validToken, 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(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)
|
||
|
||
var questionIDs []uint64
|
||
for i := 0; i < 10; i++ {
|
||
createResp, err := createQuestionRequest(validToken, 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(validToken, 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(validToken, 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)
|
||
}
|
||
|
||
// отсмотрено
|
||
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": 0,
|
||
"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)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
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)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
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("тест по фильтру %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 quiz.GetQuizListResp
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
items := result.Items
|
||
|
||
for _, item := range items {
|
||
assert.Equal(t, "draft", item.Status)
|
||
}
|
||
})
|
||
t.Run("SearchFilter", func(t *testing.T) {
|
||
resp, err := getQuizListRequest(validToken, map[string]interface{}{
|
||
"search": "тест",
|
||
"limit": 5,
|
||
"page": 0,
|
||
})
|
||
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)
|
||
|
||
items := result.Items
|
||
|
||
for _, item := range items {
|
||
assert.Contains(t, item.Name, "тест")
|
||
}
|
||
})
|
||
|
||
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 quiz.GetQuizListResp
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
items := result.Items
|
||
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.StatusInternalServerError, 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.StatusInternalServerError, 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(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 := deleteQuizRequest(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 quiz.DeactivateResp
|
||
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(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
|
||
|
||
resp1, err := deleteQuizRequest(validToken, map[string]interface{}{
|
||
"id": quizID,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp1.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp1.StatusCode)
|
||
|
||
resp2, err := deleteQuizRequest(validToken, map[string]interface{}{
|
||
"id": quizID,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp2.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp2.StatusCode)
|
||
|
||
var result1, result2 quiz.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, 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(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 := deleteQuizRequest(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 := deleteQuizRequest(validToken, map[string]interface{}{
|
||
"id": 99999,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) // Идемпотентность
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestDeleteQuiz_Performance(t *testing.T) {
|
||
var quizIDs []uint64
|
||
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 model.Quiz
|
||
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(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("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(validToken, 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 model.Quiz
|
||
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 quiz.DeactivateResp
|
||
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 model.Quiz
|
||
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 quiz.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, 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.StatusFailedDependency, 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)
|
||
})
|
||
// todo 404
|
||
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.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestArchiveQuiz_Performance(t *testing.T) {
|
||
var quizIDs []uint64
|
||
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 model.Quiz
|
||
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.StatusInternalServerError, 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 model.Quiz
|
||
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)
|
||
})
|
||
// todo 404
|
||
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.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
// todo 404
|
||
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.StatusInternalServerError, 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 model.Quiz
|
||
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) {
|
||
createResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||
"name": "Квиз для теста граничных случаев",
|
||
"description": "Детальный тест для проверки граничных случаев создания шаблонов",
|
||
"fingerprinting": true,
|
||
"repeatable": true,
|
||
"note_prevented": false,
|
||
"mail_notifications": true,
|
||
"unique_answers": false,
|
||
"config": "{\"showCorrectAnswers\": true, \"allowReview\": true}",
|
||
"status": "template",
|
||
"limit": 100,
|
||
"question_cnt": 15,
|
||
"time_of_passing": 3600,
|
||
"pausable": true,
|
||
"super": false,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer createResp.Body.Close()
|
||
var createResult model.Quiz
|
||
err = json.NewDecoder(createResp.Body).Decode(&createResult)
|
||
assert.NoError(t, err)
|
||
quizQID := createResult.Qid
|
||
|
||
resp, err := createQuestionRequest(validToken, map[string]interface{}{
|
||
"quiz_id": createResult.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"))
|
||
|
||
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, quizQID)
|
||
if err == nil && resp != nil {
|
||
resp.Body.Close()
|
||
}
|
||
}()
|
||
}
|
||
wg.Wait()
|
||
})
|
||
}
|
||
|
||
func createQuizTemplateRequest(token string, qid string) (*http.Response, error) {
|
||
payload := map[string]interface{}{
|
||
"qid": qid,
|
||
}
|
||
jsonData, err := json.Marshal(payload)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
req, err := http.NewRequest("POST", baseURL+"/quiz/template", bytes.NewReader(jsonData))
|
||
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) {
|
||
createResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||
"name": "Квиз для теста производительности переноса",
|
||
"description": "Комплексный тест для проверки создания шаблонов",
|
||
"fingerprinting": true,
|
||
"repeatable": true,
|
||
"note_prevented": false,
|
||
"mail_notifications": true,
|
||
"unique_answers": false,
|
||
"config": "{\"showCorrectAnswers\": true, \"allowReview\": true, \"showProgress\": true}",
|
||
"status": "template",
|
||
"limit": 200,
|
||
"question_cnt": 20,
|
||
"time_of_passing": 7200,
|
||
"pausable": true,
|
||
"super": false,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer createResp.Body.Close()
|
||
var createResult model.Quiz
|
||
err = json.NewDecoder(createResp.Body).Decode(&createResult)
|
||
assert.NoError(t, err)
|
||
quizQID := createResult.Qid
|
||
|
||
resp, err := createQuestionRequest(validToken, map[string]interface{}{
|
||
"quiz_id": createResult.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"))
|
||
|
||
resp, err = createQuizTemplateRequest(validToken, quizQID)
|
||
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) {
|
||
createResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||
"name": "Квиз для теста авторизации",
|
||
"description": "Тест для проверки авторизации при создании шаблонов",
|
||
"fingerprinting": false,
|
||
"repeatable": false,
|
||
"note_prevented": true,
|
||
"mail_notifications": false,
|
||
"unique_answers": true,
|
||
"config": "{\"showCorrectAnswers\": false, \"strictMode\": true}",
|
||
"status": "template",
|
||
"limit": 50,
|
||
"question_cnt": 5,
|
||
"time_of_passing": 1800,
|
||
"pausable": false,
|
||
"super": false,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer createResp.Body.Close()
|
||
var createResult model.Quiz
|
||
err = json.NewDecoder(createResp.Body).Decode(&createResult)
|
||
assert.NoError(t, err)
|
||
quizQID := createResult.Qid
|
||
|
||
resp, err := createQuestionRequest(validToken, map[string]interface{}{
|
||
"quiz_id": createResult.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"))
|
||
|
||
t.Run("NoToken", func(t *testing.T) {
|
||
payload := map[string]interface{}{
|
||
"qid": quizQID,
|
||
}
|
||
jsonData, err := json.Marshal(payload)
|
||
assert.NoError(t, err)
|
||
|
||
req, err := http.NewRequest("POST", baseURL+"/quiz/template", bytes.NewReader(jsonData))
|
||
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", quizQID)
|
||
assert.NoError(t, err)
|
||
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestCreateQuizTemplate_Performance(t *testing.T) {
|
||
createResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||
"name": "Квиз для теста производительности",
|
||
"description": "Тест производительности создания шаблонов",
|
||
"fingerprinting": true,
|
||
"repeatable": true,
|
||
"note_prevented": false,
|
||
"mail_notifications": true,
|
||
"unique_answers": false,
|
||
"config": "{\"showCorrectAnswers\": true, \"performanceMode\": true}",
|
||
"status": "template",
|
||
"limit": 150,
|
||
"question_cnt": 12,
|
||
"time_of_passing": 5400,
|
||
"pausable": true,
|
||
"super": false,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer createResp.Body.Close()
|
||
var createResult model.Quiz
|
||
err = json.NewDecoder(createResp.Body).Decode(&createResult)
|
||
assert.NoError(t, err)
|
||
quizQID := createResult.Qid
|
||
|
||
resp, err := createQuestionRequest(validToken, map[string]interface{}{
|
||
"quiz_id": createResult.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"))
|
||
|
||
resp, err = createQuestionRequest(validToken, map[string]interface{}{
|
||
"quiz_id": createResult.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"))
|
||
|
||
t.Run("ResponseTime", func(t *testing.T) {
|
||
start := time.Now()
|
||
resp, err := createQuizTemplateRequest(validToken, quizQID)
|
||
duration := time.Since(start)
|
||
|
||
assert.NoError(t, err)
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
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, quizQID)
|
||
if err == nil && resp != nil {
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
resp.Body.Close()
|
||
}
|
||
}()
|
||
}
|
||
wg.Wait()
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestCreateQuizTemplate_InputValidation(t *testing.T) {
|
||
t.Run("EmptyQid", func(t *testing.T) {
|
||
payload := map[string]interface{}{
|
||
"qid": "",
|
||
}
|
||
jsonData, err := json.Marshal(payload)
|
||
assert.NoError(t, err)
|
||
|
||
req, err := http.NewRequest("POST", baseURL+"/quiz/template", bytes.NewReader(jsonData))
|
||
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("MissingQid", func(t *testing.T) {
|
||
payload := map[string]interface{}{}
|
||
jsonData, err := json.Marshal(payload)
|
||
assert.NoError(t, err)
|
||
|
||
req, err := http.NewRequest("POST", baseURL+"/quiz/template", bytes.NewReader(jsonData))
|
||
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("InvalidQid", func(t *testing.T) {
|
||
resp, err := createQuizTemplateRequest(validToken, "invalid-qid-format")
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
|
||
t.Run("NonExistentQid", func(t *testing.T) {
|
||
resp, err := createQuizTemplateRequest(validToken, "non-existent-qid-12345")
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
|
||
t.Run("QuizWithDraftStatus", func(t *testing.T) {
|
||
createResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||
"name": "Квиз со статусом draft",
|
||
"description": "Квиз для тестирования статуса draft",
|
||
"fingerprinting": false,
|
||
"repeatable": true,
|
||
"note_prevented": false,
|
||
"mail_notifications": false,
|
||
"unique_answers": false,
|
||
"config": "{\"showCorrectAnswers\": true}",
|
||
"status": "draft",
|
||
"limit": 10,
|
||
"question_cnt": 2,
|
||
"time_of_passing": 600,
|
||
"pausable": false,
|
||
"super": false,
|
||
})
|
||
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 := createQuizTemplateRequest(validToken, createResult.Qid)
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// todo
|
||
//func TestCreateQuizTemplate_Security(t *testing.T) {
|
||
// createResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||
// "name": "Квиз для теста безопасности",
|
||
// "description": "Тест безопасности при создании шаблонов",
|
||
// "fingerprinting": true,
|
||
// "repeatable": false,
|
||
// "note_prevented": true,
|
||
// "mail_notifications": false,
|
||
// "unique_answers": true,
|
||
// "config": "{\"showCorrectAnswers\": false, \"securityMode\": true}",
|
||
// "status": "template",
|
||
// "limit": 75,
|
||
// "question_cnt": 8,
|
||
// "time_of_passing": 2700,
|
||
// "pausable": false,
|
||
// "super": false,
|
||
// })
|
||
// 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("SQLInjection", func(t *testing.T) {
|
||
// resp, err := createQuizTemplateRequest(validToken, sqlInjectionInput)
|
||
// assert.NoError(t, err)
|
||
// defer resp.Body.Close()
|
||
// assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||
// })
|
||
//
|
||
// t.Run("XSSAttempt", func(t *testing.T) {
|
||
// resp, err := createQuizTemplateRequest(validToken, xssInput)
|
||
// assert.NoError(t, err)
|
||
// defer resp.Body.Close()
|
||
// assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||
// })
|
||
//
|
||
// t.Run("LargeQid", func(t *testing.T) {
|
||
// largeQid := strings.Repeat("a", 1000)
|
||
// resp, err := createQuizTemplateRequest(validToken, largeQid)
|
||
// assert.NoError(t, err)
|
||
// defer resp.Body.Close()
|
||
// assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||
// })
|
||
//}
|
||
|
||
// отсмотрено
|
||
func TestCreateQuizTemplate_SpecialCases(t *testing.T) {
|
||
createResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||
"name": "Квиз для специальных случаев",
|
||
"description": "Тест специальных случаев создания шаблонов",
|
||
"fingerprinting": false,
|
||
"repeatable": true,
|
||
"note_prevented": false,
|
||
"mail_notifications": true,
|
||
"unique_answers": false,
|
||
"config": "{\"showCorrectAnswers\": true, \"flexibleMode\": true}",
|
||
"status": "template",
|
||
"limit": 300,
|
||
"question_cnt": 25,
|
||
"time_of_passing": 9000,
|
||
"pausable": true,
|
||
"super": false,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer createResp.Body.Close()
|
||
var createResult model.Quiz
|
||
err = json.NewDecoder(createResp.Body).Decode(&createResult)
|
||
assert.NoError(t, err)
|
||
quizQID := createResult.Qid
|
||
|
||
resp, err := createQuestionRequest(validToken, map[string]interface{}{
|
||
"quiz_id": createResult.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"))
|
||
|
||
t.Run("DuplicateTemplateCreation", func(t *testing.T) {
|
||
resp1, err := createQuizTemplateRequest(validToken, quizQID)
|
||
assert.NoError(t, err)
|
||
defer resp1.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp1.StatusCode)
|
||
|
||
resp2, err := createQuizTemplateRequest(validToken, quizQID)
|
||
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.NotEqual(t, result1["id"], result2["id"])
|
||
})
|
||
// todo need 403
|
||
t.Run("TemplateFromDifferentUser", func(t *testing.T) {
|
||
createResp2, err := createQuizRequest(existingUserIDToken, map[string]interface{}{
|
||
"name": "Квиз другого пользователя",
|
||
"description": "Квиз созданный другим пользователем для тестирования доступа",
|
||
"fingerprinting": true,
|
||
"repeatable": false,
|
||
"note_prevented": true,
|
||
"mail_notifications": false,
|
||
"unique_answers": true,
|
||
"config": "{\"showCorrectAnswers\": false, \"privateMode\": true}",
|
||
"status": "template",
|
||
"limit": 60,
|
||
"question_cnt": 6,
|
||
"time_of_passing": 2400,
|
||
"pausable": false,
|
||
"super": false,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer createResp2.Body.Close()
|
||
var createResult2 model.Quiz
|
||
err = json.NewDecoder(createResp2.Body).Decode(&createResult2)
|
||
assert.NoError(t, err)
|
||
|
||
resp, err := createQuizTemplateRequest(validToken, createResult2.Qid)
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// todo перевроверить через дамп
|
||
type TestData struct {
|
||
Quiz model.Quiz
|
||
Questions []model.Question
|
||
Answers []model.Answer
|
||
}
|
||
|
||
func createTestDataForResults(t *testing.T, token string, quizName string) *TestData {
|
||
quizResp, err := createQuizRequest(token, map[string]interface{}{
|
||
"name": quizName,
|
||
"status": "start",
|
||
})
|
||
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)
|
||
|
||
questions := []model.Question{}
|
||
questionData := []map[string]interface{}{
|
||
{
|
||
"title": "Какой основной компонент воздуха?",
|
||
"type": "variant",
|
||
"description": "Выберите один правильный ответ.",
|
||
"required": true,
|
||
"page": 1,
|
||
"content": `{"variants": ["Кислород", "Азот", "Углекислый газ", "Водород"], "correct": 1}`,
|
||
},
|
||
{
|
||
"title": "Столица России?",
|
||
"type": "text",
|
||
"description": "Введите название столицы.",
|
||
"required": true,
|
||
"page": 1,
|
||
"content": `{"maxLength": 50}`,
|
||
},
|
||
{
|
||
"title": "Ваш возраст",
|
||
"type": "number",
|
||
"description": "Укажите ваш возраст.",
|
||
"required": false,
|
||
"page": 2,
|
||
"content": `{"min": 0, "max": 120}`,
|
||
},
|
||
{
|
||
"title": "Форма контактов",
|
||
"type": "result",
|
||
"description": "Оставьте свои контактные данные.",
|
||
"required": true,
|
||
"page": 2,
|
||
"content": `{"fields": ["name", "email", "phone"]}`,
|
||
},
|
||
}
|
||
|
||
for _, qData := range questionData {
|
||
qData["quiz_id"] = quizResult.Id
|
||
questionResp, err := createQuestionRequest(token, qData)
|
||
assert.NoError(t, err)
|
||
defer questionResp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, questionResp.StatusCode)
|
||
|
||
var questionResult model.Question
|
||
err = json.NewDecoder(questionResp.Body).Decode(&questionResult)
|
||
assert.NoError(t, err)
|
||
questions = append(questions, questionResult)
|
||
}
|
||
|
||
answers := createAnswersInDB(t, quizResult.Id, questions)
|
||
|
||
return &TestData{
|
||
Quiz: quizResult,
|
||
Questions: questions,
|
||
Answers: answers,
|
||
}
|
||
}
|
||
|
||
func createAnswersInDB(t *testing.T, quizID uint64, questions []model.Question) []model.Answer {
|
||
db, err := sql.Open("postgres", postgresCred)
|
||
assert.NoError(t, err)
|
||
defer db.Close()
|
||
|
||
answers := []model.Answer{}
|
||
|
||
sessions := []string{faker.String(), faker.String(), faker.String()}
|
||
|
||
for i, session := range sessions {
|
||
for j, question := range questions {
|
||
if question.Type == "result" {
|
||
continue
|
||
}
|
||
|
||
answerContent := ""
|
||
switch question.Type {
|
||
case "variant":
|
||
answerContent = `{"selected": 1, "answer": "Азот"}`
|
||
case "text":
|
||
answerContent = `{"answer": "Москва"}`
|
||
case "number":
|
||
answerContent = `{"answer": 25}`
|
||
default:
|
||
answerContent = `{"answer": "тестовый ответ"}`
|
||
}
|
||
|
||
query := `
|
||
INSERT INTO answer (content, quiz_id, question_id, fingerprint, session, result, new, deleted, email, device_type, device, browser, ip, os, start, version)
|
||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||
RETURNING id, content, quiz_id, question_id, fingerprint, session, result, new, deleted, email, device_type, device, browser, ip, os, start, version, created_at
|
||
`
|
||
|
||
var answer model.Answer
|
||
err := db.QueryRow(
|
||
query,
|
||
answerContent,
|
||
quizID,
|
||
question.Id,
|
||
fmt.Sprintf("fingerprint_%d_%d", i, j),
|
||
session,
|
||
false,
|
||
true,
|
||
false,
|
||
faker.Email(),
|
||
"desktop",
|
||
"Chrome",
|
||
"Chrome 120.0",
|
||
"192.168.1.1",
|
||
"Windows 10",
|
||
j == 0,
|
||
1,
|
||
).Scan(
|
||
&answer.Id,
|
||
&answer.Content,
|
||
&answer.QuizId,
|
||
&answer.QuestionId,
|
||
&answer.Fingerprint,
|
||
&answer.Session,
|
||
&answer.Result,
|
||
&answer.New,
|
||
&answer.Deleted,
|
||
&answer.Email,
|
||
&answer.DeviceType,
|
||
&answer.Device,
|
||
&answer.Browser,
|
||
&answer.IP,
|
||
&answer.OS,
|
||
&answer.Start,
|
||
&answer.Version,
|
||
&answer.CreatedAt,
|
||
)
|
||
|
||
assert.NoError(t, err)
|
||
answers = append(answers, answer)
|
||
}
|
||
|
||
for _, question := range questions {
|
||
if question.Type == "result" {
|
||
answerContent := `{"name": "Иван Иванов", "email": "ivan@test.com", "phone": "+7-999-123-45-67"}`
|
||
|
||
query := `
|
||
INSERT INTO answer (content, quiz_id, question_id, fingerprint, session, result, new, deleted, email, device_type, device, browser, ip, os, start, version)
|
||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||
RETURNING id, content, quiz_id, question_id, fingerprint, session, result, new, deleted, email, device_type, device, browser, ip, os, start, version, created_at
|
||
`
|
||
|
||
var answer model.Answer
|
||
err := db.QueryRow(
|
||
query,
|
||
answerContent,
|
||
quizID,
|
||
question.Id,
|
||
fmt.Sprintf("fingerprint_result_%d", i),
|
||
session,
|
||
true,
|
||
true,
|
||
false,
|
||
faker.Email(),
|
||
"desktop",
|
||
"Chrome",
|
||
"Chrome 120.0",
|
||
"192.168.1.1",
|
||
"Windows 10",
|
||
false,
|
||
1,
|
||
).Scan(
|
||
&answer.Id,
|
||
&answer.Content,
|
||
&answer.QuizId,
|
||
&answer.QuestionId,
|
||
&answer.Fingerprint,
|
||
&answer.Session,
|
||
&answer.Result,
|
||
&answer.New,
|
||
&answer.Deleted,
|
||
&answer.Email,
|
||
&answer.DeviceType,
|
||
&answer.Device,
|
||
&answer.Browser,
|
||
&answer.IP,
|
||
&answer.OS,
|
||
&answer.Start,
|
||
&answer.Version,
|
||
&answer.CreatedAt,
|
||
)
|
||
|
||
assert.NoError(t, err)
|
||
answers = append(answers, answer)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
return answers
|
||
}
|
||
|
||
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) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования результатов")
|
||
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"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 result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
assert.NotNil(t, result.TotalCount)
|
||
assert.NotNil(t, result.Results)
|
||
|
||
assert.IsType(t, uint64(0), result.TotalCount)
|
||
assert.IsType(t, []model.AnswerExport{}, result.Results)
|
||
|
||
assert.Greater(t, result.TotalCount, uint64(0))
|
||
assert.Greater(t, len(result.Results), 0)
|
||
|
||
for _, answer := range result.Results {
|
||
assert.NotEmpty(t, answer.Id)
|
||
}
|
||
}
|
||
|
||
// отсмотрено
|
||
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"])
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestGetResults_Pagination(t *testing.T) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования пагинации результатов")
|
||
|
||
t.Run("FirstPage", func(t *testing.T) {
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 5,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.LessOrEqual(t, uint64(len(result.Results)), uint64(5))
|
||
assert.Equal(t, result.TotalCount, uint64(len(result.Results)))
|
||
})
|
||
|
||
t.Run("SecondPage", func(t *testing.T) {
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 1,
|
||
"Limit": 5,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.IsType(t, uint64(0), result.TotalCount)
|
||
assert.IsType(t, []model.AnswerExport{}, result.Results)
|
||
})
|
||
|
||
t.Run("EmptyPage", func(t *testing.T) {
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 100,
|
||
"Limit": 5,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.Empty(t, result.Results)
|
||
})
|
||
|
||
t.Run("ZeroLimit", func(t *testing.T) {
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 0,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.Empty(t, result.Results)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestGetResults_Filtering(t *testing.T) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования фильтрации результатов")
|
||
|
||
t.Run("WithDateRange", func(t *testing.T) {
|
||
fromDate := time.Now().AddDate(0, -1, 0).Format("2006-01-02T15:04:05Z")
|
||
toDate := time.Now().AddDate(0, 1, 0).Format("2006-01-02T15:04:05Z")
|
||
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"From": fromDate,
|
||
"To": toDate,
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.IsType(t, uint64(0), result.TotalCount)
|
||
assert.IsType(t, []model.AnswerExport{}, result.Results)
|
||
})
|
||
|
||
t.Run("NewResultsOnly", func(t *testing.T) {
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"New": true,
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
for _, answer := range result.Results {
|
||
assert.True(t, answer.New)
|
||
}
|
||
})
|
||
|
||
t.Run("CombinedFilters", func(t *testing.T) {
|
||
fromDate := time.Now().AddDate(0, -1, 0).Format("2006-01-02T15:04:05Z")
|
||
toDate := time.Now().AddDate(0, 1, 0).Format("2006-01-02T15:04:05Z")
|
||
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"From": fromDate,
|
||
"To": toDate,
|
||
"New": true,
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.IsType(t, uint64(0), result.TotalCount)
|
||
assert.IsType(t, []model.AnswerExport{}, result.Results)
|
||
})
|
||
|
||
t.Run("InvalidDateRange", func(t *testing.T) {
|
||
fromDate := time.Now().AddDate(0, 1, 0).Format("2006-01-02T15:04:05Z")
|
||
toDate := time.Now().AddDate(0, -1, 0).Format("2006-01-02T15:04:05Z")
|
||
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"From": fromDate,
|
||
"To": toDate,
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.Empty(t, result.Results)
|
||
assert.Equal(t, uint64(0), result.TotalCount)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestGetResults_Performance(t *testing.T) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования производительности результатов")
|
||
|
||
t.Run("ResponseTime", func(t *testing.T) {
|
||
start := time.Now()
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
duration := time.Since(start)
|
||
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
|
||
assert.Less(t, duration.Milliseconds(), int64(500))
|
||
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
fmt.Println(result)
|
||
assert.IsType(t, uint64(0), result.TotalCount)
|
||
assert.IsType(t, []model.AnswerExport{}, result.Results)
|
||
})
|
||
|
||
t.Run("ConcurrentRequests", func(t *testing.T) {
|
||
var wg sync.WaitGroup
|
||
errors := make(chan error, 10)
|
||
|
||
for i := 0; i < 10; i++ {
|
||
wg.Add(1)
|
||
go func(requestID int) {
|
||
defer wg.Done()
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 5,
|
||
})
|
||
if err != nil {
|
||
errors <- err
|
||
return
|
||
}
|
||
if resp != nil {
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode == http.StatusOK {
|
||
var result result2.ReqExportResponse
|
||
if decodeErr := json.NewDecoder(resp.Body).Decode(&result); decodeErr != nil {
|
||
errors <- decodeErr
|
||
}
|
||
}
|
||
}
|
||
}(i)
|
||
}
|
||
wg.Wait()
|
||
close(errors)
|
||
|
||
for err := range errors {
|
||
assert.NoError(t, err)
|
||
}
|
||
})
|
||
|
||
t.Run("LargeLimit", func(t *testing.T) {
|
||
start := time.Now()
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 1000,
|
||
})
|
||
duration := time.Since(start)
|
||
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
|
||
assert.Less(t, duration.Milliseconds(), int64(1000))
|
||
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
fmt.Println(result)
|
||
assert.IsType(t, uint64(0), result.TotalCount)
|
||
assert.IsType(t, []model.AnswerExport{}, result.Results)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestGetResults_ErrorHandling(t *testing.T) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования обработки ошибок")
|
||
|
||
t.Run("MalformedJSON", func(t *testing.T) {
|
||
req, err := http.NewRequest("POST", baseURL+fmt.Sprintf("/results/getResults/%v", testData.Quiz.Id), 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("InvalidQuizID", func(t *testing.T) {
|
||
resp, err := getResultsRequest(validToken, "invalid-quiz-id", map[string]interface{}{
|
||
"Page": 0,
|
||
"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, "999999", map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
var result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.Equal(t, uint64(0), result.TotalCount)
|
||
assert.Empty(t, result.Results)
|
||
})
|
||
|
||
t.Run("InvalidPagination", func(t *testing.T) {
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": "invalid-page",
|
||
"Limit": "invalid-limit",
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||
})
|
||
|
||
t.Run("InvalidDateFormat", func(t *testing.T) {
|
||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"From": "invalid-date",
|
||
"To": "invalid-date",
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||
})
|
||
|
||
t.Run("EmptyBody", func(t *testing.T) {
|
||
req, err := http.NewRequest("POST", baseURL+fmt.Sprintf("/results/getResults/%v", testData.Quiz.Id), bytes.NewReader([]byte("{}")))
|
||
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 result result2.ReqExportResponse
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.IsType(t, uint64(0), result.TotalCount)
|
||
assert.IsType(t, []model.AnswerExport{}, result.Results)
|
||
})
|
||
}
|
||
|
||
func deleteResultRequest(token string, resultId string) (*http.Response, error) {
|
||
req, err := http.NewRequest("DELETE", baseURL+"/results/delete/"+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) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования удаления результатов")
|
||
|
||
getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsResp.Body.Close()
|
||
|
||
var resultsData result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData)
|
||
assert.NoError(t, err)
|
||
|
||
firstResult := resultsData.Results[0]
|
||
resultID := fmt.Sprintf("%v", firstResult.Id)
|
||
|
||
resp, err := deleteResultRequest(validToken, resultID)
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
getResultsAfterDeleteResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsAfterDeleteResp.Body.Close()
|
||
|
||
var resultsAfterDelete result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsAfterDeleteResp.Body).Decode(&resultsAfterDelete)
|
||
assert.NoError(t, err)
|
||
|
||
assert.LessOrEqual(t, resultsAfterDelete.TotalCount, resultsData.TotalCount)
|
||
}
|
||
|
||
func TestDeleteResult_Idempotency(t *testing.T) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для идемпотентности удаления результатов")
|
||
|
||
getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 5,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsResp.Body.Close()
|
||
|
||
var resultsData result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData)
|
||
assert.NoError(t, err)
|
||
|
||
if len(resultsData.Results) > 0 {
|
||
firstResult := resultsData.Results[0]
|
||
resultID := fmt.Sprintf("%v", firstResult.Id)
|
||
|
||
resp1, err := deleteResultRequest(validToken, resultID)
|
||
assert.NoError(t, err)
|
||
defer resp1.Body.Close()
|
||
assert.Equal(t, http.StatusOK, resp1.StatusCode)
|
||
|
||
resp2, err := deleteResultRequest(validToken, resultID)
|
||
assert.NoError(t, err)
|
||
defer resp2.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, 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(validToken, "not_a_number")
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||
})
|
||
// todo need 404
|
||
t.Run("NonExistentResultID", func(t *testing.T) {
|
||
resp, err := deleteResultRequest(validToken, "99999999")
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
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(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 := deleteResultRequest(validToken, "-123")
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusBadRequest, 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) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования обновления статуса результатов")
|
||
|
||
getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsResp.Body.Close()
|
||
|
||
var resultsData result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData)
|
||
assert.NoError(t, err)
|
||
|
||
if len(resultsData.Results) >= 2 {
|
||
var answerIDs []int64
|
||
for i := 0; i < 2 && i < len(resultsData.Results); i++ {
|
||
answerIDs = append(answerIDs, int64(resultsData.Results[i].Id))
|
||
}
|
||
|
||
resp, err := updateResultsStatusRequest(validToken, map[string]interface{}{
|
||
"Answers": answerIDs,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
|
||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||
|
||
getResultsAfterUpdateResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsAfterUpdateResp.Body.Close()
|
||
|
||
var resultsAfterUpdate result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsAfterUpdateResp.Body).Decode(&resultsAfterUpdate)
|
||
assert.NoError(t, err)
|
||
|
||
for _, answerID := range answerIDs {
|
||
for _, result := range resultsAfterUpdate.Results {
|
||
if result.Id == uint64(answerID) {
|
||
assert.False(t, result.New, "Результат должен быть помечен как просмотренный")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// отсмотрено
|
||
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) {
|
||
// todo check len
|
||
//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)
|
||
//})
|
||
// todo check len
|
||
//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.StatusNotAcceptable, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestUpdateResultsStatus_Idempotency(t *testing.T) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для идемпотентности обновления статуса")
|
||
getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 5,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsResp.Body.Close()
|
||
|
||
var resultsData result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData)
|
||
assert.NoError(t, err)
|
||
results := resultsData.Results
|
||
|
||
var answerIDs []uint64
|
||
for i := 0; i < 2; i++ {
|
||
result := results[i]
|
||
answerIDs = append(answerIDs, result.Id)
|
||
}
|
||
|
||
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) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для теста производительности обновления статуса")
|
||
getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 20,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsResp.Body.Close()
|
||
|
||
var resultsData result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData)
|
||
assert.NoError(t, err)
|
||
|
||
var answerIDs []uint64
|
||
for i := 0; i < len(resultsData.Results) && i < 10; i++ {
|
||
result := resultsData.Results[i]
|
||
answerIDs = append(answerIDs, result.Id)
|
||
}
|
||
|
||
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))
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
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 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) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для экспорта результатов")
|
||
|
||
resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), 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) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для валидации экспорта")
|
||
|
||
t.Run("InvalidDateFormat", func(t *testing.T) {
|
||
resp, err := exportResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), 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)
|
||
})
|
||
// todo 404
|
||
t.Run("NonExistentQuizID", func(t *testing.T) {
|
||
resp, err := exportResultsRequest(validToken, "99999", map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 10,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
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) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для получения результата")
|
||
|
||
getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 5,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsResp.Body.Close()
|
||
|
||
var resultsData result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData)
|
||
assert.NoError(t, err)
|
||
|
||
firstResult := resultsData.Results[0]
|
||
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 []model.Answer
|
||
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.QuestionId)
|
||
assert.NotEmpty(t, answer.QuizId)
|
||
}
|
||
|
||
}
|
||
|
||
// отсмотрено
|
||
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.StatusNotFound, 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.StatusBadRequest, resp.StatusCode)
|
||
})
|
||
|
||
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) {
|
||
testData := createTestDataForResults(t, validToken, "Квиз для получения результата")
|
||
|
||
getResultsResp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||
"Page": 0,
|
||
"Limit": 1,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer getResultsResp.Body.Close()
|
||
|
||
var resultsData result2.ReqExportResponse
|
||
err = json.NewDecoder(getResultsResp.Body).Decode(&resultsData)
|
||
assert.NoError(t, err)
|
||
results := resultsData.Results
|
||
|
||
firstResult := results[0]
|
||
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 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)
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetDeviceStats_Success(t *testing.T) {
|
||
resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", 111), 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)
|
||
}
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetDeviceStats_WithoutDateRange(t *testing.T) {
|
||
resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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 statistics.DeviceStatResp
|
||
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) {
|
||
t.Run("InvalidDateFormat", func(t *testing.T) {
|
||
resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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 statistics.DeviceStatResp
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
assert.Empty(t, result.Device)
|
||
assert.Empty(t, result.OS)
|
||
assert.Empty(t, result.Browser)
|
||
})
|
||
}
|
||
|
||
// отсмотрено
|
||
func TestGetDeviceStats_Performance(t *testing.T) {
|
||
t.Run("ResponseTime", func(t *testing.T) {
|
||
start := time.Now()
|
||
resp, err := getDeviceStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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", validQuizIDForTestingClickHouse), map[string]interface{}{
|
||
"From": time.Now().Unix() - 100,
|
||
"To": time.Now().Unix(),
|
||
})
|
||
if err == nil && resp != nil {
|
||
resp.Body.Close()
|
||
}
|
||
}()
|
||
}
|
||
wg.Wait()
|
||
})
|
||
}
|
||
|
||
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)
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetGeneralStats_Success(t *testing.T) {
|
||
resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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 statistics.GeneralStatsResp
|
||
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)
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetGeneralStats_WithoutDateRange(t *testing.T) {
|
||
resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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 statistics.GeneralStatsResp
|
||
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)
|
||
})
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetGeneralStats_InputValidation(t *testing.T) {
|
||
t.Run("InvalidDateFormat", func(t *testing.T) {
|
||
resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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)
|
||
})
|
||
// todo
|
||
//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 statistics.GeneralStatsResp
|
||
// err = json.NewDecoder(resp.Body).Decode(&result)
|
||
// assert.NoError(t, err)
|
||
// openStats := result.Open
|
||
// resultStats := result.Result
|
||
// avTimeStats := result.AvTime
|
||
// conversionStats := result.Conversion
|
||
// assert.Empty(t, openStats)
|
||
// assert.Empty(t, resultStats)
|
||
// assert.Empty(t, avTimeStats)
|
||
// assert.Empty(t, conversionStats)
|
||
//})
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetGeneralStats_Performance(t *testing.T) {
|
||
t.Run("ResponseTime", func(t *testing.T) {
|
||
start := time.Now()
|
||
resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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", validQuizIDForTestingClickHouse), map[string]interface{}{
|
||
"From": time.Now().Unix() - 100,
|
||
"To": time.Now().Unix(),
|
||
})
|
||
if err == nil && resp != nil {
|
||
resp.Body.Close()
|
||
}
|
||
}()
|
||
}
|
||
wg.Wait()
|
||
})
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetGeneralStats_BoundaryCases(t *testing.T) {
|
||
t.Run("VeryLargeDateRange", func(t *testing.T) {
|
||
resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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) {
|
||
resp, err := getGeneralStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), map[string]interface{}{
|
||
"From": -1000000,
|
||
"To": -500000,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusBadRequest, 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)
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetQuestionStats_Success(t *testing.T) {
|
||
resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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 statistics.QuestionsStatsResp
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
assert.NoError(t, err)
|
||
|
||
assert.NotEmpty(t, result)
|
||
assert.NotNil(t, result.Funnel)
|
||
assert.NotNil(t, result.FunnelData)
|
||
assert.NotNil(t, result.Results)
|
||
assert.NotNil(t, result.Questions)
|
||
|
||
assert.LessOrEqual(t, len(result.Funnel), 3)
|
||
assert.LessOrEqual(t, len(result.FunnelData), 4)
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetQuestionStats_WithoutDateRange(t *testing.T) {
|
||
resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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 statistics.QuestionsStatsResp
|
||
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)
|
||
})
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetQuestionStats_InputValidation(t *testing.T) {
|
||
t.Run("InvalidDateFormat", func(t *testing.T) {
|
||
resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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)
|
||
})
|
||
// todo
|
||
//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 statistics.QuestionsStatsResp
|
||
// err = json.NewDecoder(resp.Body).Decode(&result)
|
||
// assert.NoError(t, err)
|
||
// assert.NotEmpty(t, result)
|
||
//
|
||
// funnel := result.Funnel
|
||
// funnelData := result.FunnelData
|
||
// results := result.Results
|
||
// questions := result.Questions
|
||
// assert.Empty(t, funnel)
|
||
// assert.Empty(t, funnelData)
|
||
// assert.Empty(t, results)
|
||
// assert.Empty(t, questions)
|
||
//})
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetQuestionStats_Performance(t *testing.T) {
|
||
t.Run("ResponseTime", func(t *testing.T) {
|
||
start := time.Now()
|
||
resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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", validQuizIDForTestingClickHouse), map[string]interface{}{
|
||
"From": time.Now().Unix() - 100,
|
||
"To": time.Now().Unix(),
|
||
})
|
||
if err == nil && resp != nil {
|
||
resp.Body.Close()
|
||
}
|
||
}()
|
||
}
|
||
wg.Wait()
|
||
})
|
||
}
|
||
|
||
// todo нужно заранее в кликхаусе выбрать на чем честить будем
|
||
func TestGetQuestionStats_BoundaryCases(t *testing.T) {
|
||
t.Run("VeryLargeDateRange", func(t *testing.T) {
|
||
resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), 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) {
|
||
resp, err := getQuestionStatsRequest(validToken, fmt.Sprintf("%v", validQuizIDForTestingClickHouse), map[string]interface{}{
|
||
"From": -1000000,
|
||
"To": -500000,
|
||
})
|
||
assert.NoError(t, err)
|
||
defer resp.Body.Close()
|
||
assert.Equal(t, http.StatusBadRequest, 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("<script>alert('xss')</script>")
|
||
// 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, "<script>alert(1)</script>")
|
||
// 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": "<script>alert(1)</script>",
|
||
// "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": "<script>alert(1)</script>",
|
||
// })
|
||
// 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)
|
||
// })
|
||
//}
|