mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-08-30 12:46:57 +00:00
331 lines
8.8 KiB
Go
331 lines
8.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"atcr.io/pkg/appview/db"
|
|
"atcr.io/pkg/appview/middleware"
|
|
_ "github.com/tursodatabase/go-libsql"
|
|
)
|
|
|
|
func TestDeleteAccountHandler_Unauthorized(t *testing.T) {
|
|
database := setupTestDB(t)
|
|
defer database.Close()
|
|
|
|
handler := &DeleteAccountHandler{
|
|
BaseUIHandler: BaseUIHandler{
|
|
DB: database,
|
|
OAuthStore: nil,
|
|
Refresher: nil,
|
|
},
|
|
}
|
|
|
|
reqBody := DeleteAccountRequest{
|
|
DeletePDSRecords: false,
|
|
Confirmation: "DELETE test.bsky.social",
|
|
}
|
|
body, _ := json.Marshal(reqBody)
|
|
req := httptest.NewRequest("DELETE", "/api/account", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusUnauthorized {
|
|
t.Errorf("Expected status %d, got %d", http.StatusUnauthorized, rr.Code)
|
|
}
|
|
}
|
|
|
|
func TestDeleteAccountHandler_MissingConfirmation(t *testing.T) {
|
|
database := setupTestDB(t)
|
|
defer database.Close()
|
|
|
|
// Create test user
|
|
testUser := &db.User{
|
|
DID: "did:plc:test123",
|
|
Handle: "test.bsky.social",
|
|
PDSEndpoint: "https://bsky.social",
|
|
LastSeen: time.Now(),
|
|
}
|
|
if err := db.UpsertUser(database, testUser); err != nil {
|
|
t.Fatalf("Failed to create user: %v", err)
|
|
}
|
|
|
|
handler := &DeleteAccountHandler{
|
|
BaseUIHandler: BaseUIHandler{
|
|
DB: database,
|
|
OAuthStore: nil,
|
|
Refresher: nil,
|
|
},
|
|
}
|
|
|
|
// Request without confirmation
|
|
reqBody := DeleteAccountRequest{
|
|
DeletePDSRecords: false,
|
|
Confirmation: "",
|
|
}
|
|
body, _ := json.Marshal(reqBody)
|
|
req := httptest.NewRequest("DELETE", "/api/account", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req = middleware.WithUser(req, testUser)
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusBadRequest {
|
|
t.Errorf("Expected status %d, got %d", http.StatusBadRequest, rr.Code)
|
|
}
|
|
}
|
|
|
|
func TestDeleteAccountHandler_WrongConfirmation(t *testing.T) {
|
|
database := setupTestDB(t)
|
|
defer database.Close()
|
|
|
|
testUser := &db.User{
|
|
DID: "did:plc:test123",
|
|
Handle: "test.bsky.social",
|
|
PDSEndpoint: "https://bsky.social",
|
|
LastSeen: time.Now(),
|
|
}
|
|
if err := db.UpsertUser(database, testUser); err != nil {
|
|
t.Fatalf("Failed to create user: %v", err)
|
|
}
|
|
|
|
handler := &DeleteAccountHandler{
|
|
BaseUIHandler: BaseUIHandler{
|
|
DB: database,
|
|
OAuthStore: nil,
|
|
Refresher: nil,
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
confirmation string
|
|
}{
|
|
{"just DELETE", "DELETE"},
|
|
{"wrong handle", "DELETE wrong.handle"},
|
|
{"lowercase", "delete test.bsky.social"},
|
|
{"extra spaces", "DELETE test.bsky.social"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
reqBody := DeleteAccountRequest{
|
|
DeletePDSRecords: false,
|
|
Confirmation: tt.confirmation,
|
|
}
|
|
body, _ := json.Marshal(reqBody)
|
|
req := httptest.NewRequest("DELETE", "/api/account", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req = middleware.WithUser(req, testUser)
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusBadRequest {
|
|
t.Errorf("Expected status %d for confirmation %q, got %d", http.StatusBadRequest, tt.confirmation, rr.Code)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteAccountHandler_SuccessfulDeletion(t *testing.T) {
|
|
database := setupTestDB(t)
|
|
defer database.Close()
|
|
|
|
// Create test user with some data
|
|
testUser := &db.User{
|
|
DID: "did:plc:test123",
|
|
Handle: "test.bsky.social",
|
|
PDSEndpoint: "https://bsky.social",
|
|
LastSeen: time.Now(),
|
|
}
|
|
if err := db.UpsertUser(database, testUser); err != nil {
|
|
t.Fatalf("Failed to create user: %v", err)
|
|
}
|
|
|
|
// Create some manifests for the user
|
|
_, err := database.Exec(`
|
|
INSERT INTO manifests (did, repository, digest, hold_endpoint, schema_version, media_type, created_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
`, testUser.DID, "myapp", "sha256:abc123", "did:web:hold.example.com", 2,
|
|
"application/vnd.oci.image.manifest.v1+json", time.Now())
|
|
if err != nil {
|
|
t.Fatalf("Failed to create manifest: %v", err)
|
|
}
|
|
|
|
// Create OAuth store for testing
|
|
oauthStore := db.NewOAuthStore(database)
|
|
|
|
handler := &DeleteAccountHandler{
|
|
BaseUIHandler: BaseUIHandler{
|
|
DB: database,
|
|
OAuthStore: oauthStore,
|
|
Refresher: nil, // No remote operations in this test
|
|
},
|
|
}
|
|
|
|
reqBody := DeleteAccountRequest{
|
|
DeletePDSRecords: false,
|
|
Confirmation: "DELETE test.bsky.social",
|
|
}
|
|
body, _ := json.Marshal(reqBody)
|
|
req := httptest.NewRequest("DELETE", "/api/account", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req = middleware.WithUser(req, testUser)
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Errorf("Expected status %d, got %d. Body: %s", http.StatusOK, rr.Code, rr.Body.String())
|
|
}
|
|
|
|
var response DeleteAccountResponse
|
|
if err := json.NewDecoder(rr.Body).Decode(&response); err != nil {
|
|
t.Fatalf("Failed to decode response: %v", err)
|
|
}
|
|
|
|
if !response.Success {
|
|
t.Error("Expected success=true")
|
|
}
|
|
if !response.AppViewDeleted {
|
|
t.Error("Expected appview_deleted=true")
|
|
}
|
|
|
|
// Verify user was actually deleted
|
|
var count int
|
|
err = database.QueryRow("SELECT COUNT(*) FROM users WHERE did = ?", testUser.DID).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("Failed to query user: %v", err)
|
|
}
|
|
if count != 0 {
|
|
t.Error("Expected user to be deleted from database")
|
|
}
|
|
|
|
// Verify manifests were cascade deleted
|
|
err = database.QueryRow("SELECT COUNT(*) FROM manifests WHERE did = ?", testUser.DID).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("Failed to query manifests: %v", err)
|
|
}
|
|
if count != 0 {
|
|
t.Error("Expected manifests to be cascade deleted")
|
|
}
|
|
}
|
|
|
|
func TestDeleteAccountHandler_InvalidJSON(t *testing.T) {
|
|
database := setupTestDB(t)
|
|
defer database.Close()
|
|
|
|
testUser := &db.User{
|
|
DID: "did:plc:test123",
|
|
Handle: "test.bsky.social",
|
|
PDSEndpoint: "https://bsky.social",
|
|
LastSeen: time.Now(),
|
|
}
|
|
if err := db.UpsertUser(database, testUser); err != nil {
|
|
t.Fatalf("Failed to create user: %v", err)
|
|
}
|
|
|
|
handler := &DeleteAccountHandler{
|
|
BaseUIHandler: BaseUIHandler{
|
|
DB: database,
|
|
OAuthStore: nil,
|
|
Refresher: nil,
|
|
},
|
|
}
|
|
|
|
req := httptest.NewRequest("DELETE", "/api/account", bytes.NewReader([]byte("not json")))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req = middleware.WithUser(req, testUser)
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusBadRequest {
|
|
t.Errorf("Expected status %d, got %d", http.StatusBadRequest, rr.Code)
|
|
}
|
|
}
|
|
|
|
func TestDeleteAccountHandler_DeletesHoldMembershipData(t *testing.T) {
|
|
database := setupTestDB(t)
|
|
defer database.Close()
|
|
|
|
testUser := &db.User{
|
|
DID: "did:plc:test123",
|
|
Handle: "test.bsky.social",
|
|
PDSEndpoint: "https://bsky.social",
|
|
LastSeen: time.Now(),
|
|
}
|
|
if err := db.UpsertUser(database, testUser); err != nil {
|
|
t.Fatalf("Failed to create user: %v", err)
|
|
}
|
|
|
|
// Create hold membership data (these tables don't cascade)
|
|
_, err := database.Exec(`
|
|
INSERT INTO hold_crew_approvals (hold_did, user_did, approved_at, expires_at)
|
|
VALUES (?, ?, ?, ?)
|
|
`, "did:web:hold.example.com", testUser.DID, time.Now(), time.Now().Add(24*time.Hour))
|
|
if err != nil {
|
|
t.Fatalf("Failed to create crew approval: %v", err)
|
|
}
|
|
|
|
_, err = database.Exec(`
|
|
INSERT INTO hold_crew_members (hold_did, member_did, rkey, permissions)
|
|
VALUES (?, ?, ?, ?)
|
|
`, "did:web:hold.example.com", testUser.DID, "member1", `["blob:read","blob:write"]`)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create crew member: %v", err)
|
|
}
|
|
|
|
oauthStore := db.NewOAuthStore(database)
|
|
|
|
handler := &DeleteAccountHandler{
|
|
BaseUIHandler: BaseUIHandler{
|
|
DB: database,
|
|
OAuthStore: oauthStore,
|
|
Refresher: nil,
|
|
},
|
|
}
|
|
|
|
reqBody := DeleteAccountRequest{
|
|
DeletePDSRecords: false,
|
|
Confirmation: "DELETE test.bsky.social",
|
|
}
|
|
body, _ := json.Marshal(reqBody)
|
|
req := httptest.NewRequest("DELETE", "/api/account", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req = middleware.WithUser(req, testUser)
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Errorf("Expected status %d, got %d", http.StatusOK, rr.Code)
|
|
}
|
|
|
|
// Verify hold membership data was deleted
|
|
var count int
|
|
err = database.QueryRow("SELECT COUNT(*) FROM hold_crew_approvals WHERE user_did = ?", testUser.DID).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("Failed to query crew approvals: %v", err)
|
|
}
|
|
if count != 0 {
|
|
t.Error("Expected crew approvals to be deleted")
|
|
}
|
|
|
|
err = database.QueryRow("SELECT COUNT(*) FROM hold_crew_members WHERE member_did = ?", testUser.DID).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("Failed to query crew members: %v", err)
|
|
}
|
|
if count != 0 {
|
|
t.Error("Expected crew members to be deleted")
|
|
}
|
|
}
|