core/tests/main_test.go

10074 lines
308 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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