/
advanceddev
/
license-server
Обзор
Документация
Войти
/
advanceddev
/
license-server
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
2
CI/CD
Аналитика
Безопасность
master
internal/handler/admin_handler_test.go
324 строки
9 KB
advanceddev
feat: add custom params (JSONB) to licenses
09 авг 2026, 23:34
Не верифицирован
09 авг 2026, 23:34
64a191a
Код
Авторство
О чём код?
package handler import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "time" "github.com/go-chi/chi/v5" "github.com/google/uuid" "gitverse.ru/advanceddev/license-server/internal/domain" ) // mockLicenseRepo — in-memory реализация для тестов type mockLicenseRepo struct { licenses map[uuid.UUID]*domain.License byHash map[string]*domain.License } func newMockRepo() *mockLicenseRepo { return &mockLicenseRepo{ licenses: make(map[uuid.UUID]*domain.License), byHash: make(map[string]*domain.License), } } func (m *mockLicenseRepo) Create(_ context.Context, l *domain.License) error { if l.Params == nil { l.Params = make(map[string]any) } m.licenses[l.ID] = l m.byHash[l.KeyHash] = l return nil } func TestCreateLicense_WithParams(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) body := `{ "partner_id": "550e8400-e29b-41d4-a716-446655440000", "brand_name": "Test", "params": {"theme": "dark", "max_orders": 100} }` req := httptest.NewRequest(http.MethodPost, "/api/v1/admin/licenses", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() h.Create(w, req) if w.Code != http.StatusCreated { t.Fatalf("expected 201, got %d: %s", w.Code, w.Body.String()) } } func (m *mockLicenseRepo) GetByKeyHash(_ context.Context, hash string) (*domain.License, error) { l, ok := m.byHash[hash] if !ok { return nil, domain.ErrLicenseNotFound } return l, nil } func (m *mockLicenseRepo) GetByID(_ context.Context, id uuid.UUID) (*domain.License, error) { l, ok := m.licenses[id] if !ok { return nil, domain.ErrLicenseNotFound } return l, nil } func (m *mockLicenseRepo) GetByPartnerID(_ context.Context, pid uuid.UUID) (*domain.License, error) { for _, l := range m.licenses { if l.PartnerID == pid && l.ExpiresAt.After(time.Now()) { return l, nil } } return nil, domain.ErrLicenseNotFound } func (m *mockLicenseRepo) List(_ context.Context, _, _ int) ([]domain.License, int, error) { result := make([]domain.License, 0) for _, l := range m.licenses { result = append(result, *l) } return result, len(result), nil } func (m *mockLicenseRepo) Update(_ context.Context, id uuid.UUID, input domain.UpdateLicenseInput) (*domain.License, error) { l, ok := m.licenses[id] if !ok { return nil, domain.ErrLicenseNotFound } if input.BrandName != nil { l.BrandName = *input.BrandName } if input.ExpiresAt != nil { l.ExpiresAt = *input.ExpiresAt } l.UpdatedAt = time.Now() return l, nil } func (m *mockLicenseRepo) Delete(_ context.Context, id uuid.UUID) error { l, ok := m.licenses[id] if !ok { return domain.ErrLicenseNotFound } delete(m.byHash, l.KeyHash) delete(m.licenses, id) return nil } func setupAdminRouter(h *AdminHandler) *chi.Mux { r := chi.NewRouter() r.Post("/api/v1/admin/licenses", h.Create) r.Get("/api/v1/admin/licenses", h.List) r.Put("/api/v1/admin/licenses/{id}", h.Update) r.Delete("/api/v1/admin/licenses/{id}", h.Delete) return r } func TestCreateLicense_Success(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) body := `{ "partner_id": "550e8400-e29b-41d4-a716-446655440000", "brand_name": "Test Brand" }` req := httptest.NewRequest(http.MethodPost, "/api/v1/admin/licenses", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() h.Create(w, req) if w.Code != http.StatusCreated { t.Fatalf("expected 201, got %d: %s", w.Code, w.Body.String()) } } func TestCreateLicense_UnknownField(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) body := `{ "partner_id": "550e8400-e29b-41d4-a716-446655440000", "brand_name": "Test", "extra_field": "bad" }` req := httptest.NewRequest(http.MethodPost, "/api/v1/admin/licenses", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() h.Create(w, req) if w.Code != http.StatusBadRequest { t.Fatalf("expected 400, got %d: %s", w.Code, w.Body.String()) } } func TestCreateLicense_MissingPartnerID(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) body := `{"brand_name": "Test"}` req := httptest.NewRequest(http.MethodPost, "/api/v1/admin/licenses", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() h.Create(w, req) if w.Code != http.StatusUnprocessableEntity { t.Fatalf("expected 422, got %d: %s", w.Code, w.Body.String()) } } func TestListLicenses_Empty(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/licenses", nil) w := httptest.NewRecorder() h.List(w, req) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } if !strings.Contains(w.Body.String(), `"data":[]`) { t.Errorf("expected empty array, got: %s", w.Body.String()) } } func TestCreateLicense_DuplicatePartner(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) body := `{ "partner_id": "550e8400-e29b-41d4-a716-446655440000", "brand_name": "First Brand" }` req := httptest.NewRequest(http.MethodPost, "/api/v1/admin/licenses", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() h.Create(w, req) if w.Code != http.StatusCreated { t.Fatalf("first create should succeed, got %d: %s", w.Code, w.Body.String()) } req2 := httptest.NewRequest(http.MethodPost, "/api/v1/admin/licenses", strings.NewReader(body)) req2.Header.Set("Content-Type", "application/json") w2 := httptest.NewRecorder() h.Create(w2, req2) if w2.Code != http.StatusConflict { t.Fatalf("duplicate should return 409, got %d: %s", w2.Code, w2.Body.String()) } } func TestUpdateLicense_NotFound(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) r := setupAdminRouter(h) body := `{"brand_name": "Updated"}` fakeID := uuid.New().String() req := httptest.NewRequest(http.MethodPut, "/api/v1/admin/licenses/"+fakeID, strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusNotFound { t.Fatalf("expected 404, got %d: %s", w.Code, w.Body.String()) } } func TestUpdateLicense_Success(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) r := setupAdminRouter(h) createBody := `{ "partner_id": "550e8400-e29b-41d4-a716-446655440000", "brand_name": "Original" }` createReq := httptest.NewRequest(http.MethodPost, "/api/v1/admin/licenses", strings.NewReader(createBody)) createReq.Header.Set("Content-Type", "application/json") createW := httptest.NewRecorder() h.Create(createW, createReq) var created map[string]any json.Unmarshal(createW.Body.Bytes(), &created) id := created["id"].(string) updateBody := `{"brand_name": "Updated Brand"}` updateReq := httptest.NewRequest(http.MethodPut, "/api/v1/admin/licenses/"+id, strings.NewReader(updateBody)) updateReq.Header.Set("Content-Type", "application/json") updateW := httptest.NewRecorder() r.ServeHTTP(updateW, updateReq) if updateW.Code != http.StatusOK { t.Fatalf("expected 200, got %d: %s", updateW.Code, updateW.Body.String()) } var updated map[string]any json.Unmarshal(updateW.Body.Bytes(), &updated) if updated["brand_name"] != "Updated Brand" { t.Errorf("expected brand_name 'Updated Brand', got %v", updated["brand_name"]) } } func TestDeleteLicense_Success(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) r := setupAdminRouter(h) partnerID := uuid.MustParse("550e8400-e29b-41d4-a716-446655440000") license := &domain.License{ ID: uuid.New(), KeyHash: "testhash", PartnerID: partnerID, BrandName: "To Delete", Params: map[string]any{"test": "value"}, ExpiresAt: time.Now().Add(365 * 24 * time.Hour), } repo.Create(context.Background(), license) req := httptest.NewRequest(http.MethodDelete, "/api/v1/admin/licenses/"+license.ID.String(), nil) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) } } func TestDeleteLicense_NotFound(t *testing.T) { repo := newMockRepo() h := NewAdminHandler(repo, nil, nil, 365*24*time.Hour) r := setupAdminRouter(h) fakeID := uuid.New().String() req := httptest.NewRequest(http.MethodDelete, "/api/v1/admin/licenses/"+fakeID, nil) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusNotFound { t.Fatalf("expected 404, got %d: %s", w.Code, w.Body.String()) } }