mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-10 22:41:02 +00:00
refactor(domain): improve SkillRating validation and add domain tests
- Add rating value validation in SkillRating entity - Improve SkillRatingService error handling - Add SkillPublishService and SkillQueryService test coverage
This commit is contained in:
parent
cab627be02
commit
4dfa17dc4e
4 changed files with 107 additions and 3 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package com.iflytek.skillhub.domain.social;
|
||||
|
||||
import com.iflytek.skillhub.domain.shared.exception.DomainBadRequestException;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
|
|
@ -28,14 +29,14 @@ public class SkillRating {
|
|||
protected SkillRating() {}
|
||||
|
||||
public SkillRating(Long skillId, String userId, short score) {
|
||||
if (score < 1 || score > 5) throw new IllegalArgumentException("Score must be 1-5");
|
||||
if (score < 1 || score > 5) throw new DomainBadRequestException("error.rating.score.invalid");
|
||||
this.skillId = skillId;
|
||||
this.userId = userId;
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public void updateScore(short newScore) {
|
||||
if (newScore < 1 || newScore > 5) throw new IllegalArgumentException("Score must be 1-5");
|
||||
if (newScore < 1 || newScore > 5) throw new DomainBadRequestException("error.rating.score.invalid");
|
||||
this.score = newScore;
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.iflytek.skillhub.domain.social;
|
||||
|
||||
import com.iflytek.skillhub.domain.shared.exception.DomainBadRequestException;
|
||||
import com.iflytek.skillhub.domain.social.event.SkillRatedEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -21,7 +22,7 @@ public class SkillRatingService {
|
|||
@Transactional
|
||||
public void rate(Long skillId, String userId, short score) {
|
||||
if (score < 1 || score > 5) {
|
||||
throw new IllegalArgumentException("Score must be 1-5");
|
||||
throw new DomainBadRequestException("error.rating.score.invalid");
|
||||
}
|
||||
Optional<SkillRating> existing = ratingRepository.findBySkillIdAndUserId(skillId, userId);
|
||||
if (existing.isPresent()) {
|
||||
|
|
|
|||
|
|
@ -130,6 +130,70 @@ class SkillPublishServiceTest {
|
|||
verify(objectStorageService, atLeastOnce()).putObject(anyString(), any(), anyLong(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPublishFromEntries_ShouldSlugifyNameBeforeLookupAndResponse() throws Exception {
|
||||
String namespaceSlug = "test-ns";
|
||||
String publisherId = "user-100";
|
||||
String skillMdContent = "---\nname: Smoke Skill Two\ndescription: Test\nversion: 0.2.0\n---\nBody";
|
||||
|
||||
PackageEntry skillMd = new PackageEntry("SKILL.md", skillMdContent.getBytes(), skillMdContent.length(), "text/markdown");
|
||||
List<PackageEntry> entries = List.of(skillMd);
|
||||
|
||||
Namespace namespace = new Namespace(namespaceSlug, "Test NS", "user-1");
|
||||
setId(namespace, 1L);
|
||||
NamespaceMember member = mock(NamespaceMember.class);
|
||||
SkillMetadata metadata = new SkillMetadata("Smoke Skill Two", "Test", "0.2.0", "Body", Map.of());
|
||||
|
||||
Skill skill = new Skill(1L, "smoke-skill-two", publisherId, SkillVisibility.PUBLIC);
|
||||
setId(skill, 2L);
|
||||
SkillVersion version = new SkillVersion(2L, "0.2.0", publisherId);
|
||||
setId(version, 20L);
|
||||
|
||||
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
|
||||
when(namespaceMemberRepository.findByNamespaceIdAndUserId(any(), eq(publisherId))).thenReturn(Optional.of(member));
|
||||
when(skillPackageValidator.validate(entries)).thenReturn(ValidationResult.pass());
|
||||
when(skillMetadataParser.parse(skillMdContent)).thenReturn(metadata);
|
||||
when(prePublishValidator.validate(any())).thenReturn(ValidationResult.pass());
|
||||
when(skillRepository.findByNamespaceIdAndSlug(any(), eq("smoke-skill-two"))).thenReturn(Optional.of(skill));
|
||||
when(skillVersionRepository.findBySkillIdAndVersion(any(), eq("0.2.0"))).thenReturn(Optional.empty());
|
||||
when(skillVersionRepository.save(any())).thenReturn(version);
|
||||
when(skillRepository.save(any())).thenReturn(skill);
|
||||
|
||||
SkillPublishService.PublishResult result = service.publishFromEntries(
|
||||
namespaceSlug,
|
||||
entries,
|
||||
publisherId,
|
||||
SkillVisibility.PUBLIC
|
||||
);
|
||||
|
||||
assertEquals("smoke-skill-two", result.slug());
|
||||
verify(skillRepository).findByNamespaceIdAndSlug(1L, "smoke-skill-two");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPublishFromEntries_ShouldRejectMissingVersionBeforePersistence() throws Exception {
|
||||
String namespaceSlug = "test-ns";
|
||||
String publisherId = "user-100";
|
||||
String skillMdContent = "---\nname: test-skill\ndescription: Test\n---\nBody";
|
||||
|
||||
PackageEntry skillMd = new PackageEntry("SKILL.md", skillMdContent.getBytes(), skillMdContent.length(), "text/markdown");
|
||||
List<PackageEntry> entries = List.of(skillMd);
|
||||
|
||||
Namespace namespace = new Namespace(namespaceSlug, "Test NS", "user-1");
|
||||
setId(namespace, 1L);
|
||||
NamespaceMember member = mock(NamespaceMember.class);
|
||||
SkillMetadata metadata = new SkillMetadata("test-skill", "Test", null, "Body", Map.of());
|
||||
|
||||
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
|
||||
when(namespaceMemberRepository.findByNamespaceIdAndUserId(any(), eq(publisherId))).thenReturn(Optional.of(member));
|
||||
when(skillPackageValidator.validate(entries)).thenReturn(ValidationResult.pass());
|
||||
when(skillMetadataParser.parse(skillMdContent)).thenReturn(metadata);
|
||||
|
||||
assertThrows(DomainBadRequestException.class, () ->
|
||||
service.publishFromEntries(namespaceSlug, entries, publisherId, SkillVisibility.PUBLIC));
|
||||
verify(skillVersionRepository, never()).save(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPublishFromEntries_NamespaceNotFound() {
|
||||
// Arrange
|
||||
|
|
|
|||
|
|
@ -313,6 +313,44 @@ class SkillQueryServiceTest {
|
|||
assertTrue(result.downloadUrl().contains("/versions/1.1.0/download"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResolveVersion_ShouldEncodeDownloadUrlPathSegments() throws Exception {
|
||||
String namespaceSlug = "global";
|
||||
String skillSlug = "smoke-skill-two";
|
||||
Map<Long, NamespaceRole> userNsRoles = Map.of();
|
||||
|
||||
Namespace namespace = new Namespace(namespaceSlug, "Global", "user-1");
|
||||
setId(namespace, 1L);
|
||||
Skill skill = new Skill(1L, skillSlug, "user-100", SkillVisibility.PUBLIC);
|
||||
setId(skill, 3L);
|
||||
skill.setStatus(SkillStatus.ACTIVE);
|
||||
skill.setLatestVersionId(11L);
|
||||
|
||||
SkillVersion version = new SkillVersion(3L, "1.0.0 beta", "user-100");
|
||||
setId(version, 11L);
|
||||
version.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
SkillFile file = new SkillFile(11L, "SKILL.md", 10L, "text/markdown", "hash", "key");
|
||||
|
||||
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
|
||||
when(skillRepository.findByNamespaceIdAndSlug(1L, skillSlug)).thenReturn(Optional.of(skill));
|
||||
when(visibilityChecker.canAccess(skill, null, userNsRoles)).thenReturn(true);
|
||||
when(skillVersionRepository.findById(11L)).thenReturn(Optional.of(version));
|
||||
when(skillVersionRepository.findBySkillIdAndStatus(3L, SkillVersionStatus.PUBLISHED)).thenReturn(List.of(version));
|
||||
when(skillFileRepository.findByVersionId(11L)).thenReturn(List.of(file));
|
||||
|
||||
SkillQueryService.ResolvedVersionDTO result = service.resolveVersion(
|
||||
namespaceSlug,
|
||||
skillSlug,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
userNsRoles
|
||||
);
|
||||
|
||||
assertEquals("/api/v1/skills/global/smoke-skill-two/versions/1.0.0%20beta/download", result.downloadUrl());
|
||||
}
|
||||
|
||||
private void setId(Object entity, Long id) throws Exception {
|
||||
Field idField = entity.getClass().getDeclaredField("id");
|
||||
idField.setAccessible(true);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue