71c7672545
* feat(skill-hub): add Skill Hub catalog, publish flow, and lite materialize pipeline Introduce Skill Hub for browsing, importing, publishing, and installing skills, with lite instance package materialization and runtime sync support. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(skill-hub): remove token-governance hooks from Skill Hub PR Strip validateManagedRuntimeEnvironmentOverrides, network lock policy sync, and egress proxy audit wiring that belong to the upcoming token-usage work, so the Skill Hub branch compiles independently. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(skill-hub): update migration number in materialize docs Co-authored-by: Cursor <cursoragent@cursor.com> * fix(skill-hub): make RuntimeAgentClient test stub and hub tests compile-safe Add ResyncInstanceSkills to the runtime pool handler fake client, and harden skill hub payload helpers/tests against nil storage/instance repos so go test passes. Co-authored-by: Cursor <cursoragent@cursor.com> * feat: add Skill Hub hardening with session usage tracking and egress governance Unify Skill Hub runtime sync improvements with session-token observability, egress network policy, and admin/instance usage reporting for reopenable PR. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(skill-hub): repair CI tests and nested skill install * fix(ci): restore release deployment configuration --------- Co-authored-by: heshengran <heshengran@ieisystem.com> Co-authored-by: Cursor <cursoragent@cursor.com>
76 lines
2.6 KiB
Go
76 lines
2.6 KiB
Go
package services
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"clawreef/internal/models"
|
|
)
|
|
|
|
func TestPreviewImportDirectoryNone(t *testing.T) {
|
|
svc := &skillService{repo: &skillRepoStub{skills: map[int]*models.Skill{}}}
|
|
item, err := svc.previewImportDirectory(1, extractedSkillDirectory{
|
|
Name: "weather",
|
|
Files: map[string][]byte{"SKILL.md": []byte("# weather")},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("previewImportDirectory() error = %v", err)
|
|
}
|
|
if item.ConflictType != skillImportConflictNone {
|
|
t.Fatalf("conflict_type = %q, want %q", item.ConflictType, skillImportConflictNone)
|
|
}
|
|
}
|
|
|
|
func TestPreviewImportDirectoryUnchanged(t *testing.T) {
|
|
versionID := 10
|
|
blobID := 20
|
|
dir := extractedSkillDirectory{Name: "weather", Files: map[string][]byte{"SKILL.md": []byte("# weather")}}
|
|
contentHash := hashDirectory(dir.Files)
|
|
stub := &skillRepoStub{
|
|
skills: map[int]*models.Skill{
|
|
1: {
|
|
ID: 1, UserID: 1, SkillKey: "weather", Name: "Weather", Status: skillStatusActive,
|
|
SourceType: skillSourceUploaded, CurrentVersionID: &versionID,
|
|
},
|
|
},
|
|
versions: map[int]*models.SkillVersion{versionID: {ID: versionID, SkillID: 1, BlobID: blobID, VersionNo: 2}},
|
|
blobs: map[int]*models.SkillBlob{blobID: {ID: blobID, ContentHash: contentHash, ScanStatus: "completed"}},
|
|
}
|
|
svc := &skillService{repo: stub}
|
|
item, err := svc.previewImportDirectory(1, dir)
|
|
if err != nil {
|
|
t.Fatalf("previewImportDirectory() error = %v", err)
|
|
}
|
|
if item.ConflictType != skillImportConflictUnchanged {
|
|
t.Fatalf("conflict_type = %q, want %q", item.ConflictType, skillImportConflictUnchanged)
|
|
}
|
|
}
|
|
|
|
func TestPreviewImportDirectoryContentChanged(t *testing.T) {
|
|
versionID := 10
|
|
blobID := 20
|
|
stub := &skillRepoStub{
|
|
skills: map[int]*models.Skill{
|
|
1: {
|
|
ID: 1, UserID: 1, SkillKey: "weather", Name: "Weather", Status: skillStatusActive,
|
|
SourceType: skillSourceUploaded, CurrentVersionID: &versionID,
|
|
},
|
|
},
|
|
versions: map[int]*models.SkillVersion{versionID: {ID: versionID, SkillID: 1, BlobID: blobID, VersionNo: 2}},
|
|
blobs: map[int]*models.SkillBlob{blobID: {ID: blobID, ContentHash: "old-hash", ScanStatus: "completed"}},
|
|
}
|
|
svc := &skillService{repo: stub}
|
|
item, err := svc.previewImportDirectory(1, extractedSkillDirectory{
|
|
Name: "weather",
|
|
Files: map[string][]byte{"SKILL.md": []byte("# changed")},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("previewImportDirectory() error = %v", err)
|
|
}
|
|
if item.ConflictType != skillImportConflictContentChanged {
|
|
t.Fatalf("conflict_type = %q, want %q", item.ConflictType, skillImportConflictContentChanged)
|
|
}
|
|
if item.SuggestedSkillKey == nil || *item.SuggestedSkillKey != "weather-2" {
|
|
t.Fatalf("suggested skill key = %v, want weather-2", item.SuggestedSkillKey)
|
|
}
|
|
}
|