test(rerelease): add confirmWarnings coverage and sync generated schema

- Add domain tests for rerelease with precheck warnings (reject + confirm)
- Add controller test verifying confirmWarnings passthrough
- Sync SkillVersionRereleaseRequest generated type with backend DTO
This commit is contained in:
xiose 2026-04-14 17:55:56 +08:00
parent b597a6f511
commit 7c2f06d1b6
3 changed files with 131 additions and 0 deletions

View file

@ -305,6 +305,42 @@ class SkillLifecycleControllerTest {
eq(false));
}
@Test
void rereleaseVersion_passesConfirmWarningsToService() throws Exception {
Namespace namespace = new Namespace("global", "Global", "owner");
setNamespaceId(namespace, 1L);
Skill skill = new Skill(1L, "demo-skill", "owner", SkillVisibility.PUBLIC);
setSkillId(skill, 1L);
SkillVersion newVersion = new SkillVersion(1L, "1.2.4", "owner");
setSkillVersionId(newVersion, 3L);
newVersion.setStatus(SkillVersionStatus.PUBLISHED);
given(namespaceRepository.findBySlug("global")).willReturn(java.util.Optional.of(namespace));
given(skillSlugResolutionService.resolve(1L, "demo-skill", "usr_1", SkillSlugResolutionService.Preference.CURRENT_USER))
.willReturn(skill);
SkillVersion sourceVersion = new SkillVersion(1L, "1.2.3", "owner");
setSkillVersionId(sourceVersion, 2L);
sourceVersion.setStatus(SkillVersionStatus.PUBLISHED);
given(skillVersionRepository.findBySkillIdAndVersion(1L, "1.2.3")).willReturn(java.util.Optional.of(sourceVersion));
given(skillPublishService.rereleasePublishedVersion(
eq(1L), eq("1.2.3"), eq("1.2.4"), eq("usr_1"), anyMap(), eq(true)))
.willReturn(new SkillPublishService.PublishResult(1L, "demo-skill", newVersion));
mockMvc.perform(post("/api/web/skills/global/demo-skill/versions/1.2.3/rerelease")
.requestAttr("userId", "usr_1")
.requestAttr("userNsRoles", java.util.Map.of(1L, NamespaceRole.ADMIN))
.contentType(MediaType.APPLICATION_JSON)
.content("{\"targetVersion\":\"1.2.4\",\"confirmWarnings\":true}")
.with(user("usr_1"))
.with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data.action").value("RERELEASE_VERSION"));
verify(skillPublishService).rereleasePublishedVersion(
eq(1L), eq("1.2.3"), eq("1.2.4"), eq("usr_1"), anyMap(), eq(true));
}
private Skill skillWithStatus(Skill skill, com.iflytek.skillhub.domain.skill.SkillStatus status) {
skill.setStatus(status);
return skill;

View file

@ -969,6 +969,100 @@ class SkillPublishServiceTest {
assertEquals(30L, skill.getLatestVersionId());
}
@Test
void testRereleasePublishedVersion_ShouldRequireConfirmationWhenWarningsExist() throws Exception {
String publisherId = "user-100";
Skill skill = new Skill(1L, "demo-skill", publisherId, SkillVisibility.PUBLIC);
setId(skill, 11L);
skill.setDisplayName("Demo Skill");
skill.setSummary("Original summary");
Namespace namespace = new Namespace("global", "Global", "owner");
setId(namespace, 1L);
SkillVersion sourceVersion = new SkillVersion(skill.getId(), "1.2.3", publisherId);
setId(sourceVersion, 21L);
sourceVersion.setStatus(SkillVersionStatus.PUBLISHED);
sourceVersion.setPublishedAt(Instant.parse("2026-03-15T10:00:00Z"));
String sourceSkillMd = "---\nname: Demo Skill\ndescription: Original summary\nversion: 1.2.3\n---\nHello world";
SkillFile skillMdFile = new SkillFile(sourceVersion.getId(), "SKILL.md", (long) sourceSkillMd.getBytes(StandardCharsets.UTF_8).length, "text/markdown", "hash1", "skills/11/21/SKILL.md");
SkillMetadata rereleaseMetadata = new SkillMetadata(
"Demo Skill", "Original summary", "1.2.4", "Hello world",
Map.of("name", "Demo Skill", "description", "Original summary", "version", "1.2.4"));
when(skillRepository.findById(skill.getId())).thenReturn(Optional.of(skill));
when(namespaceRepository.findById(skill.getNamespaceId())).thenReturn(Optional.of(namespace));
when(namespaceRepository.findBySlug("global")).thenReturn(Optional.of(namespace));
when(skillVersionRepository.findBySkillIdAndVersion(skill.getId(), "1.2.3")).thenReturn(Optional.of(sourceVersion));
when(skillVersionRepository.findBySkillIdAndVersion(skill.getId(), "1.2.4")).thenReturn(Optional.empty());
when(skillFileRepository.findByVersionId(sourceVersion.getId())).thenReturn(List.of(skillMdFile));
when(objectStorageService.getObject(skillMdFile.getStorageKey())).thenReturn(new java.io.ByteArrayInputStream(sourceSkillMd.getBytes(StandardCharsets.UTF_8)));
when(skillPackageValidator.validate(anyList())).thenReturn(ValidationResult.pass());
when(skillMetadataParser.parse(anyString())).thenReturn(rereleaseMetadata);
when(prePublishValidator.validate(any())).thenReturn(ValidationResult.warn(List.of(
"SKILL.md line 5 contains a value that looks like a secret or token.")));
DomainBadRequestException exception = assertThrows(DomainBadRequestException.class, () -> service.rereleasePublishedVersion(
skill.getId(), "1.2.3", "1.2.4", publisherId,
Map.of(skill.getNamespaceId(), com.iflytek.skillhub.domain.namespace.NamespaceRole.OWNER),
false
));
assertEquals("error.skill.publish.precheck.confirmRequired", exception.messageCode());
assertTrue(String.valueOf(exception.messageArgs()[0]).contains("looks like a secret or token"));
verify(skillVersionRepository, never()).save(any(SkillVersion.class));
}
@Test
void testRereleasePublishedVersion_ShouldSucceedWhenWarningsConfirmed() throws Exception {
String publisherId = "user-100";
Skill skill = new Skill(1L, "demo-skill", publisherId, SkillVisibility.PUBLIC);
setId(skill, 11L);
skill.setDisplayName("Demo Skill");
skill.setSummary("Original summary");
Namespace namespace = new Namespace("global", "Global", "owner");
setId(namespace, 1L);
SkillVersion sourceVersion = new SkillVersion(skill.getId(), "1.2.3", publisherId);
setId(sourceVersion, 21L);
sourceVersion.setStatus(SkillVersionStatus.PUBLISHED);
sourceVersion.setPublishedAt(Instant.parse("2026-03-15T10:00:00Z"));
String sourceSkillMd = "---\nname: Demo Skill\ndescription: Original summary\nversion: 1.2.3\n---\nHello world";
SkillFile skillMdFile = new SkillFile(sourceVersion.getId(), "SKILL.md", (long) sourceSkillMd.getBytes(StandardCharsets.UTF_8).length, "text/markdown", "hash1", "skills/11/21/SKILL.md");
SkillMetadata rereleaseMetadata = new SkillMetadata(
"Demo Skill", "Original summary", "1.2.4", "Hello world",
Map.of("name", "Demo Skill", "description", "Original summary", "version", "1.2.4"));
when(skillRepository.findById(skill.getId())).thenReturn(Optional.of(skill));
when(namespaceRepository.findById(skill.getNamespaceId())).thenReturn(Optional.of(namespace));
when(namespaceRepository.findBySlug("global")).thenReturn(Optional.of(namespace));
when(skillVersionRepository.findBySkillIdAndVersion(skill.getId(), "1.2.3")).thenReturn(Optional.of(sourceVersion));
when(skillVersionRepository.findBySkillIdAndVersion(skill.getId(), "1.2.4")).thenReturn(Optional.empty());
when(skillFileRepository.findByVersionId(sourceVersion.getId())).thenReturn(List.of(skillMdFile));
when(objectStorageService.getObject(skillMdFile.getStorageKey())).thenReturn(new java.io.ByteArrayInputStream(sourceSkillMd.getBytes(StandardCharsets.UTF_8)));
when(skillPackageValidator.validate(anyList())).thenReturn(ValidationResult.pass());
when(skillMetadataParser.parse(anyString())).thenReturn(rereleaseMetadata);
when(prePublishValidator.validate(any())).thenReturn(ValidationResult.warn(List.of(
"SKILL.md line 5 contains a value that looks like a secret or token.")));
when(skillVersionRepository.save(any(SkillVersion.class))).thenAnswer(invocation -> {
SkillVersion saved = invocation.getArgument(0);
if (saved.getId() == null) { setId(saved, 30L); }
return saved;
});
when(skillRepository.save(any())).thenReturn(skill);
SkillPublishService.PublishResult result = service.rereleasePublishedVersion(
skill.getId(), "1.2.3", "1.2.4", publisherId,
Map.of(skill.getNamespaceId(), com.iflytek.skillhub.domain.namespace.NamespaceRole.OWNER),
true // confirmWarnings = true should bypass warning and succeed
);
assertEquals("1.2.4", result.version().getVersion());
assertEquals(SkillVersionStatus.PENDING_REVIEW, result.version().getStatus());
verify(skillVersionRepository, atLeastOnce()).save(any(SkillVersion.class));
}
@Test
void testPublishFromEntries_ShouldRejectWhenOtherOwnerHasPublishedSkill() throws Exception {
String namespaceSlug = "test-ns";

View file

@ -3237,6 +3237,7 @@ export interface components {
};
SkillVersionRereleaseRequest: {
targetVersion: string;
confirmWarnings?: boolean;
};
SkillReportSubmitRequest: {
reason?: string;