1// Copyright 2016 go-dockerclient authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package docker 6 7import ( 8 "encoding/json" 9 "net/http" 10 "net/url" 11 "reflect" 12 "testing" 13 14 "github.com/docker/docker/api/types/swarm" 15) 16 17func TestListNodes(t *testing.T) { 18 t.Parallel() 19 jsonNodes := `[ 20 { 21 "ID": "24ifsmvkjbyhk", 22 "Version": { 23 "Index": 8 24 }, 25 "CreatedAt": "2016-06-07T20:31:11.853781916Z", 26 "UpdatedAt": "2016-06-07T20:31:11.999868824Z", 27 "Spec": { 28 "Name": "my-node", 29 "Role": "manager", 30 "Availability": "active", 31 "Labels": { 32 "foo": "bar" 33 } 34 }, 35 "Description": { 36 "Hostname": "bf3067039e47", 37 "Platform": { 38 "Architecture": "x86_64", 39 "OS": "linux" 40 }, 41 "Resources": { 42 "NanoCPUs": 4000000000, 43 "MemoryBytes": 8272408576 44 }, 45 "Engine": { 46 "EngineVersion": "1.12.0-dev", 47 "Labels": { 48 "foo": "bar" 49 }, 50 "Plugins": [ 51 { 52 "Type": "Volume", 53 "Name": "local" 54 }, 55 { 56 "Type": "Network", 57 "Name": "bridge" 58 }, 59 { 60 "Type": "Network", 61 "Name": "null" 62 }, 63 { 64 "Type": "Network", 65 "Name": "overlay" 66 } 67 ] 68 } 69 }, 70 "Status": { 71 "State": "ready" 72 }, 73 "ManagerStatus": { 74 "Leader": true, 75 "Reachability": "reachable", 76 "Addr": "172.17.0.2:2377" 77 } 78 } 79]` 80 var expected []swarm.Node 81 err := json.Unmarshal([]byte(jsonNodes), &expected) 82 if err != nil { 83 t.Fatal(err) 84 } 85 client := newTestClient(&FakeRoundTripper{message: jsonNodes, status: http.StatusOK}) 86 nodes, err := client.ListNodes(ListNodesOptions{}) 87 if err != nil { 88 t.Fatal(err) 89 } 90 if !reflect.DeepEqual(nodes, expected) { 91 t.Errorf("ListNodes: Expected %#v. Got %#v.", expected, nodes) 92 } 93 94} 95 96func TestInspectNode(t *testing.T) { 97 t.Parallel() 98 jsonNode := `{ 99 "ID": "24ifsmvkjbyhk", 100 "Version": { 101 "Index": 8 102 }, 103 "CreatedAt": "2016-06-07T20:31:11.853781916Z", 104 "UpdatedAt": "2016-06-07T20:31:11.999868824Z", 105 "Spec": { 106 "Name": "my-node", 107 "Role": "manager", 108 "Availability": "active", 109 "Labels": { 110 "foo": "bar" 111 } 112 }, 113 "Description": { 114 "Hostname": "bf3067039e47", 115 "Platform": { 116 "Architecture": "x86_64", 117 "OS": "linux" 118 }, 119 "Resources": { 120 "NanoCPUs": 4000000000, 121 "MemoryBytes": 8272408576 122 }, 123 "Engine": { 124 "EngineVersion": "1.12.0-dev", 125 "Labels": { 126 "foo": "bar" 127 }, 128 "Plugins": [ 129 { 130 "Type": "Volume", 131 "Name": "local" 132 }, 133 { 134 "Type": "Network", 135 "Name": "bridge" 136 }, 137 { 138 "Type": "Network", 139 "Name": "null" 140 }, 141 { 142 "Type": "Network", 143 "Name": "overlay" 144 } 145 ] 146 } 147 }, 148 "Status": { 149 "State": "ready" 150 }, 151 "ManagerStatus": { 152 "Leader": true, 153 "Reachability": "reachable", 154 "Addr": "172.17.0.2:2377" 155 } 156}` 157 158 var expected swarm.Node 159 err := json.Unmarshal([]byte(jsonNode), &expected) 160 if err != nil { 161 t.Fatal(err) 162 } 163 fakeRT := &FakeRoundTripper{message: jsonNode, status: http.StatusOK} 164 client := newTestClient(fakeRT) 165 id := "24ifsmvkjbyhk" 166 node, err := client.InspectNode(id) 167 if err != nil { 168 t.Fatal(err) 169 } 170 if !reflect.DeepEqual(*node, expected) { 171 t.Errorf("InspectNode(%q): Expected %#v. Got %#v.", id, expected, node) 172 } 173 expectedURL, _ := url.Parse(client.getURL("/nodes/24ifsmvkjbyhk")) 174 if gotPath := fakeRT.requests[0].URL.Path; gotPath != expectedURL.Path { 175 t.Errorf("InspectNode(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath) 176 } 177 178} 179 180func TestInspectNodeNotFound(t *testing.T) { 181 t.Parallel() 182 client := newTestClient(&FakeRoundTripper{message: "no such node", status: http.StatusNotFound}) 183 node, err := client.InspectNode("notfound") 184 if node != nil { 185 t.Errorf("InspectNode: Expected <nil> task, got %#v", node) 186 } 187 expected := &NoSuchNode{ID: "notfound"} 188 if !reflect.DeepEqual(err, expected) { 189 t.Errorf("InspectNode: Wrong error returned. Want %#v. Got %#v.", expected, err) 190 } 191} 192 193func TestUpdateNode(t *testing.T) { 194 t.Parallel() 195 fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK} 196 client := newTestClient(fakeRT) 197 id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2" 198 opts := UpdateNodeOptions{} 199 err := client.UpdateNode(id, opts) 200 if err != nil { 201 t.Fatal(err) 202 } 203 req := fakeRT.requests[0] 204 if req.Method != "POST" { 205 t.Errorf("UpdateNode: wrong HTTP method. Want %q. Got %q.", "POST", req.Method) 206 } 207 expectedURL, _ := url.Parse(client.getURL("/nodes/" + id + "/update")) 208 if gotPath := req.URL.Path; gotPath != expectedURL.Path { 209 t.Errorf("UpdateNode: Wrong path in request. Want %q. Got %q.", expectedURL.Path, gotPath) 210 } 211 expectedContentType := "application/json" 212 if contentType := req.Header.Get("Content-Type"); contentType != expectedContentType { 213 t.Errorf("UpdateNode: Wrong content-type in request. Want %q. Got %q.", expectedContentType, contentType) 214 } 215 var out UpdateNodeOptions 216 if err := json.NewDecoder(req.Body).Decode(&out); err != nil { 217 t.Fatal(err) 218 } 219 if !reflect.DeepEqual(out, opts) { 220 t.Errorf("UpdateNode: wrong body, got: %#v, want %#v", out, opts) 221 } 222} 223 224func TestUpdateNodeNotFound(t *testing.T) { 225 t.Parallel() 226 client := newTestClient(&FakeRoundTripper{message: "no such node", status: http.StatusNotFound}) 227 err := client.UpdateNode("notfound", UpdateNodeOptions{}) 228 expected := &NoSuchNode{ID: "notfound"} 229 if !reflect.DeepEqual(err, expected) { 230 t.Errorf("UpdateNode: Wrong error returned. Want %#v. Got %#v.", expected, err) 231 } 232} 233 234func TestRemoveNode(t *testing.T) { 235 t.Parallel() 236 fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK} 237 client := newTestClient(fakeRT) 238 id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2" 239 err := client.RemoveNode(RemoveNodeOptions{ID: id}) 240 if err != nil { 241 t.Fatal(err) 242 } 243 req := fakeRT.requests[0] 244 if req.Method != "DELETE" { 245 t.Errorf("RemoveNode(%q): wrong HTTP method. Want %q. Got %q.", id, "DELETE", req.Method) 246 } 247 expectedURL, _ := url.Parse(client.getURL("/nodes/" + id)) 248 if gotPath := req.URL.Path; gotPath != expectedURL.Path { 249 t.Errorf("RemoveNode(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath) 250 } 251} 252 253func TestRemoveNodeNotFound(t *testing.T) { 254 t.Parallel() 255 client := newTestClient(&FakeRoundTripper{message: "no such node", status: http.StatusNotFound}) 256 err := client.RemoveNode(RemoveNodeOptions{ID: "notfound"}) 257 expected := &NoSuchNode{ID: "notfound"} 258 if !reflect.DeepEqual(err, expected) { 259 t.Errorf("RemoveNode: Wrong error returned. Want %#v. Got %#v.", expected, err) 260 } 261} 262