mirror of
https://github.com/hanzoai/team.git
synced 2026-09-30 01:57:35 +00:00
* Report POC * Including more error logs * Added localisationj for each reviewer * Optimisations * Minor tweaks * restored go module files * lint fixes * Added back transslations * Added translations * linter and test fixes * restored go module files * e2e lint fix * lint fixes * AI fixes * fixed typo * fixed nil pointer error * Added more tests * Publish report even if deletion fails * Fixed the e2e test * Distinguished between no data and deleted data * lint fixes * fixed tests * e2e test fix * Updated test to also upload actual file * Removed file name tracking * Text updates * fixed e2e test * lint fix
425 lines
12 KiB
Go
425 lines
12 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||
// See LICENSE.txt for license information.
|
||
|
||
package model
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/stretchr/testify/assert"
|
||
"github.com/stretchr/testify/require"
|
||
)
|
||
|
||
// stubTranslateFunc returns translation IDs as-is, or interpolates params if provided.
|
||
// This mimics the i18n.TranslateFunc signature for unit tests without loading real locale files.
|
||
func stubTranslateFunc(id string, args ...any) string {
|
||
for _, arg := range args {
|
||
if params, ok := arg.(map[string]any); ok {
|
||
result := id
|
||
for k, v := range params {
|
||
result = strings.ReplaceAll(result, fmt.Sprintf("{{.%s}}", k), fmt.Sprintf("%v", v))
|
||
}
|
||
return result
|
||
}
|
||
}
|
||
return id
|
||
}
|
||
|
||
func TestDeletionStepStatusIcon(t *testing.T) {
|
||
tests := []struct {
|
||
status DeletionStepStatus
|
||
expected string
|
||
}{
|
||
{StepSuccess, "✅"},
|
||
{StepFailed, "❌"},
|
||
{StepPartial, "⚠️"},
|
||
{StepNotApplicable, "➖"},
|
||
{DeletionStepStatus(99), "❓"},
|
||
}
|
||
|
||
for _, tc := range tests {
|
||
assert.Equal(t, tc.expected, tc.status.Icon())
|
||
}
|
||
}
|
||
|
||
func TestDeletionStepStatusLabel(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
|
||
assert.Equal(t, "app.data_spillage.report.status.removed", StepSuccess.Label(T))
|
||
assert.Equal(t, "app.data_spillage.report.status.failed", StepFailed.Label(T))
|
||
assert.Equal(t, "app.data_spillage.report.status.partial", StepPartial.Label(T))
|
||
assert.Equal(t, "app.data_spillage.report.status.not_applicable", StepNotApplicable.Label(T))
|
||
assert.Equal(t, "app.data_spillage.report.status.unknown", DeletionStepStatus(99).Label(T))
|
||
}
|
||
|
||
func TestPostDeletionReportAddStep(t *testing.T) {
|
||
report := &PostDeletionReport{
|
||
PostID: "post1",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.AddStep("step1", StepSuccess, "detail1", nil)
|
||
report.AddStep("step2", StepFailed, "detail2", []string{"err1"})
|
||
|
||
require.Len(t, report.Steps, 2)
|
||
|
||
assert.Equal(t, "step1", report.Steps[0].Name)
|
||
assert.Equal(t, StepSuccess, report.Steps[0].Status)
|
||
assert.Equal(t, "detail1", report.Steps[0].Detail)
|
||
assert.Nil(t, report.Steps[0].Errors)
|
||
|
||
assert.Equal(t, "step2", report.Steps[1].Name)
|
||
assert.Equal(t, StepFailed, report.Steps[1].Status)
|
||
assert.Equal(t, []string{"err1"}, report.Steps[1].Errors)
|
||
}
|
||
|
||
func TestPostDeletionReportAddStepWithParams(t *testing.T) {
|
||
report := &PostDeletionReport{
|
||
PostID: "post1",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
params := map[string]any{"Count": 5}
|
||
report.AddStepWithParams("step1", StepSuccess, "detail", params, nil)
|
||
|
||
require.Len(t, report.Steps, 1)
|
||
assert.Equal(t, params, report.Steps[0].DetailParams)
|
||
}
|
||
|
||
func TestPostDeletionReportCountStatuses(t *testing.T) {
|
||
report := &PostDeletionReport{
|
||
PostID: "post1",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.AddStep("s1", StepSuccess, "", nil)
|
||
report.AddStep("s2", StepSuccess, "", nil)
|
||
report.AddStep("s3", StepFailed, "", nil)
|
||
report.AddStep("s4", StepPartial, "", nil)
|
||
report.AddStep("s5", StepPartial, "", nil)
|
||
report.AddStep("s6", StepNotApplicable, "", nil)
|
||
report.AddStep("s7", StepNotApplicable, "", nil)
|
||
report.AddStep("s8", StepNotApplicable, "", nil)
|
||
|
||
success, failed, partial, notApplicable := report.CountStatuses()
|
||
assert.Equal(t, 2, success)
|
||
assert.Equal(t, 1, failed)
|
||
assert.Equal(t, 2, partial)
|
||
assert.Equal(t, 3, notApplicable)
|
||
}
|
||
|
||
func TestPostDeletionReportCountStatusesEmpty(t *testing.T) {
|
||
report := &PostDeletionReport{}
|
||
success, failed, partial, notApplicable := report.CountStatuses()
|
||
assert.Equal(t, 0, success)
|
||
assert.Equal(t, 0, failed)
|
||
assert.Equal(t, 0, partial)
|
||
assert.Equal(t, 0, notApplicable)
|
||
}
|
||
|
||
func TestCountSubStepSuccesses(t *testing.T) {
|
||
subSteps := []DeletionSubStep{
|
||
{Name: "a", Status: StepSuccess},
|
||
{Name: "b", Status: StepFailed},
|
||
{Name: "c", Status: StepSuccess},
|
||
{Name: "d", Status: StepPartial},
|
||
}
|
||
assert.Equal(t, 2, CountSubStepSuccesses(subSteps))
|
||
}
|
||
|
||
func TestCountSubStepSuccessesEmpty(t *testing.T) {
|
||
assert.Equal(t, 0, CountSubStepSuccesses(nil))
|
||
assert.Equal(t, 0, CountSubStepSuccesses([]DeletionSubStep{}))
|
||
}
|
||
|
||
func TestTranslateDetail(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{}
|
||
|
||
t.Run("empty detail returns empty string", func(t *testing.T) {
|
||
assert.Equal(t, "", report.translateDetail(T, "", nil))
|
||
})
|
||
|
||
t.Run("detail without params returns translation ID", func(t *testing.T) {
|
||
assert.Equal(t, "some.key", report.translateDetail(T, "some.key", nil))
|
||
})
|
||
|
||
t.Run("detail with params interpolates", func(t *testing.T) {
|
||
result := report.translateDetail(T, "{{.Count}} rows deleted.", map[string]any{"Count": 3})
|
||
assert.Equal(t, "3 rows deleted.", result)
|
||
})
|
||
}
|
||
|
||
func TestRenderAllSuccess(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
ts := time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC)
|
||
report := &PostDeletionReport{
|
||
PostID: "test-post-id",
|
||
Timestamp: ts,
|
||
}
|
||
|
||
report.AddStep("app.data_spillage.report.step.priority_data", StepSuccess, "app.data_spillage.report.detail.deleted", nil)
|
||
report.AddStep("app.data_spillage.report.step.reminders", StepSuccess, "app.data_spillage.report.detail.deleted", nil)
|
||
|
||
result := report.Render(T)
|
||
|
||
// Header
|
||
assert.Contains(t, result, "### app.data_spillage.report.title")
|
||
assert.Contains(t, result, "`test-post-id`")
|
||
assert.Contains(t, result, "2025-01-15 at 10:30:00 UTC")
|
||
|
||
// Steps rendered with success icon
|
||
assert.Contains(t, result, "✅ app.data_spillage.report.step.priority_data")
|
||
assert.Contains(t, result, "✅ app.data_spillage.report.step.reminders")
|
||
assert.Contains(t, result, "app.data_spillage.report.detail.deleted")
|
||
|
||
// Summary table
|
||
assert.Contains(t, result, "📊 app.data_spillage.report.summary")
|
||
assert.Contains(t, result, "|---|---|---|---|")
|
||
|
||
// No incomplete warning when all succeed
|
||
assert.NotContains(t, result, "app.data_spillage.report.incomplete_warning")
|
||
}
|
||
|
||
func TestRenderWithFailures(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post123",
|
||
Timestamp: time.Date(2025, 6, 1, 0, 0, 0, 0, time.UTC),
|
||
}
|
||
|
||
report.AddStep("step.success", StepSuccess, "ok", nil)
|
||
report.AddStep("step.failed", StepFailed, "", []string{"db connection lost"})
|
||
|
||
result := report.Render(T)
|
||
|
||
// Should contain the incomplete warning
|
||
assert.Contains(t, result, "app.data_spillage.report.incomplete_warning")
|
||
|
||
// Error log for the failed step
|
||
assert.Contains(t, result, "app.data_spillage.report.error_log")
|
||
assert.Contains(t, result, "db connection lost")
|
||
}
|
||
|
||
func TestRenderWithPartialStatus(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post456",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.AddStep("step.partial", StepPartial, "some detail", nil)
|
||
|
||
result := report.Render(T)
|
||
assert.Contains(t, result, "⚠️")
|
||
assert.Contains(t, result, "app.data_spillage.report.incomplete_warning")
|
||
}
|
||
|
||
func TestRenderWithSubSteps(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post789",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.Steps = append(report.Steps, DeletionStepResult{
|
||
Name: "app.data_spillage.report.step.edit_histories",
|
||
Status: StepPartial,
|
||
Detail: "{{.Count}} of {{.Total}} revisions cleared",
|
||
DetailParams: map[string]any{
|
||
"Count": 2,
|
||
"Total": 3,
|
||
},
|
||
SubSteps: []DeletionSubStep{
|
||
{Name: "edit1", Status: StepSuccess},
|
||
{Name: "edit2", Status: StepSuccess},
|
||
{Name: "edit3", Status: StepFailed, Errors: []string{"timeout"}},
|
||
},
|
||
})
|
||
|
||
result := report.Render(T)
|
||
|
||
// Sub-step heading
|
||
assert.Contains(t, result, "app.data_spillage.report.step.edit_histories")
|
||
|
||
// Revision counts
|
||
assert.Contains(t, result, "app.data_spillage.report.revisions_found")
|
||
|
||
// Individual sub-steps
|
||
assert.Contains(t, result, "`edit1`")
|
||
assert.Contains(t, result, "`edit2`")
|
||
assert.Contains(t, result, "`edit3`")
|
||
|
||
// Error from failed sub-step
|
||
assert.Contains(t, result, "timeout")
|
||
}
|
||
|
||
func TestRenderSummaryAllSuccess(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post-ok",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.AddStep("step1", StepSuccess, "detail1", nil)
|
||
report.AddStep("step2", StepSuccess, "detail2", nil)
|
||
|
||
result := report.RenderSummary(T)
|
||
|
||
// Summary table present
|
||
assert.Contains(t, result, "📊 app.data_spillage.report.summary")
|
||
assert.Contains(t, result, "step1")
|
||
assert.Contains(t, result, "step2")
|
||
|
||
// No warning
|
||
assert.NotContains(t, result, "app.data_spillage.report.incomplete_warning")
|
||
}
|
||
|
||
func TestRenderSummaryWithFailure(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post-fail",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.AddStep("step1", StepSuccess, "", nil)
|
||
report.AddStep("step2", StepFailed, "", []string{"err"})
|
||
|
||
result := report.RenderSummary(T)
|
||
|
||
assert.Contains(t, result, "app.data_spillage.report.incomplete_warning")
|
||
}
|
||
|
||
func TestRenderSummaryTableRowCount(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post-rows",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
for i := range 5 {
|
||
report.AddStep(fmt.Sprintf("step%d", i+1), StepSuccess, "", nil)
|
||
}
|
||
|
||
result := report.RenderSummary(T)
|
||
|
||
// Table header + separator + 5 data rows
|
||
lines := strings.Split(strings.TrimSpace(result), "\n")
|
||
tableLines := 0
|
||
for _, line := range lines {
|
||
if strings.HasPrefix(line, "|") {
|
||
tableLines++
|
||
}
|
||
}
|
||
// header + separator + 5 rows = 7
|
||
assert.Equal(t, 7, tableLines)
|
||
}
|
||
|
||
func TestRenderErrorsMultiline(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post-err",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.AddStep("step1", StepFailed, "", []string{"line1\nline2\nline3"})
|
||
|
||
result := report.Render(T)
|
||
|
||
assert.Contains(t, result, "> line1")
|
||
assert.Contains(t, result, "> line2")
|
||
assert.Contains(t, result, "> line3")
|
||
}
|
||
|
||
func TestRenderEmptyReport(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "empty-post",
|
||
Timestamp: time.Date(2025, 3, 1, 12, 0, 0, 0, time.UTC),
|
||
}
|
||
|
||
result := report.Render(T)
|
||
|
||
// Should still render header and empty summary table
|
||
assert.Contains(t, result, "### app.data_spillage.report.title")
|
||
assert.Contains(t, result, "`empty-post`")
|
||
assert.Contains(t, result, "📊 app.data_spillage.report.summary")
|
||
|
||
// No warning since there are no failures
|
||
assert.NotContains(t, result, "app.data_spillage.report.incomplete_warning")
|
||
}
|
||
|
||
func TestRenderStepWithParamsDetail(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post-params",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.AddStepWithParams(
|
||
"app.data_spillage.report.step.fileinfo_rows",
|
||
StepSuccess,
|
||
"{{.Count}} rows deleted.",
|
||
map[string]any{"Count": 7},
|
||
nil,
|
||
)
|
||
|
||
result := report.Render(T)
|
||
assert.Contains(t, result, "7 rows deleted.")
|
||
}
|
||
|
||
func TestRenderSubStepWithDetail(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "post-sub-detail",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.Steps = append(report.Steps, DeletionStepResult{
|
||
Name: "edit_step",
|
||
Status: StepSuccess,
|
||
SubSteps: []DeletionSubStep{
|
||
{
|
||
Name: "rev1",
|
||
Status: StepSuccess,
|
||
Detail: "**File Attachments:** {{.FileNames}} — **FileInfo Rows:** {{.Count}} deleted",
|
||
DetailParams: map[string]any{"FileNames": "`doc.pdf`", "Count": 1},
|
||
},
|
||
},
|
||
})
|
||
|
||
result := report.Render(T)
|
||
assert.Contains(t, result, "`doc.pdf`")
|
||
assert.Contains(t, result, "1 deleted")
|
||
}
|
||
|
||
func TestRenderSummaryTableStatusIcons(t *testing.T) {
|
||
T := stubTranslateFunc
|
||
report := &PostDeletionReport{
|
||
PostID: "icons",
|
||
Timestamp: time.Now().UTC(),
|
||
}
|
||
|
||
report.AddStep("s1", StepSuccess, "", nil)
|
||
report.AddStep("s2", StepFailed, "", nil)
|
||
report.AddStep("s3", StepPartial, "", nil)
|
||
|
||
result := report.RenderSummary(T)
|
||
|
||
// Each row should have the correct icon
|
||
lines := strings.Split(result, "\n")
|
||
var dataRows []string
|
||
for _, line := range lines {
|
||
if strings.HasPrefix(line, "|") && !strings.HasPrefix(line, "|---") && !strings.Contains(line, "app.data_spillage.report.column") {
|
||
dataRows = append(dataRows, line)
|
||
}
|
||
}
|
||
require.Len(t, dataRows, 3)
|
||
assert.Contains(t, dataRows[0], "✅")
|
||
assert.Contains(t, dataRows[1], "❌")
|
||
assert.Contains(t, dataRows[2], "⚠️")
|
||
}
|