From c93ba833100e1f903cd245dc8824cb2263f679d2 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 19 May 2018 11:04:47 -0700 Subject: [PATCH] command/connect/proxy: tests for configuration --- command/connect/proxy/proxy.go | 30 ++++++++--- command/connect/proxy/proxy_test.go | 83 +++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 command/connect/proxy/proxy_test.go diff --git a/command/connect/proxy/proxy.go b/command/connect/proxy/proxy.go index fc9e65b860..5d219d3eff 100644 --- a/command/connect/proxy/proxy.go +++ b/command/connect/proxy/proxy.go @@ -8,6 +8,7 @@ import ( "net/http" _ "net/http/pprof" // Expose pprof if configured "os" + "sort" proxyAgent "github.com/hashicorp/consul/agent/proxy" "github.com/hashicorp/consul/api" @@ -44,6 +45,9 @@ type cmd struct { pprofAddr string service string upstreams map[string]proxyImpl.UpstreamConfig + + // test flags + testNoStart bool // don't start the proxy, just exit 0 } func (c *cmd) init() { @@ -86,6 +90,10 @@ func (c *cmd) Run(args []string) int { if err := c.flags.Parse(args); err != nil { return 1 } + if len(c.flags.Args()) > 0 { + c.UI.Error(fmt.Sprintf("Should have no non-flag arguments.")) + return 1 + } // Load the proxy ID and token from env vars if they're set if c.proxyID == "" { @@ -147,10 +155,11 @@ func (c *cmd) Run(args []string) int { c.UI.Output("Log data will now stream in as it occurs:\n") logGate.Flush() - // Run the proxy - err = p.Serve() - if err != nil { - c.UI.Error(fmt.Sprintf("Failed running proxy: %s", err)) + // Run the proxy unless our tests require we don't + if !c.testNoStart { + if err := p.Serve(); err != nil { + c.UI.Error(fmt.Sprintf("Failed running proxy: %s", err)) + } } c.UI.Output("Consul Connect proxy shutdown") @@ -179,10 +188,17 @@ func (c *cmd) configWatcher(client *api.Client) (proxyImpl.ConfigWatcher, error) "configure itself.") } - // Convert our upstreams to a slice of configurations + // Convert our upstreams to a slice of configurations. We do this + // deterministically by alphabetizing the upstream keys. We do this so + // that tests can compare the upstream values. + upstreamKeys := make([]string, 0, len(c.upstreams)) + for k := range c.upstreams { + upstreamKeys = append(upstreamKeys, k) + } + sort.Strings(upstreamKeys) upstreams := make([]proxyImpl.UpstreamConfig, 0, len(c.upstreams)) - for _, u := range c.upstreams { - upstreams = append(upstreams, u) + for _, k := range upstreamKeys { + upstreams = append(upstreams, c.upstreams[k]) } return proxyImpl.NewStaticConfigWatcher(&proxyImpl.Config{ diff --git a/command/connect/proxy/proxy_test.go b/command/connect/proxy/proxy_test.go new file mode 100644 index 0000000000..b99fbfae1b --- /dev/null +++ b/command/connect/proxy/proxy_test.go @@ -0,0 +1,83 @@ +package proxy + +import ( + "testing" + "time" + + "github.com/hashicorp/consul/agent" + "github.com/hashicorp/consul/connect/proxy" + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" +) + +func TestCommandConfigWatcher(t *testing.T) { + t.Parallel() + + cases := []struct { + Name string + Flags []string + Test func(*testing.T, *proxy.Config) + }{ + { + "-service flag only", + []string{"-service", "web"}, + func(t *testing.T, cfg *proxy.Config) { + require.Equal(t, 0, cfg.PublicListener.BindPort) + require.Len(t, cfg.Upstreams, 0) + }, + }, + + { + "-service flag with upstreams", + []string{ + "-service", "web", + "-upstream", "db:1234", + "-upstream", "db2:2345", + }, + func(t *testing.T, cfg *proxy.Config) { + require.Equal(t, 0, cfg.PublicListener.BindPort) + require.Len(t, cfg.Upstreams, 2) + require.Equal(t, 1234, cfg.Upstreams[0].LocalBindPort) + require.Equal(t, 2345, cfg.Upstreams[1].LocalBindPort) + }, + }, + } + + for _, tc := range cases { + t.Run(tc.Name, func(t *testing.T) { + require := require.New(t) + + a := agent.NewTestAgent(t.Name(), ``) + defer a.Shutdown() + client := a.Client() + + ui := cli.NewMockUi() + c := New(ui, make(chan struct{})) + c.testNoStart = true + + // Run and purposely fail the command + code := c.Run(append([]string{ + "-http-addr=" + a.HTTPAddr(), + }, tc.Flags...)) + require.Equal(0, code, ui.ErrorWriter.String()) + + // Get the configuration watcher + cw, err := c.configWatcher(client) + require.NoError(err) + tc.Test(t, testConfig(t, cw)) + }) + } +} + +func testConfig(t *testing.T, cw proxy.ConfigWatcher) *proxy.Config { + t.Helper() + + select { + case cfg := <-cw.Watch(): + return cfg + + case <-time.After(1 * time.Second): + t.Fatal("no configuration loaded") + return nil // satisfy compiler + } +}