修复项目无法删除问题
This commit is contained in:
@@ -96,16 +96,25 @@ func TestDeleteProjectPostgresIntegration(t *testing.T) {
|
||||
}
|
||||
unused := newProject("DEL"+strings.ToUpper(suffix), "unused deletion project")
|
||||
history := newProject("HIS"+strings.ToUpper(suffix), "history deletion project")
|
||||
history.Status = model.ProjectEnded
|
||||
notEnded := newProject("RUN"+strings.ToUpper(suffix), "running history project")
|
||||
notEnded.Status = model.ProjectRunning
|
||||
if err := db.Create(&unused).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Create(&history).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Create(¬Ended).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
grant := model.UserProject{UserID: admin.ID, ProjectID: unused.ID, CreatedAt: now}
|
||||
if err := db.Create(&grant).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Create(&model.UserProject{UserID: admin.ID, ProjectID: history.ID, CreatedAt: now}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
createdAudit := func(projectID string) model.AuditEntry {
|
||||
return model.AuditEntry{
|
||||
ID: uuid.NewString(), ProjectID: &projectID, ActorUserID: &admin.ID,
|
||||
@@ -130,6 +139,12 @@ func TestDeleteProjectPostgresIntegration(t *testing.T) {
|
||||
if err := db.Create(&queueSession).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
notEndedSession := queueSession
|
||||
notEndedSession.ID = uuid.NewString()
|
||||
notEndedSession.ProjectID = notEnded.ID
|
||||
if err := db.Create(¬EndedSession).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
loginRecorder := httptest.NewRecorder()
|
||||
loginRequest := httptest.NewRequest(http.MethodPost, "/api/admin/auth/login",
|
||||
@@ -201,20 +216,25 @@ func TestDeleteProjectPostgresIntegration(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("project with queue history is rejected intact", func(t *testing.T) {
|
||||
t.Run("ended project with queue history is archived intact", func(t *testing.T) {
|
||||
response := deleteRequest(history.ID)
|
||||
if response.Code != http.StatusConflict {
|
||||
t.Fatalf("delete history project status = %d, want 409; body = %s", response.Code, response.Body.String())
|
||||
if response.Code != http.StatusNoContent {
|
||||
t.Fatalf("archive history project status = %d, want 204; body = %s", response.Code, response.Body.String())
|
||||
}
|
||||
if !strings.Contains(response.Body.String(), `"code":"PROJECT_HAS_HISTORY"`) {
|
||||
t.Fatalf("delete history project body = %s, want PROJECT_HAS_HISTORY", response.Body.String())
|
||||
}
|
||||
if !strings.Contains(response.Body.String(), "不能删除") || !strings.Contains(response.Body.String(), "结束") {
|
||||
t.Fatalf("delete history project message is not actionable Chinese: %s", response.Body.String())
|
||||
}
|
||||
if err := db.First(&model.Project{}, "id = ?", history.ID).Error; err != nil {
|
||||
var archived model.Project
|
||||
if err := db.First(&archived, "id = ?", history.ID).Error; err != nil {
|
||||
t.Fatalf("history project was not retained: %v", err)
|
||||
}
|
||||
if archived.ArchivedAt == nil || !archived.ArchivedAt.Equal(now) {
|
||||
t.Fatalf("archived_at = %v, want %v", archived.ArchivedAt, now)
|
||||
}
|
||||
var archivedGrantCount int64
|
||||
if err := db.Model(&model.UserProject{}).Where("project_id = ?", history.ID).Count(&archivedGrantCount).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if archivedGrantCount != 0 {
|
||||
t.Fatalf("archived project grants = %d, want 0", archivedGrantCount)
|
||||
}
|
||||
if err := db.First(&model.QueueSession{}, "id = ?", queueSession.ID).Error; err != nil {
|
||||
t.Fatalf("queue session was not retained: %v", err)
|
||||
}
|
||||
@@ -225,14 +245,59 @@ func TestDeleteProjectPostgresIntegration(t *testing.T) {
|
||||
if retained.ProjectID == nil || *retained.ProjectID != history.ID {
|
||||
t.Fatalf("history audit project_id = %v, want %s", retained.ProjectID, history.ID)
|
||||
}
|
||||
var deletedAuditCount int64
|
||||
if err := db.Model(&model.AuditEntry{}).
|
||||
Where("action = ? AND entity_id = ?", "PROJECT_DELETED", history.ID).
|
||||
Count(&deletedAuditCount).Error; err != nil {
|
||||
var archivedAudit model.AuditEntry
|
||||
if err := db.Where("action = ? AND entity_id = ?", "PROJECT_ARCHIVED", history.ID).First(&archivedAudit).Error; err != nil {
|
||||
t.Fatalf("load PROJECT_ARCHIVED audit: %v", err)
|
||||
}
|
||||
if archivedAudit.ProjectID == nil || *archivedAudit.ProjectID != history.ID {
|
||||
t.Fatalf("PROJECT_ARCHIVED project_id = %v, want %s", archivedAudit.ProjectID, history.ID)
|
||||
}
|
||||
second := deleteRequest(history.ID)
|
||||
if second.Code != http.StatusNotFound {
|
||||
t.Fatalf("second archive status = %d, want 404; body = %s", second.Code, second.Body.String())
|
||||
}
|
||||
|
||||
requestAdmin := func(method, path, body string) *httptest.ResponseRecorder {
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(method, path, strings.NewReader(body))
|
||||
request.AddCookie(adminCookie)
|
||||
server.Handler().ServeHTTP(recorder, request)
|
||||
return recorder
|
||||
}
|
||||
profile := requestAdmin(http.MethodPut, "/api/admin/projects/"+history.ID,
|
||||
`{"name":"archived","code":"`+history.Code+`","timezone":"Asia/Shanghai","ticket_prefix":"A"}`)
|
||||
if profile.Code != http.StatusNotFound {
|
||||
t.Fatalf("update archived project status = %d, want 404; body = %s", profile.Code, profile.Body.String())
|
||||
}
|
||||
settings := requestAdmin(http.MethodPut, "/api/admin/projects/"+history.ID+"/settings", `{"status":"ENDED"}`)
|
||||
if settings.Code != http.StatusNotFound {
|
||||
t.Fatalf("update archived settings status = %d, want 404; body = %s", settings.Code, settings.Body.String())
|
||||
}
|
||||
createUser := requestAdmin(http.MethodPost, "/api/admin/users",
|
||||
`{"username":"archived_grant_`+suffix+`","password":"Password123!","role":"STAFF","project_ids":["`+history.ID+`"]}`)
|
||||
if createUser.Code != http.StatusUnprocessableEntity || !strings.Contains(createUser.Body.String(), `"code":"INVALID_PROJECT"`) {
|
||||
t.Fatalf("grant archived project status = %d, body = %s; want 422 INVALID_PROJECT", createUser.Code, createUser.Body.String())
|
||||
}
|
||||
adminUsers := requestAdmin(http.MethodGet, "/api/admin/users", "")
|
||||
if adminUsers.Code != http.StatusOK {
|
||||
t.Fatalf("admin users status = %d, want 200; body = %s", adminUsers.Code, adminUsers.Body.String())
|
||||
}
|
||||
if strings.Contains(adminUsers.Body.String(), history.ID) {
|
||||
t.Fatalf("admin users leaked archived project id: %s", adminUsers.Body.String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("project with history must be ended before archival", func(t *testing.T) {
|
||||
response := deleteRequest(notEnded.ID)
|
||||
if response.Code != http.StatusConflict || !strings.Contains(response.Body.String(), `"code":"PROJECT_MUST_BE_ENDED"`) {
|
||||
t.Fatalf("archive running project status = %d, body = %s; want 409 PROJECT_MUST_BE_ENDED", response.Code, response.Body.String())
|
||||
}
|
||||
var retained model.Project
|
||||
if err := db.First(&retained, "id = ?", notEnded.ID).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if deletedAuditCount != 0 {
|
||||
t.Fatalf("PROJECT_DELETED audit count for retained project = %d, want 0", deletedAuditCount)
|
||||
if retained.ArchivedAt != nil {
|
||||
t.Fatalf("running project archived_at = %v, want nil", retained.ArchivedAt)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user