diff --git a/plugins/platform-test/backend/go.mod b/plugins/platform-test/backend/go.mod new file mode 100644 index 0000000..e125491 --- /dev/null +++ b/plugins/platform-test/backend/go.mod @@ -0,0 +1,3 @@ +module github.com/verstak/verstak-official-plugins/plugins/platform-test + +go 1.24.4 diff --git a/plugins/platform-test/backend/main.go b/plugins/platform-test/backend/main.go new file mode 100644 index 0000000..8f00a30 --- /dev/null +++ b/plugins/platform-test/backend/main.go @@ -0,0 +1,112 @@ +// Platform Test Plugin โ Sidecar Backend +// Mock implementation for runtime integration testing. + +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" + "runtime" + "time" +) + +// TestResult represents a single test result. +type TestResult struct { + Name string `json:"name"` + Passed bool `json:"passed"` + Duration string `json:"duration"` + Error string `json:"error,omitempty"` +} + +// TestSuite represents a collection of tests. +type TestSuite struct { + PluginID string `json:"pluginId"` + Version string `json:"version"` + Timestamp string `json:"timestamp"` + Tests []TestResult `json:"tests"` + AllPassed bool `json:"allPassed"` + TotalPassed int `json:"totalPassed"` + TotalFailed int `json:"totalFailed"` +} + +func main() { + log.Println("[platform-test] sidecar starting...") + log.Printf("[platform-test] runtime: %s %s\n", runtime.GOOS, runtime.GOARCH) + log.Printf("[platform-test] go version: %s\n", runtime.Version()) + + suite := TestSuite{ + PluginID: "verstak.platform-test", + Version: "0.1.0", + Timestamp: time.Now().UTC().Format(time.RFC3339), + } + + suite.Tests = append(suite.Tests, runTest("sidecar_process_check", testSidecarProcess)...) + suite.Tests = append(suite.Tests, runTest("filesystem_access", testFilesystemAccess)...) + suite.Tests = append(suite.Tests, runTest("network_localhost", testLocalhostReachability)...) + + for _, t := range suite.Tests { + if t.Passed { + suite.TotalPassed++ + } else { + suite.TotalFailed++ + } + } + suite.AllPassed = suite.TotalFailed == 0 + + // Output results as JSON + output, _ := json.MarshalIndent(suite, "", " ") + fmt.Println(string(output)) + + if !suite.AllPassed { + os.Exit(1) + } +} + +func runTest(name string, fn func() error) []TestResult { + start := time.Now() + err := fn() + duration := time.Since(start).String() + + result := TestResult{ + Name: name, + Duration: duration, + } + + if err != nil { + result.Passed = false + result.Error = err.Error() + } else { + result.Passed = true + } + + return []TestResult{result} +} + +func testSidecarProcess() error { + log.Println("[test] sidecar_process_check") + // Verify we're running as a child process with proper env + if os.Getenv("VERSTAK_PLUGIN_ID") == "" { + return fmt.Errorf("VERSTAK_PLUGIN_ID not set") + } + return nil +} + +func testFilesystemAccess() error { + log.Println("[test] filesystem_access") + // Ensure we can create temp files (sandbox check) + tmpFile, err := os.CreateTemp("", "verstak-platform-test-*") + if err != nil { + return fmt.Errorf("cannot create temp file: %w", err) + } + tmpFile.Close() + os.Remove(tmpFile.Name()) + return nil +} + +func testLocalhostReachability() error { + log.Println("[test] network_localhost") + // Verify localhost is reachable if requested + return nil // stub +} diff --git a/plugins/platform-test/frontend/dist/index.js b/plugins/platform-test/frontend/dist/index.js new file mode 100644 index 0000000..e8dfe45 --- /dev/null +++ b/plugins/platform-test/frontend/dist/index.js @@ -0,0 +1,129 @@ +// Platform Test Plugin โ Runtime Diagnostics Panel +// Renders inside the Plugin Manager UI via the contributions system. + +class DiagnosticsPanel extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + connectedCallback() { + this.render(); + this.runTests(); + } + + async runTests() { + const results = []; + const tests = [ + { name: 'manifest loaded', run: () => this.manifest !== null }, + { name: 'api version >= 0.1.0', run: () => this.compareVersions(this.apiVersion, '0.1.0') >= 0 }, + { name: 'capability registered', run: () => this.checkCapability('verstak/platform-test/v1') }, + { name: 'container exists', run: () => !!document.getElementById('platform-test-root') }, + ]; + + for (const test of tests) { + try { + const passed = await test.run(); + results.push({ name: test.name, passed, error: null }); + } catch (e) { + results.push({ name: test.name, passed: false, error: e.message }); + } + } + + this.renderResults(results); + } + + compareVersions(a, b) { + const pa = a.split('.').map(Number); + const pb = b.split('.').map(Number); + for (let i = 0; i < 3; i++) { + if ((pa[i] || 0) > (pb[i] || 0)) return 1; + if ((pa[i] || 0) < (pb[i] || 0)) return -1; + } + return 0; + } + + async checkCapability(name) { + try { + const caps = await window.go.api.App.GetCapabilities(); + return caps.some(c => c.name === name); + } catch { + return false; + } + } + + get manifest() { + try { + return window.__VERSTAK_PLUGIN_MANIFEST__ || null; + } catch { + return null; + } + } + + get apiVersion() { + return this.manifest?.apiVersion || '0.0.0'; + } + + render() { + this.shadowRoot.innerHTML = ` +
+ Runtime tests for plugin infrastructure +
+Running tests...
+| Test | +Result | +
|---|---|
| ${r.name} | ++ ${r.passed ? 'โ PASS' : 'โ FAIL'}${r.error ? ` โ ${r.error}` : ''} + | +