test(summer): plugin command prompts
- TestPluginCommands: plugin:install needs --yes off a terminal, --offline and a disabled registry refuse ID installs without registry calls, plugin:manifest --check exit status and output on missing and stale files - check-phase34.sh: the 34-06 unit tests are required names of --go
This commit is contained in:
161
cmd/summer/plugin_commands_test.go
Normal file
161
cmd/summer/plugin_commands_test.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/bonfire"
|
||||
"git.golem15.com/golem15/summercms/modules/kiosk"
|
||||
)
|
||||
|
||||
// runTool runs the summer CLI with args through bonfire.Execute and
|
||||
// returns the exit status and what went to the root's writer.
|
||||
func runTool(t *testing.T, args ...string) (int, string) {
|
||||
t.Helper()
|
||||
var buf bytes.Buffer
|
||||
root, err := bonfire.NewRoot("summer", toolCommands(), &buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root.SetErr(&buf)
|
||||
code := bonfire.Execute(context.Background(), root, args)
|
||||
return code, buf.String()
|
||||
}
|
||||
|
||||
// writeFiles writes files (slash paths relative to root).
|
||||
func writeFiles(t *testing.T, root string, files map[string]string) {
|
||||
t.Helper()
|
||||
for rel, body := range files {
|
||||
path := filepath.Join(root, filepath.FromSlash(rel))
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(path, []byte(body), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestPluginCommands covers the CLI rules of plugin:install and
|
||||
// plugin:manifest that do not need a build: the --yes rule off a terminal,
|
||||
// --offline ID installs, and --check's exit status and output.
|
||||
func TestPluginCommands(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
calls.Add(1)
|
||||
if r.URL.Path == kiosk.RegistryAPIPath+"/plugins/acme.shop/versions" {
|
||||
_ = json.NewEncoder(w).Encode(kiosk.VersionsResponse{Data: []kiosk.RegistryVersion{{
|
||||
Version: "v0.1.0", Framework: "v0.6.0", Module: "example.test/sm-shop-plugin", Package: "example.test/sm-shop-plugin",
|
||||
}}})
|
||||
return
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
app := t.TempDir()
|
||||
writeFiles(t, app, map[string]string{
|
||||
"summer.yaml": "module: example.test/app\nbinary: app\n",
|
||||
"go.mod": "module example.test/app\n\ngo 1.27.0\n\nrequire git.golem15.com/golem15/summercms v0.6.0\n",
|
||||
"config/.gitkeep": "",
|
||||
})
|
||||
t.Chdir(app)
|
||||
t.Setenv("SUMMER_PLUGINS__REGISTRY_URL", srv.URL)
|
||||
|
||||
t.Run("install needs --yes off a terminal", func(t *testing.T) {
|
||||
code, out := runTool(t, "plugin:install", "acme.shop")
|
||||
if code == bonfire.ExitOK || !strings.Contains(out, "--yes") {
|
||||
t.Fatalf("exit %d, output:\n%s", code, out)
|
||||
}
|
||||
if !strings.Contains(out, "acme.shop@v0.1.0 (module)") {
|
||||
t.Errorf("the plan was not printed before the refusal:\n%s", out)
|
||||
}
|
||||
before, _ := os.ReadFile(filepath.Join(app, "summer.yaml"))
|
||||
if string(before) != "module: example.test/app\nbinary: app\n" {
|
||||
t.Errorf("summer.yaml changed:\n%s", before)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("offline ID install", func(t *testing.T) {
|
||||
calls.Store(0)
|
||||
code, out := runTool(t, "plugin:install", "acme.shop", "--offline", "--yes")
|
||||
if code == bonfire.ExitOK || !strings.Contains(out, "--offline") {
|
||||
t.Fatalf("exit %d, output:\n%s", code, out)
|
||||
}
|
||||
if n := calls.Load(); n != 0 {
|
||||
t.Errorf("--offline made %d registry calls", n)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("disabled registry", func(t *testing.T) {
|
||||
t.Setenv("SUMMER_PLUGINS__REGISTRY_URL", "")
|
||||
calls.Store(0)
|
||||
code, out := runTool(t, "plugin:install", "acme.shop", "--yes")
|
||||
if code == bonfire.ExitOK || !strings.Contains(out, "plugins.registry_url") || calls.Load() != 0 {
|
||||
t.Fatalf("exit %d, calls %d, output:\n%s", code, calls.Load(), out)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("install outside an application", func(t *testing.T) {
|
||||
t.Chdir(t.TempDir())
|
||||
if code, _ := runTool(t, "plugin:install", "acme.shop", "--yes"); code == bonfire.ExitOK {
|
||||
t.Error("plugin:install outside an application succeeded")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("manifest --check", func(t *testing.T) {
|
||||
plugin := t.TempDir()
|
||||
writeFiles(t, plugin, map[string]string{
|
||||
"go.mod": "module example.test/sm-shop-plugin\n\ngo 1.27.0\n\nrequire " + kiosk.FrameworkModule + " v0.6.0\n",
|
||||
"plugin.go": "package shop\n\ntype Plugin struct{}\n\nfunc (*Plugin) ID() string { return \"acme.shop\" }\n",
|
||||
"README.md": "# Shop\n\nProducts and orders.\n",
|
||||
})
|
||||
path := filepath.Join(plugin, kiosk.FileName)
|
||||
|
||||
code, out := runTool(t, "plugin:manifest", "--check", plugin)
|
||||
if code != bonfire.ExitFailure || !strings.Contains(out, "Expected "+path+":") || !strings.Contains(out, "id: acme.shop") ||
|
||||
!strings.Contains(out, "is missing") {
|
||||
t.Fatalf("missing: exit %d, output:\n%s", code, out)
|
||||
}
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
t.Fatalf("--check wrote %s", path)
|
||||
}
|
||||
|
||||
if code, out := runTool(t, "plugin:manifest", plugin); code != bonfire.ExitOK || !strings.Contains(out, "Wrote "+path) {
|
||||
t.Fatalf("write: exit %d, output:\n%s", code, out)
|
||||
}
|
||||
if code, out := runTool(t, "plugin:manifest", "--check", plugin); code != bonfire.ExitOK || !strings.Contains(out, "is up to date") {
|
||||
t.Fatalf("fresh: exit %d, output:\n%s", code, out)
|
||||
}
|
||||
|
||||
writeFiles(t, plugin, map[string]string{"README.md": "# Shop\n\nProducts, carts and orders.\n"})
|
||||
written, _ := os.ReadFile(path)
|
||||
code, out = runTool(t, "plugin:manifest", "--check", plugin)
|
||||
if code != bonfire.ExitFailure || !strings.Contains(out, "is stale") || !strings.Contains(out, "description: Products, carts and orders.") {
|
||||
t.Fatalf("stale: exit %d, output:\n%s", code, out)
|
||||
}
|
||||
if after, _ := os.ReadFile(path); !bytes.Equal(after, written) {
|
||||
t.Error("--check rewrote a stale file")
|
||||
}
|
||||
|
||||
code, out = runTool(t, "plugin:manifest", "--check", "--name", "Shop", plugin)
|
||||
if code == bonfire.ExitOK || !strings.Contains(out, "takes no --name or --description") {
|
||||
t.Fatalf("--check --name: exit %d, output:\n%s", code, out)
|
||||
}
|
||||
code, out = runTool(t, "plugin:manifest", "--pretend", plugin)
|
||||
if code != bonfire.ExitOK || !strings.Contains(out, "description: Products, carts and orders.") {
|
||||
t.Fatalf("--pretend: exit %d, output:\n%s", code, out)
|
||||
}
|
||||
if after, _ := os.ReadFile(path); !bytes.Equal(after, written) {
|
||||
t.Error("--pretend wrote the file")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -91,6 +91,15 @@ GO_TESTS=(
|
||||
./modules/kiosk:TestManifestSmoke ./modules/kiosk:TestPluginManifest
|
||||
./internal/build:TestPluginInfoSmoke ./internal/build:TestAddPluginConstID
|
||||
./modules/cabana:TestPluginsScreenSmoke
|
||||
# 34-06 unit tests.
|
||||
./modules/kiosk:TestReadIdentity ./modules/kiosk:TestDerive ./modules/kiosk:TestManifestFormat
|
||||
./modules/kiosk:TestCheck ./modules/kiosk:TestVersions ./modules/kiosk:TestRegistryClient
|
||||
./modules/kiosk:TestPackagePath ./modules/kiosk:TestPluginDirs ./modules/kiosk:TestLastElem
|
||||
./modules/kiosk:ExampleMarshal ./modules/kiosk:ExampleNewestCompatible
|
||||
./modules/party:TestDescribe
|
||||
./internal/build:TestPluginDirs ./internal/build:TestEffectiveFramework ./internal/build:TestResolveInstall
|
||||
./internal/build:TestAskToProceed ./internal/build:TestAppendManifestPlugins
|
||||
./cmd/summer:TestPluginCommands
|
||||
)
|
||||
|
||||
# docker stage: the non-short framework tests (file:// proxies, git
|
||||
|
||||
Reference in New Issue
Block a user