/ internal / skills / registry_test.go
registry_test.go
  1  package skills
  2  
  3  import "testing"
  4  
  5  func TestRequiredSecrets_OpenClaw(t *testing.T) {
  6  	s := &Skill{
  7  		Metadata: map[string]any{
  8  			"openclaw": map[string]any{
  9  				"requires": map[string]any{
 10  					"env": []any{"GEMINI_API_KEY", "ANOTHER_KEY"},
 11  				},
 12  			},
 13  		},
 14  	}
 15  	secrets := s.RequiredSecrets()
 16  	if len(secrets) != 2 {
 17  		t.Fatalf("expected 2 secrets, got %d", len(secrets))
 18  	}
 19  	if secrets[0].Key != "GEMINI_API_KEY" {
 20  		t.Errorf("expected key GEMINI_API_KEY, got %s", secrets[0].Key)
 21  	}
 22  	if secrets[0].Label != "GEMINI_API_KEY" {
 23  		t.Errorf("expected label GEMINI_API_KEY, got %s", secrets[0].Label)
 24  	}
 25  	if !secrets[0].Required {
 26  		t.Error("expected required=true")
 27  	}
 28  }
 29  
 30  func TestRequiredSecrets_Clawdbot(t *testing.T) {
 31  	s := &Skill{
 32  		Metadata: map[string]any{
 33  			"clawdbot": map[string]any{
 34  				"requires": map[string]any{
 35  					"env": []any{"KIE_API_KEY"},
 36  				},
 37  			},
 38  		},
 39  	}
 40  	secrets := s.RequiredSecrets()
 41  	if len(secrets) != 1 {
 42  		t.Fatalf("expected 1 secret, got %d", len(secrets))
 43  	}
 44  	if secrets[0].Key != "KIE_API_KEY" {
 45  		t.Errorf("expected key KIE_API_KEY, got %s", secrets[0].Key)
 46  	}
 47  }
 48  
 49  // TestRequiredSecrets_Clawdis covers the third interchangeable parent
 50  // key accepted by the ClawHub spec. Rarely used in practice but
 51  // documented — skills that do use it must parse correctly.
 52  func TestRequiredSecrets_Clawdis(t *testing.T) {
 53  	s := &Skill{
 54  		Metadata: map[string]any{
 55  			"clawdis": map[string]any{
 56  				"requires": map[string]any{
 57  					"env": []any{"SOME_API_KEY"},
 58  				},
 59  			},
 60  		},
 61  	}
 62  	secrets := s.RequiredSecrets()
 63  	if len(secrets) != 1 {
 64  		t.Fatalf("expected 1 secret, got %d", len(secrets))
 65  	}
 66  	if secrets[0].Key != "SOME_API_KEY" {
 67  		t.Errorf("expected key SOME_API_KEY, got %s", secrets[0].Key)
 68  	}
 69  }
 70  
 71  func TestRequiredSecrets_BothSourcesMerged(t *testing.T) {
 72  	s := &Skill{
 73  		Metadata: map[string]any{
 74  			"openclaw": map[string]any{
 75  				"requires": map[string]any{
 76  					"env": []any{"SHARED_KEY", "OPENCLAW_ONLY"},
 77  				},
 78  			},
 79  			"clawdbot": map[string]any{
 80  				"requires": map[string]any{
 81  					"env": []any{"SHARED_KEY", "CLAWDBOT_ONLY"},
 82  				},
 83  			},
 84  		},
 85  	}
 86  	secrets := s.RequiredSecrets()
 87  	if len(secrets) != 3 {
 88  		t.Fatalf("expected 3 secrets (deduplicated), got %d", len(secrets))
 89  	}
 90  	keys := map[string]bool{}
 91  	for _, s := range secrets {
 92  		keys[s.Key] = true
 93  	}
 94  	for _, expected := range []string{"SHARED_KEY", "OPENCLAW_ONLY", "CLAWDBOT_ONLY"} {
 95  		if !keys[expected] {
 96  			t.Errorf("missing expected key %s", expected)
 97  		}
 98  	}
 99  }
100  
101  // TestRequiredSecrets_AllThreeSourcesMerged covers the three-way dedup
102  // path when a skill author declares the same key under multiple
103  // interchangeable parent aliases (openclaw / clawdbot / clawdis).
104  func TestRequiredSecrets_AllThreeSourcesMerged(t *testing.T) {
105  	s := &Skill{
106  		Metadata: map[string]any{
107  			"openclaw": map[string]any{
108  				"requires": map[string]any{"env": []any{"SHARED"}},
109  			},
110  			"clawdbot": map[string]any{
111  				"requires": map[string]any{"env": []any{"SHARED", "CLAWDBOT_ONLY"}},
112  			},
113  			"clawdis": map[string]any{
114  				"requires": map[string]any{"env": []any{"SHARED", "CLAWDIS_ONLY"}},
115  			},
116  		},
117  	}
118  	secrets := s.RequiredSecrets()
119  	if len(secrets) != 3 {
120  		t.Fatalf("expected 3 deduplicated secrets, got %d: %v", len(secrets), secrets)
121  	}
122  	keys := map[string]bool{}
123  	for _, s := range secrets {
124  		keys[s.Key] = true
125  	}
126  	for _, expected := range []string{"SHARED", "CLAWDBOT_ONLY", "CLAWDIS_ONLY"} {
127  		if !keys[expected] {
128  			t.Errorf("missing expected key %s", expected)
129  		}
130  	}
131  }
132  
133  func TestRequiredSecrets_NoMetadata(t *testing.T) {
134  	s := &Skill{}
135  	secrets := s.RequiredSecrets()
136  	if len(secrets) != 0 {
137  		t.Fatalf("expected 0 secrets, got %d", len(secrets))
138  	}
139  }
140  
141  func TestRequiredSecrets_MalformedMetadata(t *testing.T) {
142  	s := &Skill{
143  		Metadata: map[string]any{
144  			"openclaw": "not-a-map",
145  		},
146  	}
147  	secrets := s.RequiredSecrets()
148  	if len(secrets) != 0 {
149  		t.Fatalf("expected 0 secrets on malformed metadata, got %d", len(secrets))
150  	}
151  }