e071084ebe
govulncheck / govulncheck (push) Has been cancelled
Lint / golangci-lint (push) Has been cancelled
Run Tests / Unit Tests (push) Has been cancelled
Run Tests / Etcd Integration Tests (push) Has been cancelled
Harness (E2E) / Harnesses (mock LLM) (push) Has been cancelled
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Has been cancelled
168 lines
4.5 KiB
Go
168 lines
4.5 KiB
Go
package deploy
|
|
|
|
import (
|
|
"flag"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/urfave/cli/v2"
|
|
"go-micro.dev/v6/cmd/micro/run/config"
|
|
)
|
|
|
|
func newDeployTestContext(t *testing.T, args ...string) *cli.Context {
|
|
t.Helper()
|
|
set := flag.NewFlagSet("deploy", flag.ContinueOnError)
|
|
set.String("path", defaultRemotePath, "")
|
|
set.String("ssh", "", "")
|
|
set.String("service", "", "")
|
|
set.Bool("build", false, "")
|
|
set.Bool("dry-run", false, "")
|
|
if err := set.Parse(args); err != nil {
|
|
t.Fatalf("parse flags: %v", err)
|
|
}
|
|
return cli.NewContext(cli.NewApp(), set, nil)
|
|
}
|
|
|
|
func TestDeployNoTargetExplainsInitAndDeployHandoff(t *testing.T) {
|
|
err := showDeployHelp()
|
|
if err == nil {
|
|
t.Fatal("expected missing target guidance")
|
|
}
|
|
msg := err.Error()
|
|
for _, want := range []string{
|
|
"no deployment target specified",
|
|
"sudo micro init --server",
|
|
"micro deploy user@your-server",
|
|
"deploy prod",
|
|
} {
|
|
if !strings.Contains(msg, want) {
|
|
t.Fatalf("missing %q in guidance:\n%s", want, msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDeployListsConfiguredTargetsWhenNoTargetProvided(t *testing.T) {
|
|
err := showDeployTargets(&config.Config{Deploy: map[string]*config.DeployTarget{
|
|
"prod": {Name: "prod", SSH: "deploy@prod.example.com"},
|
|
"staging": {Name: "staging", SSH: "deploy@staging.example.com"},
|
|
}})
|
|
if err == nil {
|
|
t.Fatal("expected configured target guidance")
|
|
}
|
|
msg := err.Error()
|
|
for _, want := range []string{
|
|
"Available deploy targets:",
|
|
"prod -> deploy@prod.example.com",
|
|
"staging -> deploy@staging.example.com",
|
|
"micro deploy <target>",
|
|
} {
|
|
if !strings.Contains(msg, want) {
|
|
t.Fatalf("missing %q in configured target guidance:\n%s", want, msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResolveDeployTargetUsesConfigTargetAndPath(t *testing.T) {
|
|
ctx := newDeployTestContext(t, "prod")
|
|
cfg := &config.Config{Deploy: map[string]*config.DeployTarget{
|
|
"prod": {Name: "prod", SSH: "deploy@prod.example.com", Path: "/srv/micro"},
|
|
}}
|
|
|
|
target, remotePath := resolveDeployTarget(ctx, ctx.Args().First(), cfg)
|
|
if target != "deploy@prod.example.com" {
|
|
t.Fatalf("target = %q, want configured SSH", target)
|
|
}
|
|
if remotePath != "/srv/micro" {
|
|
t.Fatalf("remotePath = %q, want configured path", remotePath)
|
|
}
|
|
}
|
|
|
|
func TestResolveDeployTargetAllowsCLIPathOverride(t *testing.T) {
|
|
ctx := newDeployTestContext(t, "--path", "/tmp/micro", "prod")
|
|
cfg := &config.Config{Deploy: map[string]*config.DeployTarget{
|
|
"prod": {Name: "prod", SSH: "deploy@prod.example.com", Path: "/srv/micro"},
|
|
}}
|
|
|
|
target, remotePath := resolveDeployTarget(ctx, ctx.Args().First(), cfg)
|
|
if target != "deploy@prod.example.com" {
|
|
t.Fatalf("target = %q, want configured SSH", target)
|
|
}
|
|
if remotePath != "/tmp/micro" {
|
|
t.Fatalf("remotePath = %q, want CLI override", remotePath)
|
|
}
|
|
}
|
|
|
|
func TestDeployConfigParserSupportsDeployTargets(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := dir + "/micro.mu"
|
|
content := `service api
|
|
path ./api
|
|
|
|
deploy prod
|
|
ssh deploy@prod.example.com
|
|
path /srv/micro
|
|
`
|
|
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
|
t.Fatalf("write config: %v", err)
|
|
}
|
|
|
|
cfg, err := config.ParseMu(path)
|
|
if err != nil {
|
|
t.Fatalf("parse config: %v", err)
|
|
}
|
|
prod := cfg.Deploy["prod"]
|
|
if prod == nil {
|
|
t.Fatal("missing prod deploy target")
|
|
}
|
|
if prod.SSH != "deploy@prod.example.com" || prod.Path != "/srv/micro" {
|
|
t.Fatalf("deploy target = %#v", prod)
|
|
}
|
|
}
|
|
|
|
func TestDeployDryRunPlansConfiguredTargetWithoutRemoteSideEffects(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.WriteFile(dir+"/micro.mu", []byte(`service api
|
|
path ./api
|
|
|
|
deploy prod
|
|
ssh deploy@prod.example.com
|
|
path /srv/micro
|
|
`), 0644); err != nil {
|
|
t.Fatalf("write config: %v", err)
|
|
}
|
|
|
|
oldwd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatalf("getwd: %v", err)
|
|
}
|
|
if err := os.Chdir(dir); err != nil {
|
|
t.Fatalf("chdir: %v", err)
|
|
}
|
|
t.Cleanup(func() {
|
|
if err := os.Chdir(oldwd); err != nil {
|
|
t.Errorf("restore cwd: %v", err)
|
|
}
|
|
})
|
|
|
|
ctx := newDeployTestContext(t, "--dry-run", "prod")
|
|
if err := Deploy(ctx); err != nil {
|
|
t.Fatalf("dry-run deploy: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDeployDryRunValidatesRequestedService(t *testing.T) {
|
|
ctx := newDeployTestContext(t, "--dry-run", "--service", "missing", "prod")
|
|
cfg := &config.Config{Services: map[string]*config.Service{
|
|
"api": {Name: "api", Path: "./api"},
|
|
}}
|
|
|
|
err := printDeployPlan(ctx, "deploy@prod.example.com", cfg, defaultRemotePath)
|
|
if err == nil {
|
|
t.Fatal("expected dry-run to validate service names")
|
|
}
|
|
if !strings.Contains(err.Error(), "service 'missing' not found in configuration") {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
}
|