feat(tag): add upsertBySourceRef keyed on canonical tag_path

Idempotent tag upsert for the Phase-3 importer (ADR-025). source_ref is
the stable identity (the canonical tag_path); on re-import a
human-renamed tag name is preserved while the parent link is refreshed.

Refs #669

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-27 10:24:30 +02:00
parent 05dd824283
commit 3501382ff5
3 changed files with 85 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
package org.raddatz.familienarchiv.tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TagImportUpsertTest {
@Mock TagRepository tagRepository;
@InjectMocks TagService tagService;
@Test
void upsertBySourceRef_insertsNewTag_whenSourceRefUnknown() {
when(tagRepository.findBySourceRef("Themen/Brautbriefe")).thenReturn(Optional.empty());
when(tagRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
UUID parentId = UUID.randomUUID();
Tag result = tagService.upsertBySourceRef("Themen/Brautbriefe", "Brautbriefe", parentId);
assertThat(result.getSourceRef()).isEqualTo("Themen/Brautbriefe");
assertThat(result.getName()).isEqualTo("Brautbriefe");
assertThat(result.getParentId()).isEqualTo(parentId);
}
@Test
void upsertBySourceRef_updatesInPlace_whenSourceRefExists() {
Tag existing = Tag.builder().id(UUID.randomUUID()).name("Brautbriefe")
.sourceRef("Themen/Brautbriefe").build();
when(tagRepository.findBySourceRef("Themen/Brautbriefe")).thenReturn(Optional.of(existing));
when(tagRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
tagService.upsertBySourceRef("Themen/Brautbriefe", "Brautbriefe", null);
verify(tagRepository).save(argThat(t -> t.getId().equals(existing.getId())));
verify(tagRepository, never()).save(argThat(t -> t.getId() == null));
}
@Test
void upsertBySourceRef_preservesHumanRenamedTag_onReimport() {
Tag humanRenamed = Tag.builder().id(UUID.randomUUID()).name("Verlobungsbriefe")
.sourceRef("Themen/Brautbriefe").build();
when(tagRepository.findBySourceRef("Themen/Brautbriefe")).thenReturn(Optional.of(humanRenamed));
when(tagRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
Tag result = tagService.upsertBySourceRef("Themen/Brautbriefe", "Brautbriefe", null);
assertThat(result.getName()).isEqualTo("Verlobungsbriefe");
}
}