Files
at-container-registry/pkg/appview/handlers/delete_test.go
T

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")
}
}