Files
OwnCord/Server/admin/handlers_channels_test.go
T
Claude c9099f04e7 fix compile errors and wire permission cache invalidation
Critical fixes:
- Move svc creation in router.go above MountInviteRoutes/MountChannelRoutes
  (was used before definition — compile error)
- Restore hasChannelPermREST in channel_handler.go for upload_handler.go
  (was removed but still referenced — compile error)

Permission cache invalidation:
- Add PermissionInvalidator interface to admin package
- Wire through NewHandler → NewAdminAPI → handlePatchUser
- Call InvalidateUser(userID) after role changes in admin panel
- Update all admin test files to pass nil as new parameter

Also clarifies WithTx documentation for SQLite single-writer semantics.

https://claude.ai/code/session_01CBFF3r84ywkJRWwuqw8zD8
2026-04-05 21:25:35 +00:00

143 lines
4.5 KiB
Go

package admin_test
import (
"encoding/json"
"net/http"
"testing"
"github.com/owncord/server/admin"
)
// ─── Category-Type Validation (via POST /channels) ──────────────────────────
func TestCreateChannel_TextUnderTextCategory_OK(t *testing.T) {
database := openAdminTestDB(t)
handler := admin.NewAdminAPI(database, "1.0.0", &mockHub{}, nil, nil, nil, nil)
token := createAdminUser(t, database)
body := map[string]any{
"name": "general",
"type": "text",
"category": "Chat",
}
w := doRequest(t, handler, http.MethodPost, "/channels", token, body)
if w.Code != http.StatusCreated {
t.Errorf("text channel under Chat: status = %d, want 201; body: %s", w.Code, w.Body.String())
}
}
func TestCreateChannel_AnnouncementUnderTextCategory_OK(t *testing.T) {
database := openAdminTestDB(t)
handler := admin.NewAdminAPI(database, "1.0.0", &mockHub{}, nil, nil, nil, nil)
token := createAdminUser(t, database)
body := map[string]any{
"name": "announcements",
"type": "announcement",
"category": "Text Channels",
}
w := doRequest(t, handler, http.MethodPost, "/channels", token, body)
if w.Code != http.StatusCreated {
t.Errorf("announcement under Text Channels: status = %d, want 201; body: %s", w.Code, w.Body.String())
}
}
func TestCreateChannel_VoiceUnderVoiceCategory_OK(t *testing.T) {
database := openAdminTestDB(t)
handler := admin.NewAdminAPI(database, "1.0.0", &mockHub{}, nil, nil, nil, nil)
token := createAdminUser(t, database)
body := map[string]any{
"name": "lounge",
"type": "voice",
"category": "Voice Channels",
}
w := doRequest(t, handler, http.MethodPost, "/channels", token, body)
if w.Code != http.StatusCreated {
t.Errorf("voice under Voice Channels: status = %d, want 201; body: %s", w.Code, w.Body.String())
}
}
func TestCreateChannel_VoiceUnderTextCategory_Rejected(t *testing.T) {
database := openAdminTestDB(t)
handler := admin.NewAdminAPI(database, "1.0.0", &mockHub{}, nil, nil, nil, nil)
token := createAdminUser(t, database)
body := map[string]any{
"name": "bad-voice",
"type": "voice",
"category": "Chat",
}
w := doRequest(t, handler, http.MethodPost, "/channels", token, body)
if w.Code != http.StatusBadRequest {
t.Errorf("voice under Chat: status = %d, want 400; body: %s", w.Code, w.Body.String())
}
var resp map[string]string
if err := json.Unmarshal(w.Body.Bytes(), &resp); err == nil {
if resp["error"] != "INVALID_INPUT" {
t.Errorf("error code = %q, want INVALID_INPUT", resp["error"])
}
}
}
func TestCreateChannel_TextUnderVoiceCategory_Rejected(t *testing.T) {
database := openAdminTestDB(t)
handler := admin.NewAdminAPI(database, "1.0.0", &mockHub{}, nil, nil, nil, nil)
token := createAdminUser(t, database)
body := map[string]any{
"name": "bad-text",
"type": "text",
"category": "Voice Channels",
}
w := doRequest(t, handler, http.MethodPost, "/channels", token, body)
if w.Code != http.StatusBadRequest {
t.Errorf("text under Voice Channels: status = %d, want 400; body: %s", w.Code, w.Body.String())
}
}
func TestCreateChannel_EmptyCategory_Allowed(t *testing.T) {
database := openAdminTestDB(t)
handler := admin.NewAdminAPI(database, "1.0.0", &mockHub{}, nil, nil, nil, nil)
token := createAdminUser(t, database)
body := map[string]any{
"name": "uncategorized",
"type": "voice",
"category": "",
}
w := doRequest(t, handler, http.MethodPost, "/channels", token, body)
if w.Code != http.StatusCreated {
t.Errorf("voice with empty category: status = %d, want 201; body: %s", w.Code, w.Body.String())
}
}
func TestCreateChannel_CaseInsensitiveVoiceCategory(t *testing.T) {
database := openAdminTestDB(t)
handler := admin.NewAdminAPI(database, "1.0.0", &mockHub{}, nil, nil, nil, nil)
token := createAdminUser(t, database)
// "VOICE" in uppercase should still be treated as a voice category
body := map[string]any{
"name": "vc",
"type": "voice",
"category": "VOICE CHANNELS",
}
w := doRequest(t, handler, http.MethodPost, "/channels", token, body)
if w.Code != http.StatusCreated {
t.Errorf("voice under VOICE CHANNELS: status = %d, want 201; body: %s", w.Code, w.Body.String())
}
// Text under uppercase VOICE should be rejected
body2 := map[string]any{
"name": "bad",
"type": "text",
"category": "VOICE CHANNELS",
}
w2 := doRequest(t, handler, http.MethodPost, "/channels", token, body2)
if w2.Code != http.StatusBadRequest {
t.Errorf("text under VOICE CHANNELS: status = %d, want 400; body: %s", w2.Code, w2.Body.String())
}
}