W6 — live-тест файлового dedup (TDD) #63

Closed
opened 2026-09-16 22:37:21 +01:00 by eSlider · 1 comment
Owner

Эпик: #53

W6 — live-тест файлового dedup (TDD)

Проблема

files_dedupe.go (FileDedupKey, FindProjectDuplicates, ApplyDedupGroups, DeleteFilesByDedupKey)
покрыт только unit-тестами. Живого доказательства, что dedup реально находит и удаляет дубли на портале, нет.

Работа (TDD)

  1. TestIntegrationFileDedup (//go:build integration): throwaway-проект → две папки, загрузить
    один и тот же файл (по stem+ext) в обе (и дубль в одну) → FindProjectDuplicates находит группу →
    ApplyDedupGroups/DeleteFilesByDedupKey удаляет лишние → survivor остался, остальные исчезли (poll).
  2. Проверить isTrashFolderTitle/mergeProjectRootForDedupe поведение на живом дереве.
  3. Найденные баги — починить; тест не ослаблять.

Критерии

  • TestIntegrationFileDedup зелёный на живом портале; survivor и удаления подтверждены polling-ом.
  • Unit-тесты files_dedupe_test.go остаются зелёными.
  • Вывод приложен; throwaway-проект удалён.
Эпик: #53 ## W6 — live-тест файлового dedup (TDD) ### Проблема `files_dedupe.go` (`FileDedupKey`, `FindProjectDuplicates`, `ApplyDedupGroups`, `DeleteFilesByDedupKey`) покрыт только unit-тестами. Живого доказательства, что dedup реально находит и удаляет дубли на портале, нет. ### Работа (TDD) 1. `TestIntegrationFileDedup` (`//go:build integration`): throwaway-проект → две папки, загрузить один и тот же файл (по stem+ext) в обе (и дубль в одну) → `FindProjectDuplicates` находит группу → `ApplyDedupGroups`/`DeleteFilesByDedupKey` удаляет лишние → survivor остался, остальные исчезли (poll). 2. Проверить `isTrashFolderTitle`/`mergeProjectRootForDedupe` поведение на живом дереве. 3. Найденные баги — починить; тест не ослаблять. ### Критерии - [ ] `TestIntegrationFileDedup` зелёный на живом портале; survivor и удаления подтверждены polling-ом. - [ ] Unit-тесты `files_dedupe_test.go` остаются зелёными. - [ ] Вывод приложен; throwaway-проект удалён.
Author
Owner

Отчёт SE — W6 #63 (live-тест файлового dedup)

Branch: test/w6-file-dedup#63
Commits: d9db1c5 (test), f8783b8 (fix empty key), 5588c2d (fix delete retry)
HEAD SHA: 5588c2d3f7f88da7402c248198c5e9efd98a9342
PR: #65

Что сделано

  1. TestIntegrationFileDedup (//go:build integration) — throwaway-проект go-onlyoffice-test-dedup-*:
    две папки (A, B) + project root, дубли одного stem|ext (2 в A, 1 в B, 2 в root).
    • FindProjectDuplicates within: группа A (2) и группа root (2).
    • DedupeProject(--cross, dry-run): 1 группа, 5 файлов, 4 к удалению; в группе есть root-копия.
    • DeleteFilesByDedupKey(A): удалила 2 копии; ApplyDedupGroups: удалила 4 копии.
    • survivor подтверждён polling-ом, удалённые id реально исчезли из всех папок.
    • IsTrashFolderTitle и mergeProjectRootForDedupe проверены на живом дереве (root ровно один раз, root-файлы в cross-группе).
    • Setup-запросы (create folder / upload) ретраят временный post-create 500 портала — ассерты не ослаблены.
  2. Найденные баги (починены):
    • fix(files): пропускать пустой dedup-ключ (dotfiles) — .env/.gitignore/.npmrc дают FileDedupKey="", а findWithinFolderDuplicates/findCrossFolderDuplicates схлопывали их в одну группу дублей → удаление лишнего. Добавлен unit TestFindDuplicatesSkipsEmptyKey (падал до фикса).
    • fix(files): ретраить transient-ответы при удалении файлов — DeleteDavItems (путь ApplyDedupGroups/DeleteFilesByDedupKey) не шёл через DoRetry и падал на 429 от openresty. Теперь каждый delete идёт через DoRetry.

Фактический вывод

=== RUN   TestIntegrationFileDedup
    files_dedupe_integration_test.go:59: uploaded a1=24821 a2=24822 b1=24823 r1=24824 r2=24825
    files_dedupe_integration_test.go:175: survivor id=24826 keep id=24826, deleted=[24827 24823 24824 24825]
--- PASS: TestIntegrationFileDedup (3.14s)

(второй прогон — тоже PASS; survivor = keep, удалены ровно 4 лишние копии)

Unit (до/после фикса — сначала FAIL на empty-key, потом PASS):

--- PASS: TestFileDedupKey
--- PASS: TestFindFilesByDedupKey
--- PASS: TestFindWithinFolderDuplicates
--- PASS: TestCrossFolderPrefersNonTrash
--- PASS: TestMergeProjectRootForDedupe
--- PASS: TestIsTrashFolderTitle
--- PASS: TestFindDuplicatesSkipsEmptyKey
ok  github.com/eslider/go-onlyoffice

go build ./... — зелёный. gitleaks detect --no-banner --redact -s . — no leaks.
Throwaway-проекты после прогона не остаются (проверено GetProjects — 0 с префиксом go-onlyoffice-test-).

Блокеры

Нет. go test -tags=integration ./... падает на пред-существующем не-моём cmd/office/fetch/task_integration_test.go (loader.TaskFields undefined) — точечно корневой пакет (.) зелёный; не трогал.

Мержить/закрывать — PO/RE. PR #65 ждёт ревью.

## Отчёт SE — W6 #63 (live-тест файлового dedup) **Branch:** `test/w6-file-dedup#63` **Commits:** `d9db1c5` (test), `f8783b8` (fix empty key), `5588c2d` (fix delete retry) **HEAD SHA:** `5588c2d3f7f88da7402c248198c5e9efd98a9342` **PR:** https://git.produktor.io/eSlider/go-onlyoffice/pulls/65 ### Что сделано 1. **`TestIntegrationFileDedup`** (`//go:build integration`) — throwaway-проект `go-onlyoffice-test-dedup-*`: две папки (`A`, `B`) + project root, дубли одного stem|ext (2 в A, 1 в B, 2 в root). - `FindProjectDuplicates` within: группа A (2) и группа root (2). - `DedupeProject(--cross, dry-run)`: 1 группа, 5 файлов, 4 к удалению; в группе есть root-копия. - `DeleteFilesByDedupKey(A)`: удалила 2 копии; `ApplyDedupGroups`: удалила 4 копии. - survivor подтверждён polling-ом, удалённые id реально исчезли из всех папок. - `IsTrashFolderTitle` и `mergeProjectRootForDedupe` проверены на живом дереве (root ровно один раз, root-файлы в cross-группе). - Setup-запросы (create folder / upload) ретраят временный post-create 500 портала — ассерты не ослаблены. 2. **Найденные баги (починены):** - `fix(files): пропускать пустой dedup-ключ (dotfiles)` — `.env`/`.gitignore`/`.npmrc` дают `FileDedupKey=""`, а `findWithinFolderDuplicates`/`findCrossFolderDuplicates` схлопывали их в одну группу дублей → удаление лишнего. Добавлен unit `TestFindDuplicatesSkipsEmptyKey` (падал до фикса). - `fix(files): ретраить transient-ответы при удалении файлов` — `DeleteDavItems` (путь `ApplyDedupGroups`/`DeleteFilesByDedupKey`) не шёл через `DoRetry` и падал на `429` от openresty. Теперь каждый delete идёт через `DoRetry`. ### Фактический вывод ``` === RUN TestIntegrationFileDedup files_dedupe_integration_test.go:59: uploaded a1=24821 a2=24822 b1=24823 r1=24824 r2=24825 files_dedupe_integration_test.go:175: survivor id=24826 keep id=24826, deleted=[24827 24823 24824 24825] --- PASS: TestIntegrationFileDedup (3.14s) ``` (второй прогон — тоже PASS; survivor = keep, удалены ровно 4 лишние копии) Unit (до/после фикса — сначала FAIL на empty-key, потом PASS): ``` --- PASS: TestFileDedupKey --- PASS: TestFindFilesByDedupKey --- PASS: TestFindWithinFolderDuplicates --- PASS: TestCrossFolderPrefersNonTrash --- PASS: TestMergeProjectRootForDedupe --- PASS: TestIsTrashFolderTitle --- PASS: TestFindDuplicatesSkipsEmptyKey ok github.com/eslider/go-onlyoffice ``` `go build ./...` — зелёный. `gitleaks detect --no-banner --redact -s .` — no leaks. Throwaway-проекты после прогона не остаются (проверено `GetProjects` — 0 с префиксом `go-onlyoffice-test-`). ### Блокеры Нет. `go test -tags=integration ./...` падает на пред-существующем не-моём `cmd/office/fetch/task_integration_test.go` (`loader.TaskFields undefined`) — точечно корневой пакет (`.`) зелёный; не трогал. Мержить/закрывать — PO/RE. PR #65 ждёт ревью.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eSlider/go-onlyoffice#63