1package proxy 2 3import ( 4 "strings" 5 "testing" 6 "time" 7 8 "github.com/hashicorp/consul/agent" 9 "github.com/hashicorp/consul/connect/proxy" 10 "github.com/mitchellh/cli" 11 "github.com/stretchr/testify/require" 12) 13 14func TestCommandConfigWatcher(t *testing.T) { 15 if testing.Short() { 16 t.Skip("too slow for testing.Short") 17 } 18 19 t.Parallel() 20 21 cases := []struct { 22 Name string 23 Flags []string 24 Test func(*testing.T, *proxy.Config) 25 WantErr string 26 }{ 27 { 28 Name: "-service flag only", 29 Flags: []string{"-service", "web"}, 30 Test: func(t *testing.T, cfg *proxy.Config) { 31 require.Equal(t, 0, cfg.PublicListener.BindPort) 32 require.Len(t, cfg.Upstreams, 0) 33 }, 34 }, 35 36 { 37 Name: "-service flag with upstreams", 38 Flags: []string{ 39 "-service", "web", 40 "-upstream", "db:1234", 41 "-upstream", "db2:2345", 42 }, 43 Test: func(t *testing.T, cfg *proxy.Config) { 44 require.Equal(t, 0, cfg.PublicListener.BindPort) 45 require.Len(t, cfg.Upstreams, 2) 46 require.Equal(t, 1234, cfg.Upstreams[0].LocalBindPort) 47 require.Equal(t, 2345, cfg.Upstreams[1].LocalBindPort) 48 }, 49 }, 50 51 { 52 Name: "-service flag with -service-addr", 53 Flags: []string{"-service", "web"}, 54 Test: func(t *testing.T, cfg *proxy.Config) { 55 // -service-addr has no affect since -listen isn't set 56 require.Equal(t, 0, cfg.PublicListener.BindPort) 57 require.Len(t, cfg.Upstreams, 0) 58 }, 59 }, 60 61 { 62 Name: "-service, -service-addr, -listen", 63 Flags: []string{ 64 "-service", "web", 65 "-service-addr", "127.0.0.1:1234", 66 "-listen", ":4567", 67 }, 68 Test: func(t *testing.T, cfg *proxy.Config) { 69 require.Len(t, cfg.Upstreams, 0) 70 71 require.Equal(t, "", cfg.PublicListener.BindAddress) 72 require.Equal(t, 4567, cfg.PublicListener.BindPort) 73 require.Equal(t, "127.0.0.1:1234", cfg.PublicListener.LocalServiceAddress) 74 }, 75 }, 76 77 { 78 Name: "-sidecar-for, no sidecar", 79 Flags: []string{ 80 "-sidecar-for", "no-sidecar", 81 }, 82 WantErr: "No sidecar proxy registered", 83 }, 84 85 { 86 Name: "-sidecar-for, multiple sidecars", 87 Flags: []string{ 88 "-sidecar-for", "two-sidecars", 89 }, 90 // Order is non-deterministic so don't assert the list of proxy IDs here 91 WantErr: `More than one sidecar proxy registered for two-sidecars. 92 Start proxy with -proxy-id and one of the following IDs: `, 93 }, 94 95 { 96 Name: "-sidecar-for, non-existent", 97 Flags: []string{ 98 "-sidecar-for", "foo", 99 }, 100 WantErr: "No sidecar proxy registered", 101 }, 102 103 { 104 Name: "-sidecar-for, one sidecar", 105 Flags: []string{ 106 "-sidecar-for", "one-sidecar", 107 }, 108 Test: func(t *testing.T, cfg *proxy.Config) { 109 // Sanity check we got the right instance. 110 require.Equal(t, 9999, cfg.PublicListener.BindPort) 111 }, 112 }, 113 } 114 115 for _, tc := range cases { 116 t.Run(tc.Name, func(t *testing.T) { 117 require := require.New(t) 118 119 // Register a few services with 0, 1 and 2 sidecars 120 a := agent.NewTestAgent(t, ` 121 services { 122 name = "no-sidecar" 123 port = 1111 124 } 125 services { 126 name = "one-sidecar" 127 port = 2222 128 connect { 129 sidecar_service { 130 port = 9999 131 } 132 } 133 } 134 services { 135 name = "two-sidecars" 136 port = 3333 137 connect { 138 sidecar_service {} 139 } 140 } 141 services { 142 kind = "connect-proxy" 143 name = "other-sidecar-for-two-sidecars" 144 port = 4444 145 proxy { 146 destination_service_id = "two-sidecars" 147 destination_service_name = "two-sidecars" 148 } 149 } 150 `) 151 defer a.Shutdown() 152 client := a.Client() 153 154 ui := cli.NewMockUi() 155 c := New(ui, make(chan struct{})) 156 c.testNoStart = true 157 158 // Run the command 159 code := c.Run(append([]string{ 160 "-http-addr=" + a.HTTPAddr(), 161 }, tc.Flags...)) 162 if tc.WantErr == "" { 163 require.Equal(0, code, ui.ErrorWriter.String()) 164 } else { 165 require.Equal(1, code, ui.ErrorWriter.String()) 166 require.Contains(ui.ErrorWriter.String(), tc.WantErr) 167 return 168 } 169 170 // Get the configuration watcher 171 cw, err := c.configWatcher(client) 172 require.NoError(err) 173 if tc.Test != nil { 174 tc.Test(t, testConfig(t, cw)) 175 } 176 }) 177 } 178} 179 180func testConfig(t *testing.T, cw proxy.ConfigWatcher) *proxy.Config { 181 t.Helper() 182 183 select { 184 case cfg := <-cw.Watch(): 185 return cfg 186 187 case <-time.After(1 * time.Second): 188 t.Fatal("no configuration loaded") 189 return nil // satisfy compiler 190 } 191} 192 193func TestCatalogCommand_noTabs(t *testing.T) { 194 t.Parallel() 195 if strings.ContainsRune(New(nil, nil).Help(), '\t') { 196 t.Fatal("help has tabs") 197 } 198} 199