1// 2// Copyright (c) 2018, Joyent, Inc. All rights reserved. 3// 4// This Source Code Form is subject to the terms of the Mozilla Public 5// License, v. 2.0. If a copy of the MPL was not distributed with this 6// file, You can obtain one at http://mozilla.org/MPL/2.0/. 7// 8 9package network_test 10 11import ( 12 "context" 13 "fmt" 14 "io/ioutil" 15 "net/http" 16 "path" 17 "strings" 18 "testing" 19 20 triton "github.com/joyent/triton-go" 21 "github.com/joyent/triton-go/network" 22 "github.com/joyent/triton-go/testutils" 23 "github.com/pkg/errors" 24) 25 26var ( 27 fakeNetworkID = "daeb93a2-532e-4bd4-8788-b6b30f10ac17" 28 getNetworkErrorType = errors.New("unable to get network") 29 listNetworkErrorType = errors.New("unable to list networks") 30) 31 32// Note that this is specific to Joyent Public Cloud and will not pass on 33// private installations of Triton. 34func TestAccNetworks_List(t *testing.T) { 35 testutils.AccTest(t, testutils.TestCase{ 36 Steps: []testutils.Step{ 37 38 &testutils.StepClient{ 39 StateBagKey: "datacenter", 40 CallFunc: func(config *triton.ClientConfig) (interface{}, error) { 41 return network.NewClient(config) 42 }, 43 }, 44 45 &testutils.StepAPICall{ 46 StateBagKey: "networks", 47 CallFunc: func(client interface{}) (interface{}, error) { 48 ctx := context.Background() 49 input := &network.ListInput{} 50 if c, ok := client.(*network.NetworkClient); ok { 51 return c.List(ctx, input) 52 } 53 return nil, fmt.Errorf("Bad client initialization") 54 }, 55 }, 56 57 &testutils.StepAssertFunc{ 58 AssertFunc: func(state testutils.TritonStateBag) error { 59 dcs, ok := state.GetOk("networks") 60 if !ok { 61 return fmt.Errorf("State key %q not found", "networks") 62 } 63 64 toFind := []string{"Joyent-SDC-Private", "Joyent-SDC-Public"} 65 for _, dcName := range toFind { 66 found := false 67 for _, dc := range dcs.([]*network.Network) { 68 if dc.Name == dcName { 69 found = true 70 if dc.Id == "" { 71 return fmt.Errorf("%q has no ID", dc.Name) 72 } 73 } 74 } 75 if !found { 76 return fmt.Errorf("Did not find Network %q", dcName) 77 } 78 } 79 80 return nil 81 }, 82 }, 83 }, 84 }) 85} 86 87func TestListNetworks(t *testing.T) { 88 networkClient := MockNetworkClient() 89 90 do := func(ctx context.Context, nc *network.NetworkClient) ([]*network.Network, error) { 91 defer testutils.DeactivateClient() 92 93 networks, err := nc.List(ctx, &network.ListInput{}) 94 if err != nil { 95 return nil, err 96 } 97 return networks, nil 98 } 99 100 t.Run("successful", func(t *testing.T) { 101 testutils.RegisterResponder("GET", path.Join("/", accountURL, "networks"), listNetworksSuccess) 102 103 resp, err := do(context.Background(), networkClient) 104 if err != nil { 105 t.Fatal(err) 106 } 107 108 if resp == nil { 109 t.Fatalf("Expected an output but got nil") 110 } 111 }) 112 113 t.Run("eof", func(t *testing.T) { 114 testutils.RegisterResponder("GET", path.Join("/", accountURL, "networks"), listNetworksEmpty) 115 116 _, err := do(context.Background(), networkClient) 117 if err == nil { 118 t.Fatal(err) 119 } 120 121 if !strings.Contains(err.Error(), "EOF") { 122 t.Errorf("expected error to contain EOF: found %v", err) 123 } 124 }) 125 126 t.Run("bad_decode", func(t *testing.T) { 127 testutils.RegisterResponder("GET", path.Join("/", accountURL, "networks"), listNetworksBadeDecode) 128 129 _, err := do(context.Background(), networkClient) 130 if err == nil { 131 t.Fatal(err) 132 } 133 134 if !strings.Contains(err.Error(), "invalid character") { 135 t.Errorf("expected decode to fail: found %v", err) 136 } 137 }) 138 139 t.Run("error", func(t *testing.T) { 140 testutils.RegisterResponder("GET", path.Join("/", accountURL, "networks"), listNetworksError) 141 142 resp, err := do(context.Background(), networkClient) 143 if err == nil { 144 t.Fatal(err) 145 } 146 if resp != nil { 147 t.Error("expected resp to be nil") 148 } 149 150 if !strings.Contains(err.Error(), "unable to list networks") { 151 t.Errorf("expected error to equal testError: found %v", err) 152 } 153 }) 154} 155 156func TestGetNetwork(t *testing.T) { 157 networkClient := MockNetworkClient() 158 159 do := func(ctx context.Context, nc *network.NetworkClient) (*network.Network, error) { 160 defer testutils.DeactivateClient() 161 162 network, err := nc.Get(ctx, &network.GetInput{ 163 ID: fakeNetworkID, 164 }) 165 if err != nil { 166 return nil, err 167 } 168 return network, nil 169 } 170 171 t.Run("successful", func(t *testing.T) { 172 testutils.RegisterResponder("GET", path.Join("/", accountURL, "networks", fakeNetworkID), getNetworkSuccess) 173 174 resp, err := do(context.Background(), networkClient) 175 if err != nil { 176 t.Fatal(err) 177 } 178 179 if resp == nil { 180 t.Fatalf("Expected an output but got nil") 181 } 182 }) 183 184 t.Run("eof", func(t *testing.T) { 185 testutils.RegisterResponder("GET", path.Join("/", accountURL, "networks", fakeNetworkID), getNetworkEmpty) 186 187 _, err := do(context.Background(), networkClient) 188 if err == nil { 189 t.Fatal(err) 190 } 191 192 if !strings.Contains(err.Error(), "EOF") { 193 t.Errorf("expected error to contain EOF: found %v", err) 194 } 195 }) 196 197 t.Run("bad_decode", func(t *testing.T) { 198 testutils.RegisterResponder("GET", path.Join("/", accountURL, "networks", fakeNetworkID), getNetworkBadeDecode) 199 200 _, err := do(context.Background(), networkClient) 201 if err == nil { 202 t.Fatal(err) 203 } 204 205 if !strings.Contains(err.Error(), "invalid character") { 206 t.Errorf("expected decode to fail: found %v", err) 207 } 208 }) 209 210 t.Run("error", func(t *testing.T) { 211 testutils.RegisterResponder("GET", path.Join("/", accountURL, "networks"), getNetworkError) 212 213 resp, err := do(context.Background(), networkClient) 214 if err == nil { 215 t.Fatal(err) 216 } 217 if resp != nil { 218 t.Error("expected resp to be nil") 219 } 220 221 if !strings.Contains(err.Error(), "unable to get network") { 222 t.Errorf("expected error to equal testError: found %v", err) 223 } 224 }) 225} 226 227func getNetworkSuccess(req *http.Request) (*http.Response, error) { 228 header := http.Header{} 229 header.Add("Content-Type", "application/json") 230 231 body := strings.NewReader(`{ 232 "id": "daeb93a2-532e-4bd4-8788-b6b30f10ac17", 233 "name": "external", 234 "public": true 235} 236`) 237 return &http.Response{ 238 StatusCode: http.StatusOK, 239 Header: header, 240 Body: ioutil.NopCloser(body), 241 }, nil 242} 243 244func getNetworkError(req *http.Request) (*http.Response, error) { 245 return nil, getNetworkErrorType 246} 247 248func getNetworkBadeDecode(req *http.Request) (*http.Response, error) { 249 header := http.Header{} 250 header.Add("Content-Type", "application/json") 251 252 body := strings.NewReader(`{ 253 "id": "daeb93a2-532e-4bd4-8788-b6b30f10ac17", 254 "name": "external", 255 "public": true, 256}`) 257 return &http.Response{ 258 StatusCode: http.StatusOK, 259 Header: header, 260 Body: ioutil.NopCloser(body), 261 }, nil 262} 263 264func getNetworkEmpty(req *http.Request) (*http.Response, error) { 265 header := http.Header{} 266 header.Add("Content-Type", "application/json") 267 return &http.Response{ 268 StatusCode: http.StatusOK, 269 Header: header, 270 Body: ioutil.NopCloser(strings.NewReader("")), 271 }, nil 272} 273 274func listNetworksEmpty(req *http.Request) (*http.Response, error) { 275 header := http.Header{} 276 header.Add("Content-Type", "application/json") 277 return &http.Response{ 278 StatusCode: http.StatusOK, 279 Header: header, 280 Body: ioutil.NopCloser(strings.NewReader("")), 281 }, nil 282} 283 284func listNetworksSuccess(req *http.Request) (*http.Response, error) { 285 header := http.Header{} 286 header.Add("Content-Type", "application/json") 287 288 body := strings.NewReader(`[ 289 { 290 "id": "daeb93a2-532e-4bd4-8788-b6b30f10ac17", 291 "name": "external", 292 "public": true 293 } 294]`) 295 return &http.Response{ 296 StatusCode: http.StatusOK, 297 Header: header, 298 Body: ioutil.NopCloser(body), 299 }, nil 300} 301 302func listNetworksBadeDecode(req *http.Request) (*http.Response, error) { 303 header := http.Header{} 304 header.Add("Content-Type", "application/json") 305 306 body := strings.NewReader(`{[ 307 { 308 "id": "daeb93a2-532e-4bd4-8788-b6b30f10ac17", 309 "name": "external", 310 "public": true 311 } 312]}`) 313 return &http.Response{ 314 StatusCode: http.StatusOK, 315 Header: header, 316 Body: ioutil.NopCloser(body), 317 }, nil 318} 319 320func listNetworksError(req *http.Request) (*http.Response, error) { 321 return nil, listNetworkErrorType 322} 323