mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-27 11:14:59 +00:00
fix(cli): align anonymous installability rules
Signed-off-by: dongmucat <1127093059@qq.com>
This commit is contained in:
parent
9520cf63e0
commit
32cc316b30
9 changed files with 218 additions and 13 deletions
|
|
@ -56,15 +56,16 @@ public class CliSkillAppService {
|
|||
);
|
||||
|
||||
List<CliSearchItem> items = response.items().stream()
|
||||
.filter(item -> item.publishedVersion() != null)
|
||||
.map(item -> new CliSearchItem(
|
||||
item.namespace(),
|
||||
item.slug(),
|
||||
item.publishedVersion() != null ? item.publishedVersion().version() : null,
|
||||
item.publishedVersion().version(),
|
||||
item.summary()
|
||||
))
|
||||
.toList();
|
||||
|
||||
return new CliSearchResult(items, response.total(), limit);
|
||||
return new CliSearchResult(items, items.size(), limit);
|
||||
}
|
||||
|
||||
public CliResolveResponse resolve(String namespace, String slug, String version, String userId, Map<Long, NamespaceRole> userNsRoles) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import com.iflytek.skillhub.domain.namespace.NamespaceStatus;
|
|||
import com.iflytek.skillhub.domain.namespace.NamespaceService;
|
||||
import com.iflytek.skillhub.domain.skill.Skill;
|
||||
import com.iflytek.skillhub.domain.skill.SkillRepository;
|
||||
import com.iflytek.skillhub.domain.skill.SkillVersion;
|
||||
import com.iflytek.skillhub.domain.skill.SkillVersionRepository;
|
||||
import com.iflytek.skillhub.domain.skill.SkillVersionStatus;
|
||||
import com.iflytek.skillhub.domain.skill.SkillVisibility;
|
||||
import com.iflytek.skillhub.domain.skill.service.SkillLifecycleProjectionService;
|
||||
import com.iflytek.skillhub.search.SearchQuery;
|
||||
|
|
@ -184,6 +186,36 @@ class SkillSearchAppServiceTest {
|
|||
.findBySkillIdInAndStatus(List.of(10L, 11L), com.iflytek.skillhub.domain.skill.SkillVersionStatus.PUBLISHED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void search_shouldNotExposeDownloadUnavailableVersionAsPublishedSummary() {
|
||||
Skill skill = new Skill(1L, "not-ready", "owner-1", SkillVisibility.PUBLIC);
|
||||
setField(skill, "id", 10L);
|
||||
skill.setLatestVersionId(101L);
|
||||
|
||||
SkillVersion version = new SkillVersion(10L, "1.0.0", "owner-1");
|
||||
setField(version, "id", 101L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(false);
|
||||
|
||||
Namespace namespace = new Namespace("global", "Global", "owner-1");
|
||||
setField(namespace, "id", 1L);
|
||||
namespace.setStatus(NamespaceStatus.ACTIVE);
|
||||
|
||||
when(searchQueryService.search(any()))
|
||||
.thenReturn(new SearchResult(List.of(10L), 1, 0, 20));
|
||||
when(skillRepository.findByIdIn(List.of(10L))).thenReturn(List.of(skill));
|
||||
when(namespaceRepository.findByIdIn(List.of(1L))).thenReturn(List.of(namespace));
|
||||
when(skillVersionRepository.findByIdIn(List.of(101L))).thenReturn(List.of(version));
|
||||
when(skillVersionRepository.findBySkillIdInAndStatus(List.of(10L), SkillVersionStatus.PUBLISHED))
|
||||
.thenReturn(List.of(version));
|
||||
|
||||
SkillSearchAppService.SearchResponse response = service.search(null, null, "newest", 0, 20, null, null);
|
||||
|
||||
assertEquals(1, response.items().size());
|
||||
assertEquals("not-ready", response.items().getFirst().slug());
|
||||
assertEquals(null, response.items().getFirst().publishedVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
void search_shouldNormalizeAndPassLabelSlugs() {
|
||||
when(searchQueryService.search(any()))
|
||||
|
|
|
|||
|
|
@ -76,6 +76,37 @@ class CliSkillAppServiceTest {
|
|||
assertEquals(20, result.limit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void search_filtersResultsWithoutInstallablePublishedVersion() {
|
||||
var searchResponse = new SkillSearchAppService.SearchResponse(
|
||||
List.of(
|
||||
new SkillSummaryResponse(
|
||||
1L, "draft-only", "Draft Only", "No installable version",
|
||||
"PUBLIC", "ACTIVE", 0L, 0, BigDecimal.ZERO, 0,
|
||||
"global", Instant.now(), false,
|
||||
null, null, null, "NONE"
|
||||
),
|
||||
new SkillSummaryResponse(
|
||||
2L, "ready", "Ready", "Installable",
|
||||
"PUBLIC", "ACTIVE", 0L, 0, BigDecimal.ZERO, 0,
|
||||
"global", Instant.now(), false,
|
||||
new SkillLifecycleVersionResponse(2L, "1.0.0", "PUBLISHED"),
|
||||
new SkillLifecycleVersionResponse(2L, "1.0.0", "PUBLISHED"),
|
||||
null, "PUBLISHED"
|
||||
)
|
||||
),
|
||||
2L, 0, 20
|
||||
);
|
||||
given(skillSearchAppService.search("demo", null, "newest", 0, 20, null, null))
|
||||
.willReturn(searchResponse);
|
||||
|
||||
var result = service.search("demo", 20, null, null);
|
||||
|
||||
assertEquals(1, result.items().size());
|
||||
assertEquals("ready", result.items().getFirst().slug());
|
||||
assertEquals(1L, result.total());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolve_delegatesToQueryService() {
|
||||
given(skillQueryService.resolveVersion("global", "demo", "2.0.0", null, null, "user-1", Map.of()))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.iflytek.skillhub.domain.skill;
|
||||
|
||||
/**
|
||||
* Defines whether a skill version can be installed through public download
|
||||
* paths. Storage object presence is checked later by the download service so
|
||||
* fallback bundle behavior stays separate from domain publication state.
|
||||
*/
|
||||
public final class SkillInstallability {
|
||||
private SkillInstallability() {
|
||||
}
|
||||
|
||||
public static boolean isInstallableVersion(SkillVersion version) {
|
||||
return version != null
|
||||
&& version.getStatus() == SkillVersionStatus.PUBLISHED
|
||||
&& version.isDownloadReady()
|
||||
&& version.getYankedAt() == null;
|
||||
}
|
||||
}
|
||||
|
|
@ -306,7 +306,7 @@ public class SkillDownloadService {
|
|||
|
||||
/**
|
||||
* Asserts that the version can be downloaded.
|
||||
* - PUBLISHED: anyone with skill access can download
|
||||
* - PUBLISHED: must be installable before public download
|
||||
* - UPLOADED/PENDING_REVIEW: only skill owner or namespace admin can download
|
||||
*/
|
||||
private void assertDownloadableVersion(Skill skill,
|
||||
|
|
@ -315,7 +315,9 @@ public class SkillDownloadService {
|
|||
Map<Long, NamespaceRole> userNsRoles) {
|
||||
switch (version.getStatus()) {
|
||||
case PUBLISHED -> {
|
||||
// Anyone with skill access can download published versions
|
||||
if (!SkillInstallability.isInstallableVersion(version)) {
|
||||
throw new DomainBadRequestException("error.skill.version.notDownloadable", version.getVersion());
|
||||
}
|
||||
}
|
||||
case UPLOADED, PENDING_REVIEW -> {
|
||||
if (!canManageSkillDraft(skill, currentUserId, userNsRoles)) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.iflytek.skillhub.domain.skill.service;
|
|||
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceRole;
|
||||
import com.iflytek.skillhub.domain.skill.Skill;
|
||||
import com.iflytek.skillhub.domain.skill.SkillInstallability;
|
||||
import com.iflytek.skillhub.domain.skill.SkillVersion;
|
||||
import com.iflytek.skillhub.domain.skill.SkillVersionRepository;
|
||||
import com.iflytek.skillhub.domain.skill.SkillVersionStatus;
|
||||
|
|
@ -91,7 +92,7 @@ public class SkillLifecycleProjectionService {
|
|||
List<Long> unresolvedSkillIds = new java.util.ArrayList<>();
|
||||
for (Skill skill : skills) {
|
||||
SkillVersion latestVersion = latestVersionsById.get(skill.getLatestVersionId());
|
||||
if (latestVersion != null && latestVersion.getStatus() == SkillVersionStatus.PUBLISHED) {
|
||||
if (SkillInstallability.isInstallableVersion(latestVersion)) {
|
||||
publishedBySkillId.put(skill.getId(), latestVersion);
|
||||
} else {
|
||||
unresolvedSkillIds.add(skill.getId());
|
||||
|
|
@ -100,7 +101,9 @@ public class SkillLifecycleProjectionService {
|
|||
|
||||
if (!unresolvedSkillIds.isEmpty()) {
|
||||
for (SkillVersion version : skillVersionRepository.findBySkillIdInAndStatus(unresolvedSkillIds, SkillVersionStatus.PUBLISHED)) {
|
||||
publishedBySkillId.merge(version.getSkillId(), version, this::newerVersion);
|
||||
if (SkillInstallability.isInstallableVersion(version)) {
|
||||
publishedBySkillId.merge(version.getSkillId(), version, this::newerVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -487,13 +487,7 @@ public class SkillQueryService {
|
|||
}
|
||||
|
||||
public boolean isDownloadAvailable(SkillVersion version) {
|
||||
if (version == null) {
|
||||
return false;
|
||||
}
|
||||
if (version.getStatus() != SkillVersionStatus.PUBLISHED) {
|
||||
return false;
|
||||
}
|
||||
return version.isDownloadReady();
|
||||
return SkillInstallability.isInstallableVersion(version);
|
||||
}
|
||||
|
||||
public ReviewSkillSnapshotDTO getReviewSkillSnapshot(Long skillVersionId) {
|
||||
|
|
@ -565,6 +559,7 @@ public class SkillQueryService {
|
|||
Skill skill = resolveVisibleSkill(namespace.getId(), skillSlug, currentUserId);
|
||||
assertPublishedAccessible(namespace, skill, currentUserId, userNsRoles);
|
||||
SkillVersion resolved = resolveVersionEntity(skill, version, tag, hash);
|
||||
assertInstallableVersion(resolved, resolved.getVersion());
|
||||
String fingerprint = computeFingerprint(resolved);
|
||||
Boolean matched = hash == null || hash.isBlank() ? null : Objects.equals(hash, fingerprint);
|
||||
|
||||
|
|
@ -916,6 +911,12 @@ public class SkillQueryService {
|
|||
}
|
||||
}
|
||||
|
||||
private void assertInstallableVersion(SkillVersion version, String versionStr) {
|
||||
if (!SkillInstallability.isInstallableVersion(version)) {
|
||||
throw new DomainBadRequestException("error.skill.version.notDownloadable", versionStr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the caller may preview a specific version's files and metadata.
|
||||
* Published versions are visible to everyone; all other statuses are restricted
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ class SkillDownloadServiceTest {
|
|||
SkillVersion version = new SkillVersion(1L, "1.0.0", userId);
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
String storageKey = "packages/1/10/bundle.zip";
|
||||
InputStream content = new ByteArrayInputStream("test".getBytes());
|
||||
ObjectMetadata metadata = new ObjectMetadata(1000L, "application/zip", Instant.now());
|
||||
|
|
@ -137,6 +138,7 @@ class SkillDownloadServiceTest {
|
|||
SkillVersion version = new SkillVersion(1L, "1.0.0", userId);
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
String storageKey = "packages/1/10/bundle.zip";
|
||||
InputStream content = new ByteArrayInputStream("test".getBytes());
|
||||
ObjectMetadata metadata = new ObjectMetadata(1000L, "application/zip", Instant.now());
|
||||
|
|
@ -180,6 +182,7 @@ class SkillDownloadServiceTest {
|
|||
SkillVersion version = new SkillVersion(1L, versionStr, userId);
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
String storageKey = "packages/1/10/bundle.zip";
|
||||
InputStream content = new ByteArrayInputStream("test".getBytes());
|
||||
ObjectMetadata metadata = new ObjectMetadata(1000L, "application/zip", Instant.now());
|
||||
|
|
@ -232,6 +235,73 @@ class SkillDownloadServiceTest {
|
|||
verify(eventPublisher, never()).publishEvent(any(SkillDownloadedEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownloadVersion_ShouldRejectDownloadUnavailablePublishedVersion() throws Exception {
|
||||
String namespaceSlug = "test-ns";
|
||||
String skillSlug = "test-skill";
|
||||
String versionStr = "1.0.0";
|
||||
String userId = "user-100";
|
||||
Map<Long, NamespaceRole> userNsRoles = Map.of(1L, NamespaceRole.MEMBER);
|
||||
|
||||
Namespace namespace = new Namespace(namespaceSlug, "Test NS", "user-1");
|
||||
setId(namespace, 1L);
|
||||
Skill skill = new Skill(1L, skillSlug, userId, SkillVisibility.PUBLIC);
|
||||
setId(skill, 1L);
|
||||
skill.setStatus(SkillStatus.ACTIVE);
|
||||
SkillVersion version = new SkillVersion(1L, versionStr, userId);
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(false);
|
||||
|
||||
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
|
||||
when(skillRepository.findByNamespaceIdAndSlug(1L, skillSlug)).thenReturn(List.of(skill));
|
||||
when(visibilityChecker.canAccess(skill, userId, userNsRoles)).thenReturn(true);
|
||||
when(skillVersionRepository.findBySkillIdAndVersion(1L, versionStr)).thenReturn(Optional.of(version));
|
||||
|
||||
DomainBadRequestException ex = assertThrows(DomainBadRequestException.class, () ->
|
||||
service.downloadVersion(namespaceSlug, skillSlug, versionStr, userId, userNsRoles));
|
||||
|
||||
assertEquals("error.skill.version.notDownloadable", ex.messageCode());
|
||||
assertArrayEquals(new Object[]{versionStr}, ex.messageArgs());
|
||||
verify(skillRepository, never()).incrementDownloadCount(anyLong());
|
||||
verify(skillVersionStatsRepository, never()).incrementDownloadCount(anyLong(), anyLong());
|
||||
verify(eventPublisher, never()).publishEvent(any(SkillDownloadedEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownloadVersion_ShouldRejectYankedPublishedVersion() throws Exception {
|
||||
String namespaceSlug = "test-ns";
|
||||
String skillSlug = "test-skill";
|
||||
String versionStr = "1.0.0";
|
||||
String userId = "user-100";
|
||||
Map<Long, NamespaceRole> userNsRoles = Map.of(1L, NamespaceRole.MEMBER);
|
||||
|
||||
Namespace namespace = new Namespace(namespaceSlug, "Test NS", "user-1");
|
||||
setId(namespace, 1L);
|
||||
Skill skill = new Skill(1L, skillSlug, userId, SkillVisibility.PUBLIC);
|
||||
setId(skill, 1L);
|
||||
skill.setStatus(SkillStatus.ACTIVE);
|
||||
SkillVersion version = new SkillVersion(1L, versionStr, userId);
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
version.setYankedAt(Instant.parse("2026-06-12T00:00:00Z"));
|
||||
|
||||
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
|
||||
when(skillRepository.findByNamespaceIdAndSlug(1L, skillSlug)).thenReturn(List.of(skill));
|
||||
when(visibilityChecker.canAccess(skill, userId, userNsRoles)).thenReturn(true);
|
||||
when(skillVersionRepository.findBySkillIdAndVersion(1L, versionStr)).thenReturn(Optional.of(version));
|
||||
|
||||
DomainBadRequestException ex = assertThrows(DomainBadRequestException.class, () ->
|
||||
service.downloadVersion(namespaceSlug, skillSlug, versionStr, userId, userNsRoles));
|
||||
|
||||
assertEquals("error.skill.version.notDownloadable", ex.messageCode());
|
||||
assertArrayEquals(new Object[]{versionStr}, ex.messageArgs());
|
||||
verify(skillRepository, never()).incrementDownloadCount(anyLong());
|
||||
verify(skillVersionStatsRepository, never()).incrementDownloadCount(anyLong(), anyLong());
|
||||
verify(eventPublisher, never()).publishEvent(any(SkillDownloadedEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownloadVersion_ShouldFallbackToBundledFilesWhenBundleIsMissing() throws Exception {
|
||||
String namespaceSlug = "test-ns";
|
||||
|
|
@ -249,6 +319,7 @@ class SkillDownloadServiceTest {
|
|||
SkillVersion version = new SkillVersion(1L, versionStr, userId);
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
SkillFile file = new SkillFile(10L, "SKILL.md", 4L, "text/markdown", "hash", "skills/1/10/SKILL.md");
|
||||
|
||||
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
|
||||
|
|
@ -297,6 +368,7 @@ class SkillDownloadServiceTest {
|
|||
SkillVersion version = new SkillVersion(1L, "1.0.0", "owner-1");
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
|
||||
when(namespaceRepository.findBySlug("global")).thenReturn(Optional.of(namespace));
|
||||
when(skillRepository.findByNamespaceIdAndSlug(1L, "demo-skill")).thenReturn(List.of(skill));
|
||||
|
|
@ -332,6 +404,7 @@ class SkillDownloadServiceTest {
|
|||
SkillVersion version = new SkillVersion(1L, "1.0.0", "owner-1");
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
|
||||
when(namespaceRepository.findBySlug("team-ai")).thenReturn(Optional.of(namespace));
|
||||
when(skillRepository.findByNamespaceIdAndSlug(2L, "demo-skill")).thenReturn(List.of(skill));
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
|
@ -439,6 +440,17 @@ class SkillQueryServiceTest {
|
|||
assertTrue(service.isDownloadAvailable(version));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsDownloadAvailable_ShouldReturnFalseWhenVersionIsYanked() throws Exception {
|
||||
SkillVersion version = new SkillVersion(1L, "1.0.0", "user-100");
|
||||
setId(version, 10L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
version.setYankedAt(Instant.parse("2026-06-12T00:00:00Z"));
|
||||
|
||||
assertFalse(service.isDownloadAvailable(version));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsDownloadAvailable_ShouldNotHitObjectStorageForListSignals() throws Exception {
|
||||
SkillVersion version = new SkillVersion(1L, "1.0.0", "user-100");
|
||||
|
|
@ -565,9 +577,11 @@ class SkillQueryServiceTest {
|
|||
SkillVersion version100 = new SkillVersion(1L, "1.0.0", "user-100");
|
||||
setId(version100, 9L);
|
||||
version100.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version100.setDownloadReady(true);
|
||||
SkillVersion version110 = new SkillVersion(1L, "1.1.0", "user-100");
|
||||
setId(version110, 10L);
|
||||
version110.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version110.setDownloadReady(true);
|
||||
|
||||
SkillFile version100File = new SkillFile(9L, "SKILL.md", 10L, "text/markdown", "hash100", "key100");
|
||||
SkillFile version110File = new SkillFile(10L, "SKILL.md", 10L, "text/markdown", "hash110", "key110");
|
||||
|
|
@ -611,6 +625,7 @@ class SkillQueryServiceTest {
|
|||
SkillVersion version = new SkillVersion(3L, "1.0.0 beta", "user-100");
|
||||
setId(version, 11L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(true);
|
||||
SkillFile file = new SkillFile(11L, "SKILL.md", 10L, "text/markdown", "hash", "key");
|
||||
|
||||
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
|
||||
|
|
@ -632,6 +647,35 @@ class SkillQueryServiceTest {
|
|||
assertEquals("/api/v1/skills/global/smoke-skill-two/versions/1.0.0%20beta/download", result.downloadUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResolveVersion_ShouldRejectDownloadUnavailableLatestVersion() throws Exception {
|
||||
String namespaceSlug = "global";
|
||||
String skillSlug = "not-ready";
|
||||
|
||||
Namespace namespace = new Namespace(namespaceSlug, "Global", "owner-1");
|
||||
setId(namespace, 1L);
|
||||
Skill skill = new Skill(1L, skillSlug, "owner-1", SkillVisibility.PUBLIC);
|
||||
setId(skill, 3L);
|
||||
skill.setStatus(SkillStatus.ACTIVE);
|
||||
skill.setLatestVersionId(11L);
|
||||
|
||||
SkillVersion version = new SkillVersion(3L, "1.0.0", "owner-1");
|
||||
setId(version, 11L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
version.setDownloadReady(false);
|
||||
|
||||
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
|
||||
when(skillRepository.findByNamespaceIdAndSlug(1L, skillSlug)).thenReturn(List.of(skill));
|
||||
when(skillVersionRepository.findBySkillIdAndStatus(3L, SkillVersionStatus.PUBLISHED)).thenReturn(List.of(version));
|
||||
when(skillVersionRepository.findById(11L)).thenReturn(Optional.of(version));
|
||||
|
||||
DomainBadRequestException ex = assertThrows(DomainBadRequestException.class, () ->
|
||||
service.resolveVersion(namespaceSlug, skillSlug, null, null, null, null, Map.of()));
|
||||
|
||||
assertEquals("error.skill.version.notDownloadable", ex.messageCode());
|
||||
assertArrayEquals(new Object[]{"1.0.0"}, ex.messageArgs());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSkillDetail_ShouldFlagLifecyclePermissionForOwner() throws Exception {
|
||||
String namespaceSlug = "test-ns";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue