|
| 1 | +package vscode |
| 2 | + |
| 3 | +import ( |
| 4 | + "encoding/json" |
| 5 | + "os" |
| 6 | + "path/filepath" |
| 7 | + "runtime" |
| 8 | + "testing" |
| 9 | + |
| 10 | + "github.com/jfrog/jfrog-cli-core/v2/utils/config" |
| 11 | + "github.com/stretchr/testify/assert" |
| 12 | + "github.com/stretchr/testify/require" |
| 13 | +) |
| 14 | + |
| 15 | +func TestNewVscodeCommand(t *testing.T) { |
| 16 | + serviceURL := "https://company.jfrog.io/artifactory/api/vscodeextensions/repo/_apis/public/gallery" |
| 17 | + productPath := "/custom/path/product.json" |
| 18 | + repoKey := "repo" |
| 19 | + |
| 20 | + cmd := NewVscodeCommand(serviceURL, productPath, repoKey) |
| 21 | + |
| 22 | + assert.Equal(t, serviceURL, cmd.serviceURL) |
| 23 | + assert.Equal(t, productPath, cmd.productPath) |
| 24 | + assert.Equal(t, repoKey, cmd.repoKey) |
| 25 | +} |
| 26 | + |
| 27 | +func TestVscodeCommand_CommandName(t *testing.T) { |
| 28 | + cmd := NewVscodeCommand("", "", "") |
| 29 | + assert.Equal(t, "rt_vscode_config", cmd.CommandName()) |
| 30 | +} |
| 31 | + |
| 32 | +func TestVscodeCommand_SetServerDetails(t *testing.T) { |
| 33 | + cmd := NewVscodeCommand("", "", "") |
| 34 | + serverDetails := &config.ServerDetails{ |
| 35 | + Url: "https://company.jfrog.io", |
| 36 | + ArtifactoryUrl: "https://company.jfrog.io/artifactory", |
| 37 | + AccessToken: "test-token", |
| 38 | + } |
| 39 | + |
| 40 | + result := cmd.SetServerDetails(serverDetails) |
| 41 | + |
| 42 | + assert.Equal(t, serverDetails, cmd.serverDetails) |
| 43 | + assert.Equal(t, cmd, result) // Should return self for chaining |
| 44 | +} |
| 45 | + |
| 46 | +func TestVscodeCommand_ServerDetails(t *testing.T) { |
| 47 | + cmd := NewVscodeCommand("", "", "") |
| 48 | + serverDetails := &config.ServerDetails{ |
| 49 | + Url: "https://company.jfrog.io", |
| 50 | + ArtifactoryUrl: "https://company.jfrog.io/artifactory", |
| 51 | + AccessToken: "test-token", |
| 52 | + } |
| 53 | + |
| 54 | + cmd.SetServerDetails(serverDetails) |
| 55 | + |
| 56 | + details, err := cmd.ServerDetails() |
| 57 | + assert.NoError(t, err) |
| 58 | + assert.Equal(t, serverDetails, details) |
| 59 | +} |
| 60 | + |
| 61 | +func TestVscodeCommand_DetectVSCodeInstallation(t *testing.T) { |
| 62 | + // This test verifies that the detection method runs without error |
| 63 | + // but skips actual file checks since they depend on the environment |
| 64 | + cmd := NewVscodeCommand("", "", "") |
| 65 | + |
| 66 | + // The method should not panic and should handle missing installations gracefully |
| 67 | + _, err := cmd.detectVSCodeInstallation() |
| 68 | + // We expect an error since VSCode likely isn't installed in the test environment |
| 69 | + // But the method should handle it gracefully |
| 70 | + if err != nil { |
| 71 | + assert.Contains(t, err.Error(), "VSCode") |
| 72 | + } |
| 73 | +} |
| 74 | + |
| 75 | +func TestVscodeCommand_CheckWritePermissions_NonExistentFile(t *testing.T) { |
| 76 | + cmd := NewVscodeCommand("", "/non/existent/path/product.json", "") |
| 77 | + |
| 78 | + err := cmd.checkWritePermissions() |
| 79 | + assert.Error(t, err) |
| 80 | + assert.Contains(t, err.Error(), "failed to access product.json") |
| 81 | +} |
| 82 | + |
| 83 | +func TestVscodeCommand_CreateBackup(t *testing.T) { |
| 84 | + // Create temporary product.json file |
| 85 | + tempDir := t.TempDir() |
| 86 | + productPath := filepath.Join(tempDir, "product.json") |
| 87 | + originalContent := []byte(`{"extensionsGallery": {"serviceUrl": "https://marketplace.visualstudio.com"}}`) |
| 88 | + |
| 89 | + err := os.WriteFile(productPath, originalContent, 0644) |
| 90 | + require.NoError(t, err) |
| 91 | + |
| 92 | + cmd := NewVscodeCommand("", productPath, "") |
| 93 | + |
| 94 | + err = cmd.createBackup() |
| 95 | + assert.NoError(t, err) |
| 96 | + |
| 97 | + // Verify backup exists |
| 98 | + backupPath := productPath + ".backup" |
| 99 | + assert.FileExists(t, backupPath) |
| 100 | + |
| 101 | + // Verify backup content |
| 102 | + backupContent, err := os.ReadFile(backupPath) |
| 103 | + require.NoError(t, err) |
| 104 | + assert.Equal(t, originalContent, backupContent) |
| 105 | + |
| 106 | + // Store backup path for cleanup |
| 107 | + cmd.backupPath = backupPath |
| 108 | +} |
| 109 | + |
| 110 | +func TestVscodeCommand_RestoreBackup(t *testing.T) { |
| 111 | + // Create temporary files |
| 112 | + tempDir := t.TempDir() |
| 113 | + productPath := filepath.Join(tempDir, "product.json") |
| 114 | + backupPath := productPath + ".backup" |
| 115 | + |
| 116 | + // Create original backup content |
| 117 | + originalContent := []byte(`{"extensionsGallery": {"serviceUrl": "https://marketplace.visualstudio.com"}}`) |
| 118 | + err := os.WriteFile(backupPath, originalContent, 0644) |
| 119 | + require.NoError(t, err) |
| 120 | + |
| 121 | + // Create modified product.json |
| 122 | + modifiedContent := []byte(`{"extensionsGallery": {"serviceUrl": "https://company.jfrog.io"}}`) |
| 123 | + err = os.WriteFile(productPath, modifiedContent, 0644) |
| 124 | + require.NoError(t, err) |
| 125 | + |
| 126 | + cmd := NewVscodeCommand("", productPath, "") |
| 127 | + cmd.backupPath = backupPath |
| 128 | + |
| 129 | + err = cmd.restoreBackup() |
| 130 | + assert.NoError(t, err) |
| 131 | + |
| 132 | + // Verify restoration |
| 133 | + restoredContent, err := os.ReadFile(productPath) |
| 134 | + require.NoError(t, err) |
| 135 | + assert.Equal(t, originalContent, restoredContent) |
| 136 | +} |
| 137 | + |
| 138 | +func TestVscodeCommand_ModifyProductJson_ValidFile(t *testing.T) { |
| 139 | + // Create temporary product.json file |
| 140 | + tempDir := t.TempDir() |
| 141 | + productPath := filepath.Join(tempDir, "product.json") |
| 142 | + |
| 143 | + // Create a valid product.json |
| 144 | + productContent := map[string]interface{}{ |
| 145 | + "extensionsGallery": map[string]interface{}{ |
| 146 | + "serviceUrl": "https://marketplace.visualstudio.com/_apis/public/gallery", |
| 147 | + }, |
| 148 | + "nameShort": "Code", |
| 149 | + "version": "1.70.0", |
| 150 | + } |
| 151 | + |
| 152 | + jsonData, err := json.Marshal(productContent) |
| 153 | + require.NoError(t, err) |
| 154 | + |
| 155 | + err = os.WriteFile(productPath, jsonData, 0644) |
| 156 | + require.NoError(t, err) |
| 157 | + |
| 158 | + cmd := NewVscodeCommand("", productPath, "") |
| 159 | + newServiceURL := "https://company.jfrog.io/artifactory/api/vscodeextensions/repo/_apis/public/gallery" |
| 160 | + |
| 161 | + err = cmd.modifyProductJson(newServiceURL) |
| 162 | + assert.NoError(t, err) |
| 163 | + |
| 164 | + // Verify backup was created |
| 165 | + backupPath := productPath + ".backup" |
| 166 | + assert.FileExists(t, backupPath) |
| 167 | +} |
| 168 | + |
| 169 | +func TestVscodeCommand_ModifyProductJson_NonExistentFile(t *testing.T) { |
| 170 | + cmd := NewVscodeCommand("", "/non/existent/path/product.json", "") |
| 171 | + newServiceURL := "https://company.jfrog.io/artifactory/api/vscodeextensions/repo/_apis/public/gallery" |
| 172 | + |
| 173 | + err := cmd.modifyProductJson(newServiceURL) |
| 174 | + assert.Error(t, err) |
| 175 | +} |
| 176 | + |
| 177 | +func TestVscodeCommand_VerifyModification(t *testing.T) { |
| 178 | + // Create temporary product.json with expected content |
| 179 | + tempDir := t.TempDir() |
| 180 | + productPath := filepath.Join(tempDir, "product.json") |
| 181 | + expectedURL := "https://company.jfrog.io/artifactory/api/vscodeextensions/repo/_apis/public/gallery" |
| 182 | + |
| 183 | + productContent := map[string]interface{}{ |
| 184 | + "extensionsGallery": map[string]interface{}{ |
| 185 | + "serviceUrl": expectedURL, |
| 186 | + }, |
| 187 | + } |
| 188 | + |
| 189 | + jsonData, err := json.Marshal(productContent) |
| 190 | + require.NoError(t, err) |
| 191 | + |
| 192 | + err = os.WriteFile(productPath, jsonData, 0644) |
| 193 | + require.NoError(t, err) |
| 194 | + |
| 195 | + cmd := NewVscodeCommand("", productPath, "") |
| 196 | + |
| 197 | + err = cmd.verifyModification(expectedURL) |
| 198 | + assert.NoError(t, err) |
| 199 | +} |
| 200 | + |
| 201 | +func TestVscodeCommand_VerifyModification_WrongURL(t *testing.T) { |
| 202 | + // Create temporary product.json with different content |
| 203 | + tempDir := t.TempDir() |
| 204 | + productPath := filepath.Join(tempDir, "product.json") |
| 205 | + actualURL := "https://marketplace.visualstudio.com/_apis/public/gallery" |
| 206 | + expectedURL := "https://company.jfrog.io/artifactory/api/vscodeextensions/repo/_apis/public/gallery" |
| 207 | + |
| 208 | + productContent := map[string]interface{}{ |
| 209 | + "extensionsGallery": map[string]interface{}{ |
| 210 | + "serviceUrl": actualURL, |
| 211 | + }, |
| 212 | + } |
| 213 | + |
| 214 | + jsonData, err := json.Marshal(productContent) |
| 215 | + require.NoError(t, err) |
| 216 | + |
| 217 | + err = os.WriteFile(productPath, jsonData, 0644) |
| 218 | + require.NoError(t, err) |
| 219 | + |
| 220 | + cmd := NewVscodeCommand("", productPath, "") |
| 221 | + |
| 222 | + err = cmd.verifyModification(expectedURL) |
| 223 | + assert.Error(t, err) |
| 224 | + assert.Contains(t, err.Error(), "verification failed") |
| 225 | +} |
| 226 | + |
| 227 | +func TestVscodeCommand_GetManualSetupInstructions(t *testing.T) { |
| 228 | + cmd := NewVscodeCommand("", "", "") |
| 229 | + serviceURL := "https://company.jfrog.io/artifactory/api/vscodeextensions/repo/_apis/public/gallery" |
| 230 | + |
| 231 | + instructions := cmd.getManualSetupInstructions(serviceURL) |
| 232 | + |
| 233 | + assert.NotEmpty(t, instructions) |
| 234 | + assert.Contains(t, instructions, serviceURL) |
| 235 | + assert.Contains(t, instructions, "product.json") |
| 236 | + |
| 237 | + // Should contain platform-specific instructions |
| 238 | + switch runtime.GOOS { |
| 239 | + case "darwin": |
| 240 | + assert.Contains(t, instructions, "Applications") |
| 241 | + case "windows": |
| 242 | + assert.Contains(t, instructions, "resources") |
| 243 | + case "linux": |
| 244 | + assert.Contains(t, instructions, "usr/share") |
| 245 | + } |
| 246 | +} |
| 247 | + |
| 248 | +func TestVscodeCommand_ValidateRepository_NoServerDetails(t *testing.T) { |
| 249 | + cmd := NewVscodeCommand("", "", "repo") |
| 250 | + |
| 251 | + // Should return nil when no server details are set |
| 252 | + err := cmd.validateRepository() |
| 253 | + // This will likely fail because serverDetails is nil, but it should handle gracefully |
| 254 | + if err != nil { |
| 255 | + assert.Contains(t, err.Error(), "auth config") |
| 256 | + } |
| 257 | +} |
| 258 | + |
| 259 | +func TestVscodeCommand_HandlePermissionError_macOS(t *testing.T) { |
| 260 | + if runtime.GOOS != "darwin" { |
| 261 | + t.Skip("macOS-specific test") |
| 262 | + } |
| 263 | + |
| 264 | + cmd := NewVscodeCommand("https://company.jfrog.io/artifactory/api/vscodeextensions/repo/_apis/public/gallery", |
| 265 | + "/Applications/Visual Studio Code.app/Contents/Resources/app/product.json", "") |
| 266 | + |
| 267 | + err := cmd.handlePermissionError() |
| 268 | + assert.Error(t, err) |
| 269 | + assert.Contains(t, err.Error(), "sudo") |
| 270 | + assert.Contains(t, err.Error(), "elevated privileges") |
| 271 | + assert.Contains(t, err.Error(), "/Applications/") |
| 272 | +} |
| 273 | + |
| 274 | +// Benchmark tests for performance |
| 275 | +func BenchmarkVscodeCommand_DetectVSCodeInstallation(b *testing.B) { |
| 276 | + cmd := NewVscodeCommand("", "", "") |
| 277 | + |
| 278 | + for i := 0; i < b.N; i++ { |
| 279 | + _, _ = cmd.detectVSCodeInstallation() |
| 280 | + } |
| 281 | +} |
0 commit comments