1package hcloud 2 3import ( 4 "encoding/json" 5 "testing" 6 "time" 7 8 "github.com/google/go-cmp/cmp" 9 10 "github.com/hetznercloud/hcloud-go/hcloud/schema" 11) 12 13func TestActionFromSchema(t *testing.T) { 14 data := []byte(`{ 15 "id": 1, 16 "command": "create_server", 17 "status": "success", 18 "progress": 100, 19 "started": "2016-01-30T23:55:00Z", 20 "finished": "2016-01-30T23:56:13Z", 21 "resources": [ 22 { 23 "id": 42, 24 "type": "server" 25 } 26 ], 27 "error": { 28 "code": "action_failed", 29 "message": "Action failed" 30 } 31 }`) 32 33 var s schema.Action 34 if err := json.Unmarshal(data, &s); err != nil { 35 t.Fatal(err) 36 } 37 action := ActionFromSchema(s) 38 39 if action.ID != 1 { 40 t.Errorf("unexpected ID: %v", action.ID) 41 } 42 if action.Command != "create_server" { 43 t.Errorf("unexpected command: %v", action.Command) 44 } 45 if action.Status != "success" { 46 t.Errorf("unexpected status: %v", action.Status) 47 } 48 if action.Progress != 100 { 49 t.Errorf("unexpected progress: %d", action.Progress) 50 } 51 if !action.Started.Equal(time.Date(2016, 1, 30, 23, 55, 0, 0, time.UTC)) { 52 t.Errorf("unexpected started: %v", action.Started) 53 } 54 if !action.Finished.Equal(time.Date(2016, 1, 30, 23, 56, 13, 0, time.UTC)) { 55 t.Errorf("unexpected finished: %v", action.Started) 56 } 57 if action.ErrorCode != "action_failed" { 58 t.Errorf("unexpected error code: %v", action.ErrorCode) 59 } 60 if action.ErrorMessage != "Action failed" { 61 t.Errorf("unexpected error message: %v", action.ErrorMessage) 62 } 63 if len(action.Resources) == 1 { 64 if action.Resources[0].ID != 42 { 65 t.Errorf("unexpected id in resources[0].ID: %v", action.Resources[0].ID) 66 } 67 if action.Resources[0].Type != ActionResourceTypeServer { 68 t.Errorf("unexpected type in resources[0].Type: %v", action.Resources[0].Type) 69 } 70 } else { 71 t.Errorf("unexpected number of resources") 72 } 73} 74 75func TestActionsFromSchema(t *testing.T) { 76 data := []byte(`[ 77 { 78 "id": 13, 79 "command": "create_server" 80 }, 81 { 82 "id": 14, 83 "command": "start_server" 84 } 85 ]`) 86 var s []schema.Action 87 if err := json.Unmarshal(data, &s); err != nil { 88 t.Fatal(err) 89 } 90 actions := ActionsFromSchema(s) 91 if len(actions) != 2 || actions[0].ID != 13 || actions[1].ID != 14 { 92 t.Fatal("unexpected actions") 93 } 94} 95 96func TestFloatingIPFromSchema(t *testing.T) { 97 t.Run("IPv6", func(t *testing.T) { 98 data := []byte(`{ 99 "id": 4711, 100 "name": "Web Frontend", 101 "description": "Web Frontend", 102 "created":"2017-08-16T17:29:14+00:00", 103 "ip": "2001:db8::/64", 104 "type": "ipv6", 105 "server": null, 106 "dns_ptr": [], 107 "blocked": true, 108 "home_location": { 109 "id": 1, 110 "name": "fsn1", 111 "description": "Falkenstein DC Park 1", 112 "country": "DE", 113 "city": "Falkenstein", 114 "latitude": 50.47612, 115 "longitude": 12.370071, 116 "network_zone": "eu-central" 117 }, 118 "protection": { 119 "delete": true 120 }, 121 "labels": { 122 "key": "value", 123 "key2": "value2" 124 } 125 }`) 126 127 var s schema.FloatingIP 128 if err := json.Unmarshal(data, &s); err != nil { 129 t.Fatal(err) 130 } 131 floatingIP := FloatingIPFromSchema(s) 132 133 if floatingIP.ID != 4711 { 134 t.Errorf("unexpected ID: %v", floatingIP.ID) 135 } 136 if !floatingIP.Blocked { 137 t.Errorf("unexpected value for Blocked: %v", floatingIP.Blocked) 138 } 139 if floatingIP.Name != "Web Frontend" { 140 t.Errorf("unexpected name: %v", floatingIP.Name) 141 } 142 if floatingIP.Description != "Web Frontend" { 143 t.Errorf("unexpected description: %v", floatingIP.Description) 144 } 145 if floatingIP.IP.String() != "2001:db8::" { 146 t.Errorf("unexpected IP: %v", floatingIP.IP) 147 } 148 if floatingIP.Type != FloatingIPTypeIPv6 { 149 t.Errorf("unexpected Type: %v", floatingIP.Type) 150 } 151 if floatingIP.Server != nil { 152 t.Errorf("unexpected Server: %v", floatingIP.Server) 153 } 154 if floatingIP.DNSPtr == nil || floatingIP.DNSPtrForIP(floatingIP.IP) != "" { 155 t.Errorf("unexpected DNS ptr: %v", floatingIP.DNSPtr) 156 } 157 if floatingIP.HomeLocation == nil || floatingIP.HomeLocation.ID != 1 { 158 t.Errorf("unexpected home location: %v", floatingIP.HomeLocation) 159 } 160 if !floatingIP.Protection.Delete { 161 t.Errorf("unexpected Protection.Delete: %v", floatingIP.Protection.Delete) 162 } 163 if floatingIP.Labels["key"] != "value" || floatingIP.Labels["key2"] != "value2" { 164 t.Errorf("unexpected Labels: %v", floatingIP.Labels) 165 } 166 if !floatingIP.Created.Equal(time.Date(2017, 8, 16, 17, 29, 14, 0, time.UTC)) { 167 t.Errorf("unexpected created date: %v", floatingIP.Created) 168 } 169 }) 170 171 t.Run("IPv4", func(t *testing.T) { 172 data := []byte(`{ 173 "id": 4711, 174 "description": "Web Frontend", 175 "ip": "131.232.99.1", 176 "type": "ipv4", 177 "server": 42, 178 "dns_ptr": [{ 179 "ip": "131.232.99.1", 180 "dns_ptr": "fip01.example.com" 181 }], 182 "blocked": false, 183 "home_location": { 184 "id": 1, 185 "name": "fsn1", 186 "description": "Falkenstein DC Park 1", 187 "country": "DE", 188 "city": "Falkenstein", 189 "latitude": 50.47612, 190 "longitude": 12.370071 191 } 192 }`) 193 194 var s schema.FloatingIP 195 if err := json.Unmarshal(data, &s); err != nil { 196 t.Fatal(err) 197 } 198 floatingIP := FloatingIPFromSchema(s) 199 200 if floatingIP.ID != 4711 { 201 t.Errorf("unexpected ID: %v", floatingIP.ID) 202 } 203 if floatingIP.Blocked { 204 t.Errorf("unexpected value for Blocked: %v", floatingIP.Blocked) 205 } 206 if floatingIP.Description != "Web Frontend" { 207 t.Errorf("unexpected description: %v", floatingIP.Description) 208 } 209 if floatingIP.IP.String() != "131.232.99.1" { 210 t.Errorf("unexpected IP: %v", floatingIP.IP) 211 } 212 if floatingIP.Type != FloatingIPTypeIPv4 { 213 t.Errorf("unexpected type: %v", floatingIP.Type) 214 } 215 if floatingIP.Server == nil || floatingIP.Server.ID != 42 { 216 t.Errorf("unexpected server: %v", floatingIP.Server) 217 } 218 if floatingIP.DNSPtr == nil || floatingIP.DNSPtrForIP(floatingIP.IP) != "fip01.example.com" { 219 t.Errorf("unexpected DNS ptr: %v", floatingIP.DNSPtr) 220 } 221 if floatingIP.HomeLocation == nil || floatingIP.HomeLocation.ID != 1 { 222 t.Errorf("unexpected home location: %v", floatingIP.HomeLocation) 223 } 224 }) 225} 226 227func TestISOFromSchema(t *testing.T) { 228 data := []byte(`{ 229 "id": 4711, 230 "name": "FreeBSD-11.0-RELEASE-amd64-dvd1", 231 "description": "FreeBSD 11.0 x64", 232 "type": "public", 233 "deprecated": "2018-02-28T00:00:00+00:00" 234 }`) 235 236 var s schema.ISO 237 if err := json.Unmarshal(data, &s); err != nil { 238 t.Fatal(err) 239 } 240 iso := ISOFromSchema(s) 241 if iso.ID != 4711 { 242 t.Errorf("unexpected ID: %v", iso.ID) 243 } 244 if iso.Name != "FreeBSD-11.0-RELEASE-amd64-dvd1" { 245 t.Errorf("unexpected name: %v", iso.Name) 246 } 247 if iso.Description != "FreeBSD 11.0 x64" { 248 t.Errorf("unexpected description: %v", iso.Description) 249 } 250 if iso.Type != ISOTypePublic { 251 t.Errorf("unexpected type: %v", iso.Type) 252 } 253 if iso.Deprecated.IsZero() { 254 t.Errorf("unexpected value for deprecated: %v", iso.Deprecated) 255 } 256} 257 258func TestDatacenterFromSchema(t *testing.T) { 259 data := []byte(`{ 260 "id": 1, 261 "name": "fsn1-dc8", 262 "description": "Falkenstein 1 DC 8", 263 "location": { 264 "id": 1, 265 "name": "fsn1", 266 "description": "Falkenstein DC Park 1", 267 "country": "DE", 268 "city": "Falkenstein", 269 "latitude": 50.47612, 270 "longitude": 12.370071, 271 "network_zone": "eu-central" 272 }, 273 "server_types": { 274 "supported": [ 275 1, 276 1, 277 2, 278 3 279 ], 280 "available": [ 281 1, 282 1, 283 2, 284 3 285 ] 286 } 287 }`) 288 289 var s schema.Datacenter 290 if err := json.Unmarshal(data, &s); err != nil { 291 t.Fatal(err) 292 } 293 datacenter := DatacenterFromSchema(s) 294 if datacenter.ID != 1 { 295 t.Errorf("unexpected ID: %v", datacenter.ID) 296 } 297 if datacenter.Name != "fsn1-dc8" { 298 t.Errorf("unexpected Name: %v", datacenter.Name) 299 } 300 if datacenter.Location == nil || datacenter.Location.ID != 1 { 301 t.Errorf("unexpected Location: %v", datacenter.Location) 302 } 303 if len(datacenter.ServerTypes.Available) != 4 { 304 t.Errorf("unexpected ServerTypes.Available (should be 4): %v", len(datacenter.ServerTypes.Available)) 305 } 306 if len(datacenter.ServerTypes.Supported) != 4 { 307 t.Errorf("unexpected ServerTypes.Supported length (should be 4): %v", len(datacenter.ServerTypes.Supported)) 308 } 309} 310 311func TestLocationFromSchema(t *testing.T) { 312 data := []byte(`{ 313 "id": 1, 314 "name": "fsn1", 315 "description": "Falkenstein DC Park 1", 316 "country": "DE", 317 "city": "Falkenstein", 318 "latitude": 50.47612, 319 "longitude": 12.370071, 320 "network_zone": "eu-central" 321 }`) 322 323 var s schema.Location 324 if err := json.Unmarshal(data, &s); err != nil { 325 t.Fatal(err) 326 } 327 location := LocationFromSchema(s) 328 if location.ID != 1 { 329 t.Errorf("unexpected ID: %v", location.ID) 330 } 331 if location.Name != "fsn1" { 332 t.Errorf("unexpected Name: %v", location.Name) 333 } 334 if location.Description != "Falkenstein DC Park 1" { 335 t.Errorf("unexpected Description: %v", location.Description) 336 } 337 if location.Country != "DE" { 338 t.Errorf("unexpected Country: %v", location.Country) 339 } 340 if location.City != "Falkenstein" { 341 t.Errorf("unexpected City: %v", location.City) 342 } 343 if location.Latitude != 50.47612 { 344 t.Errorf("unexpected Latitude: %v", location.Latitude) 345 } 346 if location.Longitude != 12.370071 { 347 t.Errorf("unexpected Longitude: %v", location.Longitude) 348 } 349 if location.NetworkZone != "eu-central" { 350 t.Errorf("unexpected NetworkZone: %v", location.NetworkZone) 351 } 352} 353 354func TestServerFromSchema(t *testing.T) { 355 data := []byte(`{ 356 "id": 1, 357 "name": "server.example.com", 358 "status": "running", 359 "created": "2017-08-16T17:29:14+00:00", 360 "public_net": { 361 "ipv4": { 362 "ip": "1.2.3.4", 363 "blocked": false, 364 "dns_ptr": "server01.example.com" 365 }, 366 "ipv6": { 367 "ip": "2a01:4f8:1c11:3400::/64", 368 "blocked": false, 369 "dns_ptr": [ 370 { 371 "ip": "2a01:4f8:1c11:3400::1/64", 372 "dns_ptr": "server01.example.com" 373 } 374 ] 375 } 376 }, 377 "private_net": [ 378 { 379 "network": 4711, 380 "ip": "10.0.1.1", 381 "aliases": [ 382 "10.0.1.2" 383 ] 384 } 385 ], 386 "server_type": { 387 "id": 2 388 }, 389 "outgoing_traffic": 123456, 390 "ingoing_traffic": 7891011, 391 "included_traffic": 654321, 392 "backup_window": "22-02", 393 "rescue_enabled": true, 394 "primary_disk_size": 20, 395 "image": { 396 "id": 4711, 397 "type": "system", 398 "status": "available", 399 "name": "ubuntu16.04-standard-x64", 400 "description": "Ubuntu 16.04 Standard 64 bit", 401 "image_size": 2.3, 402 "disk_size": 10, 403 "created": "2017-08-16T17:29:14+00:00", 404 "created_from": { 405 "id": 1, 406 "name": "Server" 407 }, 408 "bound_to": 1, 409 "os_flavor": "ubuntu", 410 "os_version": "16.04", 411 "rapid_deploy": false 412 }, 413 "iso": { 414 "id": 4711, 415 "name": "FreeBSD-11.0-RELEASE-amd64-dvd1", 416 "description": "FreeBSD 11.0 x64", 417 "type": "public" 418 }, 419 "datacenter": { 420 "id": 1, 421 "name": "fsn1-dc8", 422 "description": "Falkenstein 1 DC 8", 423 "location": { 424 "id": 1, 425 "name": "fsn1", 426 "description": "Falkenstein DC Park 1", 427 "country": "DE", 428 "city": "Falkenstein", 429 "latitude": 50.47612, 430 "longitude": 12.370071, 431 "network_zone": "eu-central" 432 } 433 }, 434 "protection": { 435 "delete": true, 436 "rebuild": true 437 }, 438 "locked": true, 439 "labels": { 440 "key": "value", 441 "key2": "value2" 442 }, 443 "volumes": [123, 456, 789] 444 }`) 445 446 var s schema.Server 447 if err := json.Unmarshal(data, &s); err != nil { 448 t.Fatal(err) 449 } 450 server := ServerFromSchema(s) 451 452 if server.ID != 1 { 453 t.Errorf("unexpected ID: %v", server.ID) 454 } 455 if server.Name != "server.example.com" { 456 t.Errorf("unexpected name: %v", server.Name) 457 } 458 if server.Status != ServerStatusRunning { 459 t.Errorf("unexpected status: %v", server.Status) 460 } 461 if !server.Created.Equal(time.Date(2017, 8, 16, 17, 29, 14, 0, time.UTC)) { 462 t.Errorf("unexpected created date: %v", server.Created) 463 } 464 if server.PublicNet.IPv4.IP.String() != "1.2.3.4" { 465 t.Errorf("unexpected public net IPv4 IP: %v", server.PublicNet.IPv4.IP) 466 } 467 if server.ServerType.ID != 2 { 468 t.Errorf("unexpected server type ID: %v", server.ServerType.ID) 469 } 470 if server.IncludedTraffic != 654321 { 471 t.Errorf("unexpected included traffic: %v", server.IncludedTraffic) 472 } 473 if server.OutgoingTraffic != 123456 { 474 t.Errorf("unexpected outgoing traffic: %v", server.OutgoingTraffic) 475 } 476 if server.IngoingTraffic != 7891011 { 477 t.Errorf("unexpected ingoing traffic: %v", server.IngoingTraffic) 478 } 479 if server.BackupWindow != "22-02" { 480 t.Errorf("unexpected backup window: %v", server.BackupWindow) 481 } 482 if server.PrimaryDiskSize != 20 { 483 t.Errorf("unexpected primary disk size: %v", server.PrimaryDiskSize) 484 } 485 if !server.RescueEnabled { 486 t.Errorf("unexpected rescue enabled state: %v", server.RescueEnabled) 487 } 488 if server.Image == nil || server.Image.ID != 4711 { 489 t.Errorf("unexpected Image: %v", server.Image) 490 } 491 if server.ISO == nil || server.ISO.ID != 4711 { 492 t.Errorf("unexpected ISO: %v", server.ISO) 493 } 494 if server.Datacenter == nil || server.Datacenter.ID != 1 { 495 t.Errorf("unexpected Datacenter: %v", server.Datacenter) 496 } 497 if !server.Locked { 498 t.Errorf("unexpected value for Locked: %v", server.Locked) 499 } 500 if !server.Protection.Delete { 501 t.Errorf("unexpected value for Protection.Delete: %v", server.Protection.Delete) 502 } 503 if !server.Protection.Rebuild { 504 t.Errorf("unexpected value for Protection.Rebuild: %v", server.Protection.Rebuild) 505 } 506 if server.Labels["key"] != "value" || server.Labels["key2"] != "value2" { 507 t.Errorf("unexpected Labels: %v", server.Labels) 508 } 509 if len(s.Volumes) != 3 { 510 t.Errorf("unexpected number of volumes: %v", len(s.Volumes)) 511 } 512 if s.Volumes[0] != 123 || s.Volumes[1] != 456 || s.Volumes[2] != 789 { 513 t.Errorf("unexpected volumes: %v", s.Volumes) 514 } 515 if len(server.PrivateNet) != 1 { 516 t.Errorf("unexpected length of PrivateNet: %v", len(server.PrivateNet)) 517 } 518 if server.PrivateNet[0].Network.ID != 4711 { 519 t.Errorf("unexpected first private net: %v", server.PrivateNet[0]) 520 } 521} 522 523func TestServerFromSchemaNoTraffic(t *testing.T) { 524 data := []byte(`{ 525 "public_net": { 526 "ipv4": { 527 "ip": "1.2.3.4", 528 "blocked": false, 529 "dns_ptr": "server01.example.com" 530 }, 531 "ipv6": { 532 "ip": "2a01:4f8:1c11:3400::/64", 533 "blocked": false, 534 "dns_ptr": [ 535 { 536 "ip": "2a01:4f8:1c11:3400::1/64", 537 "dns_ptr": "server01.example.com" 538 } 539 ] 540 } 541 }, 542 "outgoing_traffic": null, 543 "ingoing_traffic": null 544 }`) 545 546 var s schema.Server 547 if err := json.Unmarshal(data, &s); err != nil { 548 t.Fatal(err) 549 } 550 server := ServerFromSchema(s) 551 552 if server.OutgoingTraffic != 0 { 553 t.Errorf("unexpected outgoing traffic: %v", server.OutgoingTraffic) 554 } 555 if server.IngoingTraffic != 0 { 556 t.Errorf("unexpected ingoing traffic: %v", server.IngoingTraffic) 557 } 558} 559 560func TestServerPublicNetFromSchema(t *testing.T) { 561 data := []byte(`{ 562 "ipv4": { 563 "ip": "1.2.3.4", 564 "blocked": false, 565 "dns_ptr": "server.example.com" 566 }, 567 "ipv6": { 568 "ip": "2a01:4f8:1c19:1403::/64", 569 "blocked": false, 570 "dns_ptr": [] 571 }, 572 "floating_ips": [4], 573 "firewalls": [ 574 { 575 "id": 23, 576 "status": "applied" 577 } 578 ] 579 }`) 580 581 var s schema.ServerPublicNet 582 if err := json.Unmarshal(data, &s); err != nil { 583 t.Fatal(err) 584 } 585 publicNet := ServerPublicNetFromSchema(s) 586 587 if publicNet.IPv4.IP.String() != "1.2.3.4" { 588 t.Errorf("unexpected IPv4 IP: %v", publicNet.IPv4.IP) 589 } 590 if publicNet.IPv6.Network.String() != "2a01:4f8:1c19:1403::/64" { 591 t.Errorf("unexpected IPv6 IP: %v", publicNet.IPv6.IP) 592 } 593 if len(publicNet.FloatingIPs) != 1 || publicNet.FloatingIPs[0].ID != 4 { 594 t.Errorf("unexpected Floating IPs: %v", publicNet.FloatingIPs) 595 } 596 if len(publicNet.Firewalls) != 1 || publicNet.Firewalls[0].Firewall.ID != 23 || publicNet.Firewalls[0].Status != FirewallStatusApplied { 597 t.Errorf("unexpected Firewalls: %v", publicNet.Firewalls) 598 } 599} 600 601func TestServerPublicNetIPv4FromSchema(t *testing.T) { 602 data := []byte(`{ 603 "ip": "1.2.3.4", 604 "blocked": true, 605 "dns_ptr": "server.example.com" 606 }`) 607 608 var s schema.ServerPublicNetIPv4 609 if err := json.Unmarshal(data, &s); err != nil { 610 t.Fatal(err) 611 } 612 ipv4 := ServerPublicNetIPv4FromSchema(s) 613 614 if ipv4.IP.String() != "1.2.3.4" { 615 t.Errorf("unexpected IP: %v", ipv4.IP) 616 } 617 if !ipv4.Blocked { 618 t.Errorf("unexpected blocked state: %v", ipv4.Blocked) 619 } 620 if ipv4.DNSPtr != "server.example.com" { 621 t.Errorf("unexpected DNS ptr: %v", ipv4.DNSPtr) 622 } 623} 624 625func TestServerPublicNetIPv6FromSchema(t *testing.T) { 626 data := []byte(`{ 627 "ip": "2a01:4f8:1c11:3400::/64", 628 "blocked": true, 629 "dns_ptr": [ 630 { 631 "ip": "2a01:4f8:1c11:3400::1/64", 632 "blocked": "server01.example.com" 633 } 634 ] 635 }`) 636 637 var s schema.ServerPublicNetIPv6 638 if err := json.Unmarshal(data, &s); err != nil { 639 t.Fatal(err) 640 } 641 ipv6 := ServerPublicNetIPv6FromSchema(s) 642 643 if ipv6.Network.String() != "2a01:4f8:1c11:3400::/64" { 644 t.Errorf("unexpected IP: %v", ipv6.IP) 645 } 646 if !ipv6.Blocked { 647 t.Errorf("unexpected blocked state: %v", ipv6.Blocked) 648 } 649 if len(ipv6.DNSPtr) != 1 { 650 t.Errorf("unexpected DNS ptr: %v", ipv6.DNSPtr) 651 } 652} 653 654func TestServerPrivateNetFromSchema(t *testing.T) { 655 data := []byte(`{ 656 "network": 4711, 657 "ip": "10.0.1.1", 658 "alias_ips": [ 659 "10.0.1.2" 660 ], 661 "mac_address": "86:00:ff:2a:7d:e1" 662 }`) 663 664 var s schema.ServerPrivateNet 665 if err := json.Unmarshal(data, &s); err != nil { 666 t.Fatal(err) 667 } 668 privateNet := ServerPrivateNetFromSchema(s) 669 670 if privateNet.Network.ID != 4711 { 671 t.Errorf("unexpected Network: %v", privateNet.Network) 672 } 673 if privateNet.IP.String() != "10.0.1.1" { 674 t.Errorf("unexpected IP: %v", privateNet.IP) 675 } 676 if len(privateNet.Aliases) != 1 { 677 t.Errorf("unexpected number of alias IPs: %v", len(privateNet.Aliases)) 678 } 679 if privateNet.Aliases[0].String() != "10.0.1.2" { 680 t.Errorf("unexpected alias IP: %v", privateNet.Aliases[0]) 681 } 682 if privateNet.MACAddress != "86:00:ff:2a:7d:e1" { 683 t.Errorf("unexpected mac address: %v", privateNet.MACAddress) 684 } 685} 686 687func TestServerTypeFromSchema(t *testing.T) { 688 data := []byte(`{ 689 "id": 1, 690 "name": "cx10", 691 "description": "description", 692 "cores": 4, 693 "memory": 1.0, 694 "disk": 20, 695 "storage_type": "local", 696 "cpu_type": "shared", 697 "prices": [ 698 { 699 "location": "fsn1", 700 "price_hourly": { 701 "net": "1", 702 "gross": "1.19" 703 }, 704 "price_monthly": { 705 "net": "1", 706 "gross": "1.19" 707 } 708 } 709 ] 710 }`) 711 712 var s schema.ServerType 713 if err := json.Unmarshal(data, &s); err != nil { 714 t.Fatal(err) 715 } 716 serverType := ServerTypeFromSchema(s) 717 718 if serverType.ID != 1 { 719 t.Errorf("unexpected ID: %v", serverType.ID) 720 } 721 if serverType.Name != "cx10" { 722 t.Errorf("unexpected name: %q", serverType.Name) 723 } 724 if serverType.Description != "description" { 725 t.Errorf("unexpected description: %q", serverType.Description) 726 } 727 if serverType.Cores != 4 { 728 t.Errorf("unexpected cores: %v", serverType.Cores) 729 } 730 if serverType.Memory != 1.0 { 731 t.Errorf("unexpected memory: %v", serverType.Memory) 732 } 733 if serverType.Disk != 20 { 734 t.Errorf("unexpected disk: %v", serverType.Disk) 735 } 736 if serverType.StorageType != StorageTypeLocal { 737 t.Errorf("unexpected storage type: %q", serverType.StorageType) 738 } 739 if serverType.CPUType != CPUTypeShared { 740 t.Errorf("unexpected cpu type: %q", serverType.CPUType) 741 } 742 if len(serverType.Pricings) != 1 { 743 t.Errorf("unexpected number of pricings: %d", len(serverType.Pricings)) 744 } else { 745 if serverType.Pricings[0].Location.Name != "fsn1" { 746 t.Errorf("unexpected location name: %v", serverType.Pricings[0].Location.Name) 747 } 748 if serverType.Pricings[0].Hourly.Net != "1" { 749 t.Errorf("unexpected hourly net price: %v", serverType.Pricings[0].Hourly.Net) 750 } 751 if serverType.Pricings[0].Hourly.Gross != "1.19" { 752 t.Errorf("unexpected hourly gross price: %v", serverType.Pricings[0].Hourly.Gross) 753 } 754 if serverType.Pricings[0].Monthly.Net != "1" { 755 t.Errorf("unexpected monthly net price: %v", serverType.Pricings[0].Monthly.Net) 756 } 757 if serverType.Pricings[0].Monthly.Gross != "1.19" { 758 t.Errorf("unexpected monthly gross price: %v", serverType.Pricings[0].Monthly.Gross) 759 } 760 } 761} 762 763func TestSSHKeyFromSchema(t *testing.T) { 764 data := []byte(`{ 765 "id": 2323, 766 "name": "My key", 767 "fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2c", 768 "public_key": "ssh-rsa AAAjjk76kgf...Xt", 769 "labels": { 770 "key": "value", 771 "key2": "value2" 772 }, 773 "created":"2017-08-16T17:29:14+00:00" 774 }`) 775 776 var s schema.SSHKey 777 if err := json.Unmarshal(data, &s); err != nil { 778 t.Fatal(err) 779 } 780 sshKey := SSHKeyFromSchema(s) 781 782 if sshKey.ID != 2323 { 783 t.Errorf("unexpected ID: %v", sshKey.ID) 784 } 785 if sshKey.Name != "My key" { 786 t.Errorf("unexpected name: %v", sshKey.Name) 787 } 788 if sshKey.Fingerprint != "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2c" { 789 t.Errorf("unexpected fingerprint: %v", sshKey.Fingerprint) 790 } 791 if sshKey.PublicKey != "ssh-rsa AAAjjk76kgf...Xt" { 792 t.Errorf("unexpected public key: %v", sshKey.PublicKey) 793 } 794 if sshKey.Labels["key"] != "value" || sshKey.Labels["key2"] != "value2" { 795 t.Errorf("unexpected labels: %v", sshKey.Labels) 796 } 797 if !sshKey.Created.Equal(time.Date(2017, 8, 16, 17, 29, 14, 0, time.UTC)) { 798 t.Errorf("unexpected created date: %v", sshKey.Created) 799 } 800} 801 802func TestErrorFromSchema(t *testing.T) { 803 t.Run("service_error", func(t *testing.T) { 804 data := []byte(`{ 805 "code": "service_error", 806 "message": "An error occurred", 807 "details": {} 808 }`) 809 810 var s schema.Error 811 if err := json.Unmarshal(data, &s); err != nil { 812 t.Fatal(err) 813 } 814 err := ErrorFromSchema(s) 815 816 if err.Code != "service_error" { 817 t.Errorf("unexpected code: %v", err.Code) 818 } 819 if err.Message != "An error occurred" { 820 t.Errorf("unexpected message: %v", err.Message) 821 } 822 }) 823 824 t.Run("invalid_input", func(t *testing.T) { 825 data := []byte(`{ 826 "code": "invalid_input", 827 "message": "invalid input", 828 "details": { 829 "fields": [ 830 { 831 "name": "broken_field", 832 "messages": ["is required"] 833 } 834 ] 835 } 836 }`) 837 838 var s schema.Error 839 if err := json.Unmarshal(data, &s); err != nil { 840 t.Fatal(err) 841 } 842 err := ErrorFromSchema(s) 843 844 if err.Code != "invalid_input" { 845 t.Errorf("unexpected Code: %v", err.Code) 846 } 847 if err.Message != "invalid input" { 848 t.Errorf("unexpected Message: %v", err.Message) 849 } 850 if d, ok := err.Details.(ErrorDetailsInvalidInput); !ok { 851 t.Fatalf("unexpected Details type (should be ErrorDetailsInvalidInput): %v", err.Details) 852 } else { 853 if len(d.Fields) != 1 { 854 t.Fatalf("unexpected Details.Fields length (should be 1): %v", d.Fields) 855 } 856 if d.Fields[0].Name != "broken_field" { 857 t.Errorf("unexpected Details.Fields[0].Name: %v", d.Fields[0].Name) 858 } 859 if len(d.Fields[0].Messages) != 1 { 860 t.Fatalf("unexpected Details.Fields[0].Messages length (should be 1): %v", d.Fields[0].Messages) 861 } 862 if d.Fields[0].Messages[0] != "is required" { 863 t.Errorf("unexpected Details.Fields[0].Messages[0]: %v", d.Fields[0].Messages[0]) 864 } 865 } 866 }) 867} 868 869func TestPaginationFromSchema(t *testing.T) { 870 data := []byte(`{ 871 "page": 2, 872 "per_page": 25, 873 "previous_page": 1, 874 "next_page": 3, 875 "last_page": 13, 876 "total_entries": 322 877 }`) 878 879 var s schema.MetaPagination 880 if err := json.Unmarshal(data, &s); err != nil { 881 t.Fatal(err) 882 } 883 p := PaginationFromSchema(s) 884 885 if p.Page != 2 { 886 t.Errorf("unexpected page: %v", p.Page) 887 } 888 if p.PerPage != 25 { 889 t.Errorf("unexpected per page: %v", p.PerPage) 890 } 891 if p.PreviousPage != 1 { 892 t.Errorf("unexpected previous page: %v", p.PreviousPage) 893 } 894 if p.NextPage != 3 { 895 t.Errorf("unexpected next page: %d", p.NextPage) 896 } 897 if p.LastPage != 13 { 898 t.Errorf("unexpected last page: %d", p.LastPage) 899 } 900 if p.TotalEntries != 322 { 901 t.Errorf("unexpected total entries: %d", p.TotalEntries) 902 } 903} 904 905func TestImageFromSchema(t *testing.T) { 906 data := []byte(`{ 907 "id": 4711, 908 "type": "system", 909 "status": "available", 910 "name": "ubuntu16.04-standard-x64", 911 "description": "Ubuntu 16.04 Standard 64 bit", 912 "image_size": 2.3, 913 "disk_size": 10, 914 "created": "2016-01-30T23:55:01Z", 915 "created_from": { 916 "id": 1, 917 "name": "my-server1" 918 }, 919 "bound_to": 1, 920 "os_flavor": "ubuntu", 921 "os_version": "16.04", 922 "rapid_deploy": false, 923 "protection": { 924 "delete": true 925 }, 926 "deprecated": "2018-02-28T00:00:00+00:00", 927 "labels": { 928 "key": "value", 929 "key2": "value2" 930 } 931 }`) 932 933 var s schema.Image 934 if err := json.Unmarshal(data, &s); err != nil { 935 t.Fatal(err) 936 } 937 image := ImageFromSchema(s) 938 939 if image.ID != 4711 { 940 t.Errorf("unexpected ID: %v", image.ID) 941 } 942 if image.Type != ImageTypeSystem { 943 t.Errorf("unexpected Type: %v", image.Type) 944 } 945 if image.Status != ImageStatusAvailable { 946 t.Errorf("unexpected Status: %v", image.Status) 947 } 948 if image.Name != "ubuntu16.04-standard-x64" { 949 t.Errorf("unexpected Name: %v", image.Name) 950 } 951 if image.Description != "Ubuntu 16.04 Standard 64 bit" { 952 t.Errorf("unexpected Description: %v", image.Description) 953 } 954 if image.ImageSize != 2.3 { 955 t.Errorf("unexpected ImageSize: %v", image.ImageSize) 956 } 957 if image.DiskSize != 10 { 958 t.Errorf("unexpected DiskSize: %v", image.DiskSize) 959 } 960 if !image.Created.Equal(time.Date(2016, 1, 30, 23, 55, 1, 0, time.UTC)) { 961 t.Errorf("unexpected Created: %v", image.Created) 962 } 963 if image.CreatedFrom == nil || image.CreatedFrom.ID != 1 || image.CreatedFrom.Name != "my-server1" { 964 t.Errorf("unexpected CreatedFrom: %v", image.CreatedFrom) 965 } 966 if image.BoundTo == nil || image.BoundTo.ID != 1 { 967 t.Errorf("unexpected BoundTo: %v", image.BoundTo) 968 } 969 if image.OSVersion != "16.04" { 970 t.Errorf("unexpected OSVersion: %v", image.OSVersion) 971 } 972 if image.OSFlavor != "ubuntu" { 973 t.Errorf("unexpected OSFlavor: %v", image.OSFlavor) 974 } 975 if image.RapidDeploy { 976 t.Errorf("unexpected RapidDeploy: %v", image.RapidDeploy) 977 } 978 if !image.Protection.Delete { 979 t.Errorf("unexpected Protection.Delete: %v", image.Protection.Delete) 980 } 981 if image.Deprecated.IsZero() { 982 t.Errorf("unexpected value for Deprecated: %v", image.Deprecated) 983 } 984 if image.Labels["key"] != "value" || image.Labels["key2"] != "value2" { 985 t.Errorf("unexpected Labels: %v", image.Labels) 986 } 987} 988 989func TestVolumeFromSchema(t *testing.T) { 990 data := []byte(`{ 991 "id": 4711, 992 "created": "2016-01-30T23:50:11+00:00", 993 "name": "db-storage", 994 "status": "creating", 995 "server": 2, 996 "location": { 997 "id": 1, 998 "name": "fsn1", 999 "description": "Falkenstein DC Park 1", 1000 "country": "DE", 1001 "city": "Falkenstein", 1002 "latitude": 50.47612, 1003 "longitude": 12.370071 1004 }, 1005 "size": 42, 1006 "linux_device":"/dev/disk/by-id/scsi-0HC_volume_1", 1007 "protection": { 1008 "delete": true 1009 }, 1010 "labels": { 1011 "key": "value", 1012 "key2": "value2" 1013 } 1014 }`) 1015 var s schema.Volume 1016 if err := json.Unmarshal(data, &s); err != nil { 1017 t.Fatal(err) 1018 } 1019 volume := VolumeFromSchema(s) 1020 if volume.ID != 4711 { 1021 t.Errorf("unexpected ID: %v", volume.ID) 1022 } 1023 if volume.Name != "db-storage" { 1024 t.Errorf("unexpected name: %v", volume.Name) 1025 } 1026 if volume.Status != VolumeStatusCreating { 1027 t.Errorf("unexpected status: %v", volume.Status) 1028 } 1029 if !volume.Created.Equal(time.Date(2016, 1, 30, 23, 50, 11, 0, time.UTC)) { 1030 t.Errorf("unexpected created date: %s", volume.Created) 1031 } 1032 if volume.Server == nil { 1033 t.Error("no server") 1034 } 1035 if volume.Server != nil && volume.Server.ID != 2 { 1036 t.Errorf("unexpected server ID: %v", volume.Server.ID) 1037 } 1038 if volume.Location == nil || volume.Location.ID != 1 { 1039 t.Errorf("unexpected location: %v", volume.Location) 1040 } 1041 if volume.Size != 42 { 1042 t.Errorf("unexpected size: %v", volume.Size) 1043 } 1044 if !volume.Protection.Delete { 1045 t.Errorf("unexpected value for delete protection: %v", volume.Protection.Delete) 1046 } 1047 if len(volume.Labels) != 2 { 1048 t.Errorf("unexpected number of labels: %d", len(volume.Labels)) 1049 } 1050 if volume.Labels["key"] != "value" || volume.Labels["key2"] != "value2" { 1051 t.Errorf("unexpected labels: %v", volume.Labels) 1052 } 1053} 1054 1055func TestNetworkFromSchema(t *testing.T) { 1056 data := []byte(`{ 1057 "id": 4711, 1058 "name": "mynet", 1059 "created": "2017-08-16T17:29:14+00:00", 1060 "ip_range": "10.0.0.0/16", 1061 "subnets": [ 1062 { 1063 "type": "server", 1064 "ip_range": "10.0.1.0/24", 1065 "network_zone": "eu-central", 1066 "gateway": "10.0.0.1" 1067 } 1068 ], 1069 "routes": [ 1070 { 1071 "destination": "10.100.1.0/24", 1072 "gateway": "10.0.1.1" 1073 } 1074 ], 1075 "servers": [ 1076 4711 1077 ], 1078 "protection": { 1079 "delete": false 1080 }, 1081 "labels": {} 1082 }`) 1083 1084 var s schema.Network 1085 if err := json.Unmarshal(data, &s); err != nil { 1086 t.Fatal(err) 1087 } 1088 network := NetworkFromSchema(s) 1089 if network.ID != 4711 { 1090 t.Errorf("unexpected ID: %v", network.ID) 1091 } 1092 if network.Name != "mynet" { 1093 t.Errorf("unexpected Name: %v", network.Name) 1094 } 1095 if !network.Created.Equal(time.Date(2017, 8, 16, 17, 29, 14, 0, time.UTC)) { 1096 t.Errorf("unexpected created date: %v", network.Created) 1097 } 1098 if network.IPRange.String() != "10.0.0.0/16" { 1099 t.Errorf("unexpected IPRange: %v", network.IPRange) 1100 } 1101 if len(network.Subnets) != 1 { 1102 t.Errorf("unexpected length of Subnets: %v", len(network.Subnets)) 1103 } 1104 if len(network.Routes) != 1 { 1105 t.Errorf("unexpected length of Routes: %v", len(network.Routes)) 1106 } 1107 if len(network.Servers) != 1 { 1108 t.Errorf("unexpected length of Servers: %v", len(network.Servers)) 1109 } 1110 if network.Servers[0].ID != 4711 { 1111 t.Errorf("unexpected Server ID: %v", network.Servers[0].ID) 1112 } 1113 if network.Protection.Delete { 1114 t.Errorf("unexpected value for delete protection: %v", network.Protection.Delete) 1115 } 1116} 1117 1118func TestNetworkSubnetFromSchema(t *testing.T) { 1119 t.Run("type server", func(t *testing.T) { 1120 data := []byte(`{ 1121 "type": "server", 1122 "ip_range": "10.0.1.0/24", 1123 "network_zone": "eu-central", 1124 "gateway": "10.0.0.1" 1125 }`) 1126 var s schema.NetworkSubnet 1127 if err := json.Unmarshal(data, &s); err != nil { 1128 t.Fatal(err) 1129 } 1130 networkSubnet := NetworkSubnetFromSchema(s) 1131 if networkSubnet.NetworkZone != "eu-central" { 1132 t.Errorf("unexpected NetworkZone: %v", networkSubnet.NetworkZone) 1133 } 1134 if networkSubnet.Type != "server" { 1135 t.Errorf("unexpected Type: %v", networkSubnet.Type) 1136 } 1137 if networkSubnet.IPRange.String() != "10.0.1.0/24" { 1138 t.Errorf("unexpected IPRange: %v", networkSubnet.IPRange) 1139 } 1140 if networkSubnet.Gateway.String() != "10.0.0.1" { 1141 t.Errorf("unexpected Gateway: %v", networkSubnet.Gateway) 1142 } 1143 if networkSubnet.VSwitchID != 0 { 1144 t.Errorf("unexpected VSwitchID: %v", networkSubnet.VSwitchID) 1145 } 1146 }) 1147 1148 t.Run("type vswitch", func(t *testing.T) { 1149 data := []byte(`{ 1150 "type": "vswitch", 1151 "ip_range": "10.0.1.0/24", 1152 "network_zone": "eu-central", 1153 "gateway": "10.0.0.1", 1154 "vswitch_id": 123 1155 }`) 1156 var s schema.NetworkSubnet 1157 if err := json.Unmarshal(data, &s); err != nil { 1158 t.Fatal(err) 1159 } 1160 networkSubnet := NetworkSubnetFromSchema(s) 1161 if networkSubnet.NetworkZone != "eu-central" { 1162 t.Errorf("unexpected NetworkZone: %v", networkSubnet.NetworkZone) 1163 } 1164 if networkSubnet.Type != "vswitch" { 1165 t.Errorf("unexpected Type: %v", networkSubnet.Type) 1166 } 1167 if networkSubnet.IPRange.String() != "10.0.1.0/24" { 1168 t.Errorf("unexpected IPRange: %v", networkSubnet.IPRange) 1169 } 1170 if networkSubnet.Gateway.String() != "10.0.0.1" { 1171 t.Errorf("unexpected Gateway: %v", networkSubnet.Gateway) 1172 } 1173 if networkSubnet.VSwitchID != 123 { 1174 t.Errorf("unexpected VSwitchID: %v", networkSubnet.VSwitchID) 1175 } 1176 }) 1177} 1178 1179func TestNetworkRouteFromSchema(t *testing.T) { 1180 data := []byte(`{ 1181 "destination": "10.100.1.0/24", 1182 "gateway": "10.0.1.1" 1183 }`) 1184 var s schema.NetworkRoute 1185 if err := json.Unmarshal(data, &s); err != nil { 1186 t.Fatal(err) 1187 } 1188 networkRoute := NetworkRouteFromSchema(s) 1189 if networkRoute.Destination.String() != "10.100.1.0/24" { 1190 t.Errorf("unexpected Destination: %v", networkRoute.Destination) 1191 } 1192 if networkRoute.Gateway.String() != "10.0.1.1" { 1193 t.Errorf("unexpected Gateway: %v", networkRoute.Gateway) 1194 } 1195} 1196 1197func TestLoadBalancerTypeFromSchema(t *testing.T) { 1198 data := []byte(`{ 1199 "id": 1, 1200 "name": "lx11", 1201 "description": "LX11", 1202 "max_connections": 20000, 1203 "max_services": 3, 1204 "max_targets": 25, 1205 "max_assigned_certificates": 10, 1206 "deprecated": "2016-01-30T23:50:00+00:00", 1207 "prices": [ 1208 { 1209 "location": "fsn1", 1210 "price_hourly": { 1211 "net": "1", 1212 "gross": "1.19" 1213 }, 1214 "price_monthly": { 1215 "net": "1", 1216 "gross": "1.19" 1217 } 1218 } 1219 ] 1220 }`) 1221 var s schema.LoadBalancerType 1222 if err := json.Unmarshal(data, &s); err != nil { 1223 t.Fatal(err) 1224 } 1225 loadBalancerType := LoadBalancerTypeFromSchema(s) 1226 if loadBalancerType.ID != 1 { 1227 t.Errorf("unexpected ID: %v", loadBalancerType.ID) 1228 } 1229 if loadBalancerType.Name != "lx11" { 1230 t.Errorf("unexpected Name: %v", loadBalancerType.Name) 1231 } 1232 if loadBalancerType.Description != "LX11" { 1233 t.Errorf("unexpected Description: %v", loadBalancerType.Description) 1234 } 1235 if loadBalancerType.MaxConnections != 20000 { 1236 t.Errorf("unexpected MaxConnections: %v", loadBalancerType.MaxConnections) 1237 } 1238 if loadBalancerType.MaxServices != 3 { 1239 t.Errorf("unexpected MaxServices: %v", loadBalancerType.MaxServices) 1240 } 1241 if loadBalancerType.MaxTargets != 25 { 1242 t.Errorf("unexpected MaxTargets: %v", loadBalancerType.MaxTargets) 1243 } 1244 if loadBalancerType.MaxAssignedCertificates != 10 { 1245 t.Errorf("unexpected MaxAssignedCertificates: %v", loadBalancerType.MaxAssignedCertificates) 1246 } 1247 if len(loadBalancerType.Pricings) != 1 { 1248 t.Errorf("unexpected number of pricings: %d", len(loadBalancerType.Pricings)) 1249 } else { 1250 if loadBalancerType.Pricings[0].Location.Name != "fsn1" { 1251 t.Errorf("unexpected location name: %v", loadBalancerType.Pricings[0].Location.Name) 1252 } 1253 if loadBalancerType.Pricings[0].Hourly.Net != "1" { 1254 t.Errorf("unexpected hourly net price: %v", loadBalancerType.Pricings[0].Hourly.Net) 1255 } 1256 if loadBalancerType.Pricings[0].Hourly.Gross != "1.19" { 1257 t.Errorf("unexpected hourly gross price: %v", loadBalancerType.Pricings[0].Hourly.Gross) 1258 } 1259 if loadBalancerType.Pricings[0].Monthly.Net != "1" { 1260 t.Errorf("unexpected monthly net price: %v", loadBalancerType.Pricings[0].Monthly.Net) 1261 } 1262 if loadBalancerType.Pricings[0].Monthly.Gross != "1.19" { 1263 t.Errorf("unexpected monthly gross price: %v", loadBalancerType.Pricings[0].Monthly.Gross) 1264 } 1265 } 1266} 1267 1268func TestLoadBalancerFromSchema(t *testing.T) { 1269 data := []byte(`{ 1270 "id": 4711, 1271 "name": "Web Frontend", 1272 "public_net": { 1273 "ipv4": { 1274 "ip": "131.232.99.1" 1275 }, 1276 "ipv6": { 1277 "ip": "2001:db8::1" 1278 } 1279 }, 1280 "private_net": [ 1281 { 1282 "network": 4711, 1283 "ip": "10.0.255.1" 1284 } 1285 ], 1286 "location": { 1287 "id": 1, 1288 "name": "fsn1", 1289 "description": "Falkenstein DC Park 1", 1290 "country": "DE", 1291 "city": "Falkenstein", 1292 "latitude": 50.47612, 1293 "longitude": 12.370071, 1294 "network_zone": "eu-central" 1295 }, 1296 "load_balancer_type": { 1297 "id": 1, 1298 "name": "lx11", 1299 "description": "LX11", 1300 "max_connections": 20000, 1301 "services": 3, 1302 "prices": [ 1303 { 1304 "location": "fsn-1", 1305 "price_hourly": { 1306 "net": "1", 1307 "gross": "1.19" 1308 }, 1309 "price_monthly": { 1310 "net": "1", 1311 "gross": "1.19" 1312 } 1313 } 1314 ] 1315 }, 1316 "outgoing_traffic": 123456, 1317 "ingoing_traffic": 7891011, 1318 "included_traffic": 654321, 1319 "protection": { 1320 "delete": false 1321 }, 1322 "labels": {}, 1323 "created": "2016-01-30T23:50:00+00:00", 1324 "services": [ 1325 { 1326 "protocol": "http", 1327 "listen_port": 443, 1328 "destination_port": 80, 1329 "proxyprotocol": false, 1330 "sticky_sessions": false, 1331 "http": { 1332 "cookie_name": "HCLBSTICKY", 1333 "cookie_lifetime": 300, 1334 "certificates": [ 1335 897 1336 ] 1337 }, 1338 "health_check": { 1339 "protocol": "http", 1340 "port": 4711, 1341 "interval": 15, 1342 "timeout": 10, 1343 "retries": 3, 1344 "http": { 1345 "domain": "example.com", 1346 "path": "/" 1347 } 1348 } 1349 } 1350 ], 1351 "targets": [ 1352 { 1353 "type": "server", 1354 "server": { 1355 "id": 80 1356 }, 1357 "label_selector": null, 1358 "health_status": [ 1359 { 1360 "listen_port": 443, 1361 "status": "healthy" 1362 } 1363 ], 1364 "use_private_ip": false 1365 }, 1366 { 1367 "type": "label_selector", 1368 "label_selector": { 1369 "selector": "lbt" 1370 }, 1371 "targets": [ 1372 { 1373 "type": "server", 1374 "server": { 1375 "id": 80 1376 }, 1377 "health_status": [ 1378 { 1379 "listen_port": 443, 1380 "status": "healthy" 1381 } 1382 ], 1383 "use_private_ip": false 1384 } 1385 ] 1386 } 1387 ], 1388 "algorithm": { 1389 "type": "round_robin" 1390 } 1391 }`) 1392 var s schema.LoadBalancer 1393 if err := json.Unmarshal(data, &s); err != nil { 1394 t.Fatal(err) 1395 } 1396 loadBalancer := LoadBalancerFromSchema(s) 1397 if loadBalancer.ID != 4711 { 1398 t.Errorf("unexpected ID: %v", loadBalancer.ID) 1399 } 1400 if loadBalancer.Name != "Web Frontend" { 1401 t.Errorf("unexpected Name: %v", loadBalancer.Name) 1402 } 1403 if loadBalancer.PublicNet.IPv4.IP.String() != "131.232.99.1" { 1404 t.Errorf("unexpected IPv4: %v", loadBalancer.PublicNet.IPv4.IP) 1405 } 1406 if loadBalancer.PublicNet.IPv6.IP.String() != "2001:db8::1" { 1407 t.Errorf("unexpected IPv6: %v", loadBalancer.PublicNet.IPv6) 1408 } 1409 if len(loadBalancer.PrivateNet) != 1 { 1410 t.Errorf("unexpected length of PrivateNet: %v", len(loadBalancer.PrivateNet)) 1411 } else { 1412 if loadBalancer.PrivateNet[0].Network.ID != 4711 { 1413 t.Errorf("unexpected Network ID: %v", loadBalancer.PrivateNet[0].Network.ID) 1414 } 1415 if loadBalancer.PrivateNet[0].IP.String() != "10.0.255.1" { 1416 t.Errorf("unexpected Network IP: %v", loadBalancer.PrivateNet[0].IP) 1417 } 1418 } 1419 if loadBalancer.Location == nil || loadBalancer.Location.ID != 1 { 1420 t.Errorf("unexpected Location: %v", loadBalancer.Location) 1421 } 1422 if loadBalancer.LoadBalancerType == nil || loadBalancer.LoadBalancerType.ID != 1 { 1423 t.Errorf("unexpected LoadBalancerType: %v", loadBalancer.LoadBalancerType) 1424 } 1425 if loadBalancer.Protection.Delete { 1426 t.Errorf("unexpected value for delete protection: %v", loadBalancer.Protection.Delete) 1427 } 1428 if !loadBalancer.Created.Equal(time.Date(2016, 01, 30, 23, 50, 00, 0, time.UTC)) { 1429 t.Errorf("unexpected created date: %v", loadBalancer.Created) 1430 } 1431 if len(loadBalancer.Services) != 1 { 1432 t.Errorf("unexpected length of Services: %v", len(loadBalancer.Services)) 1433 } 1434 if len(loadBalancer.Targets) != 2 { 1435 t.Errorf("unexpected length of Targets: %v", len(loadBalancer.Targets)) 1436 } 1437 if loadBalancer.Algorithm.Type != "round_robin" { 1438 t.Errorf("unexpected Algorithm.Type: %v", loadBalancer.Algorithm.Type) 1439 } 1440 if loadBalancer.IncludedTraffic != 654321 { 1441 t.Errorf("unexpected included traffic: %v", loadBalancer.IncludedTraffic) 1442 } 1443 if loadBalancer.OutgoingTraffic != 123456 { 1444 t.Errorf("unexpected outgoing traffic: %v", loadBalancer.OutgoingTraffic) 1445 } 1446 if loadBalancer.IngoingTraffic != 7891011 { 1447 t.Errorf("unexpected ingoing traffic: %v", loadBalancer.IngoingTraffic) 1448 } 1449} 1450 1451func TestLoadBalancerServiceFromSchema(t *testing.T) { 1452 data := []byte(`{ 1453 "protocol": "http", 1454 "listen_port": 443, 1455 "destination_port": 80, 1456 "proxyprotocol": false, 1457 "http": { 1458 "cookie_name": "HCLBSTICKY", 1459 "cookie_lifetime": 300, 1460 "certificates": [ 1461 897 1462 ], 1463 "redirect_http": true, 1464 "sticky_sessions": true 1465 }, 1466 "health_check": { 1467 "protocol": "http", 1468 "port": 4711, 1469 "interval": 15, 1470 "timeout": 10, 1471 "retries": 3, 1472 "http": { 1473 "domain": "example.com", 1474 "path": "/", 1475 "response": "", 1476 "status_codes":["200","201"], 1477 "tls": false 1478 } 1479 } 1480 }`) 1481 var s schema.LoadBalancerService 1482 if err := json.Unmarshal(data, &s); err != nil { 1483 t.Fatal(err) 1484 } 1485 loadBalancerService := LoadBalancerServiceFromSchema(s) 1486 if loadBalancerService.Protocol != "http" { 1487 t.Errorf("unexpected Protocol: %v", loadBalancerService.Protocol) 1488 } 1489 if loadBalancerService.ListenPort != 443 { 1490 t.Errorf("unexpected ListenPort: %v", loadBalancerService.ListenPort) 1491 } 1492 if loadBalancerService.DestinationPort != 80 { 1493 t.Errorf("unexpected DestinationPort: %v", loadBalancerService.DestinationPort) 1494 } 1495 if loadBalancerService.Proxyprotocol { 1496 t.Errorf("unexpected ProxyProtocol: %v", loadBalancerService.Proxyprotocol) 1497 } 1498 if loadBalancerService.HTTP.CookieName != "HCLBSTICKY" { 1499 t.Errorf("unexpected HTTP.CookieName: %v", loadBalancerService.HTTP.CookieName) 1500 } 1501 if loadBalancerService.HTTP.CookieLifetime.Seconds() != 300 { 1502 t.Errorf("unexpected HTTP.CookieLifetime: %v", loadBalancerService.HTTP.CookieLifetime.Seconds()) 1503 } 1504 if loadBalancerService.HTTP.Certificates[0].ID != 897 { 1505 t.Errorf("unexpected Certificates[0].ID : %v", loadBalancerService.HTTP.Certificates[0].ID) 1506 } 1507 if !loadBalancerService.HTTP.RedirectHTTP { 1508 t.Errorf("unexpected HTTP.RedirectHTTP: %v", loadBalancerService.HTTP.RedirectHTTP) 1509 } 1510 1511 if !loadBalancerService.HTTP.StickySessions { 1512 t.Errorf("unexpected HTTP.StickySessions: %v", loadBalancerService.HTTP.StickySessions) 1513 } 1514 if loadBalancerService.HealthCheck.Protocol != "http" { 1515 t.Errorf("unexpected HealthCheck.Protocol: %v", loadBalancerService.HealthCheck.Protocol) 1516 } 1517 if loadBalancerService.HealthCheck.Port != 4711 { 1518 t.Errorf("unexpected HealthCheck.Port: %v", loadBalancerService.HealthCheck.Port) 1519 } 1520 if loadBalancerService.HealthCheck.Interval.Seconds() != 15 { 1521 t.Errorf("unexpected HealthCheck.Interval: %v", loadBalancerService.HealthCheck.Interval) 1522 } 1523 if loadBalancerService.HealthCheck.Timeout.Seconds() != 10 { 1524 t.Errorf("unexpected HealthCheck.Timeout: %v", loadBalancerService.HealthCheck.Timeout) 1525 } 1526 if loadBalancerService.HealthCheck.Retries != 3 { 1527 t.Errorf("unexpected HealthCheck.Retries: %v", loadBalancerService.HealthCheck.Retries) 1528 } 1529 if loadBalancerService.HealthCheck.HTTP.Domain != "example.com" { 1530 t.Errorf("unexpected HealthCheck.HTTP.Domain: %v", loadBalancerService.HealthCheck.HTTP.Domain) 1531 } 1532 if loadBalancerService.HealthCheck.HTTP.Path != "/" { 1533 t.Errorf("unexpected HealthCheck.HTTP.Path: %v", loadBalancerService.HealthCheck.HTTP.Path) 1534 } 1535 if loadBalancerService.HealthCheck.HTTP.Response != "" { 1536 t.Errorf("unexpected HealthCheck.HTTP.Response: %v", loadBalancerService.HealthCheck.HTTP.Response) 1537 } 1538 if loadBalancerService.HealthCheck.HTTP.TLS { 1539 t.Errorf("unexpected HealthCheck.HTTP.TLS: %v", loadBalancerService.HealthCheck.HTTP.TLS) 1540 } 1541 if len(loadBalancerService.HealthCheck.HTTP.StatusCodes) != 2 { 1542 t.Errorf("unexpected len(HealthCheck.HTTP.StatusCodes): %v", len(loadBalancerService.HealthCheck.HTTP.StatusCodes)) 1543 } else { 1544 if loadBalancerService.HealthCheck.HTTP.StatusCodes[0] != "200" { 1545 t.Errorf("unexpected HealthCheck.HTTP.StatusCodes[0]: %v", loadBalancerService.HealthCheck.HTTP.StatusCodes[0]) 1546 } 1547 if loadBalancerService.HealthCheck.HTTP.StatusCodes[1] != "201" { 1548 t.Errorf("unexpected HealthCheck.HTTP.StatusCodes[1]: %v", loadBalancerService.HealthCheck.HTTP.StatusCodes[1]) 1549 } 1550 } 1551} 1552 1553func TestLoadBalancerTargetFromSchema(t *testing.T) { 1554 t.Run("server target", func(t *testing.T) { 1555 data := []byte(`{ 1556 "type": "server", 1557 "server": { 1558 "id": 80 1559 }, 1560 "label_selector": null, 1561 "health_status": [ 1562 { 1563 "listen_port": 443, 1564 "status": "healthy" 1565 } 1566 ], 1567 "use_private_ip": false 1568 }`) 1569 var s schema.LoadBalancerTarget 1570 if err := json.Unmarshal(data, &s); err != nil { 1571 t.Fatal(err) 1572 } 1573 loadBalancerTarget := LoadBalancerTargetFromSchema(s) 1574 if loadBalancerTarget.Type != "server" { 1575 t.Errorf("unexpected Type: %v", loadBalancerTarget.Type) 1576 } 1577 if loadBalancerTarget.Server == nil || loadBalancerTarget.Server.Server.ID != 80 { 1578 t.Errorf("unexpected Server: %v", loadBalancerTarget.Server) 1579 } 1580 if loadBalancerTarget.LabelSelector != nil { 1581 t.Errorf("unexpected LabelSelector.Selector: %v", loadBalancerTarget.LabelSelector) 1582 } 1583 if loadBalancerTarget.UsePrivateIP { 1584 t.Errorf("unexpected UsePrivateIP: %v", loadBalancerTarget.UsePrivateIP) 1585 } 1586 if len(loadBalancerTarget.HealthStatus) != 1 { 1587 t.Errorf("unexpected Health Status length: %v", len(loadBalancerTarget.HealthStatus)) 1588 } else { 1589 if loadBalancerTarget.HealthStatus[0].ListenPort != 443 { 1590 t.Errorf("unexpected HealthStatus[0].ListenPort: %v", loadBalancerTarget.HealthStatus[0].ListenPort) 1591 } 1592 if loadBalancerTarget.HealthStatus[0].Status != LoadBalancerTargetHealthStatusStatusHealthy { 1593 t.Errorf("unexpected HealthStatus[0].Status: %v", loadBalancerTarget.HealthStatus[0].Status) 1594 } 1595 } 1596 }) 1597 t.Run("label_selector target", func(t *testing.T) { 1598 data := []byte(`{ 1599 "type": "label_selector", 1600 "label_selector": { 1601 "selector": "lbt" 1602 }, 1603 "targets": [ 1604 { 1605 "type": "server", 1606 "server": { 1607 "id": 80 1608 }, 1609 "health_status": [ 1610 { 1611 "listen_port": 443, 1612 "status": "healthy" 1613 } 1614 ] 1615 } 1616 ] 1617 }`) 1618 var s schema.LoadBalancerTarget 1619 if err := json.Unmarshal(data, &s); err != nil { 1620 t.Fatal(err) 1621 } 1622 loadBalancerTarget := LoadBalancerTargetFromSchema(s) 1623 if loadBalancerTarget.Type != "label_selector" { 1624 t.Errorf("unexpected Type: %v", loadBalancerTarget.Type) 1625 } 1626 if loadBalancerTarget.LabelSelector == nil || loadBalancerTarget.LabelSelector.Selector != "lbt" { 1627 t.Errorf("unexpected LabelSelector: %v", loadBalancerTarget.LabelSelector) 1628 } 1629 if loadBalancerTarget.Server != nil { 1630 t.Errorf("unexpected LabelSelector.Server: %v", loadBalancerTarget.Server) 1631 } 1632 if len(loadBalancerTarget.Targets) != 1 { 1633 t.Errorf("unexpected Targets length: %v", len(loadBalancerTarget.Targets)) 1634 } else { 1635 if loadBalancerTarget.Targets[0].Server == nil || loadBalancerTarget.Targets[0].Server.Server.ID != 80 { 1636 t.Errorf("unexpected loadBalancerTarget.Targets[0].Server.Server.ID: %v", loadBalancerTarget.Targets[0].Server.Server.ID) 1637 } 1638 if len(loadBalancerTarget.Targets[0].HealthStatus) != 1 { 1639 t.Errorf("unexpected Targets length: %v", len(loadBalancerTarget.Targets[0].HealthStatus)) 1640 } else { 1641 if loadBalancerTarget.Targets[0].HealthStatus[0].ListenPort != 443 { 1642 t.Errorf("unexpected HealthStatus[0].ListenPort: %v", loadBalancerTarget.Targets[0].HealthStatus[0].ListenPort) 1643 } 1644 if loadBalancerTarget.Targets[0].HealthStatus[0].Status != LoadBalancerTargetHealthStatusStatusHealthy { 1645 t.Errorf("unexpected HealthStatus[0].Status: %v", loadBalancerTarget.Targets[0].HealthStatus[0].Status) 1646 } 1647 } 1648 } 1649 }) 1650 1651 t.Run("ip target", func(t *testing.T) { 1652 var s schema.LoadBalancerTarget 1653 1654 data := []byte(`{ 1655 "type": "ip", 1656 "ip": { 1657 "ip": "1.2.3.4" 1658 } 1659 }`) 1660 if err := json.Unmarshal(data, &s); err != nil { 1661 t.Fatal(err) 1662 } 1663 lbTgt := LoadBalancerTargetFromSchema(s) 1664 if lbTgt.Type != LoadBalancerTargetTypeIP { 1665 t.Errorf("unexpected Type: %s", lbTgt.Type) 1666 } 1667 if lbTgt.IP.IP != "1.2.3.4" { 1668 t.Errorf("unexpected IP: %s", lbTgt.IP.IP) 1669 } 1670 }) 1671} 1672 1673func TestCertificateFromSchema(t *testing.T) { 1674 data := []byte(`{ 1675 "id": 897, 1676 "name": "my website cert", 1677 "labels": {}, 1678 "certificate": "-----BEGIN CERTIFICATE-----\n...", 1679 "created": "2016-01-30T23:50:00+00:00", 1680 "not_valid_before": "2016-01-30T23:51:00+00:00", 1681 "not_valid_after": "2016-01-30T23:55:00+00:00", 1682 "domain_names": [ 1683 "example.com", 1684 "webmail.example.com", 1685 "www.example.com" 1686 ], 1687 "fingerprint": "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f", 1688 "used_by": [ 1689 { 1690 "id": 42, 1691 "type": "server" 1692 } 1693 ] 1694 } 1695`) 1696 var s schema.Certificate 1697 if err := json.Unmarshal(data, &s); err != nil { 1698 t.Fatal(err) 1699 } 1700 certificate := CertificateFromSchema(s) 1701 1702 if certificate.ID != 897 { 1703 t.Errorf("unexpected ID: %v", certificate.ID) 1704 } 1705 if certificate.Name != "my website cert" { 1706 t.Errorf("unexpected Name: %v", certificate.Name) 1707 } 1708 if certificate.Certificate != "-----BEGIN CERTIFICATE-----\n..." { 1709 t.Errorf("unexpected Certificate: %v", certificate.Certificate) 1710 } 1711 if !certificate.Created.Equal(time.Date(2016, 01, 30, 23, 50, 00, 0, time.UTC)) { 1712 t.Errorf("unexpected created date: %v", certificate.Created) 1713 } 1714 if !certificate.NotValidBefore.Equal(time.Date(2016, 01, 30, 23, 51, 00, 0, time.UTC)) { 1715 t.Errorf("unexpected NotValidBefore: %v", certificate.NotValidBefore) 1716 } 1717 if !certificate.NotValidAfter.Equal(time.Date(2016, 01, 30, 23, 55, 00, 0, time.UTC)) { 1718 t.Errorf("unexpected NotValidAfter: %v", certificate.NotValidAfter) 1719 } 1720 if len(certificate.DomainNames) != 3 { 1721 t.Errorf("unexpected DomainNames length: %v", len(certificate.DomainNames)) 1722 } else { 1723 if certificate.DomainNames[0] != "example.com" { 1724 t.Errorf("unexpected DomainNames[0]: %v", certificate.DomainNames[0]) 1725 } 1726 if certificate.DomainNames[1] != "webmail.example.com" { 1727 t.Errorf("unexpected DomainNames[1]: %v", certificate.DomainNames[1]) 1728 } 1729 if certificate.DomainNames[2] != "www.example.com" { 1730 t.Errorf("unexpected DomainNames[2]: %v", certificate.DomainNames[2]) 1731 } 1732 } 1733 if certificate.Fingerprint != "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f" { 1734 t.Errorf("unexpected Fingerprint: %v", certificate.Fingerprint) 1735 } 1736} 1737 1738func TestPricingFromSchema(t *testing.T) { 1739 data := []byte(`{ 1740 "currency": "EUR", 1741 "vat_rate": "19.00", 1742 "image": { 1743 "price_per_gb_month": { 1744 "net": "1", 1745 "gross": "1.19" 1746 } 1747 }, 1748 "floating_ip": { 1749 "price_monthly": { 1750 "net": "1", 1751 "gross": "1.19" 1752 } 1753 }, 1754 "traffic": { 1755 "price_per_tb": { 1756 "net": "1", 1757 "gross": "1.19" 1758 } 1759 }, 1760 "server_backup": { 1761 "percentage": "20" 1762 }, 1763 "server_types": [ 1764 { 1765 "id": 4, 1766 "name": "CX11", 1767 "prices": [ 1768 { 1769 "location": "fsn1", 1770 "price_hourly": { 1771 "net": "1", 1772 "gross": "1.19" 1773 }, 1774 "price_monthly": { 1775 "net": "1", 1776 "gross": "1.19" 1777 } 1778 } 1779 ] 1780 } 1781 ], 1782 "load_balancer_types": [ 1783 { 1784 "id": 4, 1785 "name": "LX11", 1786 "prices": [ 1787 { 1788 "location": "fsn1", 1789 "price_hourly": { 1790 "net": "1", 1791 "gross": "1.19" 1792 }, 1793 "price_monthly": { 1794 "net": "1", 1795 "gross": "1.19" 1796 } 1797 } 1798 ] 1799 } 1800 ], 1801 "volume": { 1802 "price_per_gb_month": { 1803 "net": "1", 1804 "gross": "1.19" 1805 } 1806 } 1807 }`) 1808 1809 var s schema.Pricing 1810 if err := json.Unmarshal(data, &s); err != nil { 1811 t.Fatal(err) 1812 } 1813 pricing := PricingFromSchema(s) 1814 1815 if pricing.Image.PerGBMonth.Currency != "EUR" { 1816 t.Errorf("unexpected Image.PerGBMonth.Currency: %v", pricing.Image.PerGBMonth.Currency) 1817 } 1818 if pricing.Image.PerGBMonth.VATRate != "19.00" { 1819 t.Errorf("unexpected Image.PerGBMonth.VATRate: %v", pricing.Image.PerGBMonth.VATRate) 1820 } 1821 if pricing.Image.PerGBMonth.Net != "1" { 1822 t.Errorf("unexpected Image.PerGBMonth.Net: %v", pricing.Image.PerGBMonth.Net) 1823 } 1824 if pricing.Image.PerGBMonth.Gross != "1.19" { 1825 t.Errorf("unexpected Image.PerGBMonth.Gross: %v", pricing.Image.PerGBMonth.Gross) 1826 } 1827 1828 if pricing.FloatingIP.Monthly.Currency != "EUR" { 1829 t.Errorf("unexpected FloatingIP.Monthly.Currency: %v", pricing.FloatingIP.Monthly.Currency) 1830 } 1831 if pricing.FloatingIP.Monthly.VATRate != "19.00" { 1832 t.Errorf("unexpected FloatingIP.Monthly.VATRate: %v", pricing.FloatingIP.Monthly.VATRate) 1833 } 1834 if pricing.FloatingIP.Monthly.Net != "1" { 1835 t.Errorf("unexpected FloatingIP.Monthly.Net: %v", pricing.FloatingIP.Monthly.Net) 1836 } 1837 if pricing.FloatingIP.Monthly.Gross != "1.19" { 1838 t.Errorf("unexpected FloatingIP.Monthly.Gross: %v", pricing.FloatingIP.Monthly.Gross) 1839 } 1840 1841 if pricing.Volume.PerGBMonthly.Currency != "EUR" { 1842 t.Errorf("unexpected Traffic.PerTB.Currency: %v", pricing.Volume.PerGBMonthly.Currency) 1843 } 1844 if pricing.Volume.PerGBMonthly.VATRate != "19.00" { 1845 t.Errorf("unexpected Traffic.PerTB.VATRate: %v", pricing.Volume.PerGBMonthly.VATRate) 1846 } 1847 if pricing.Volume.PerGBMonthly.Net != "1" { 1848 t.Errorf("unexpected Traffic.PerTB.Net: %v", pricing.Volume.PerGBMonthly.Net) 1849 } 1850 if pricing.Volume.PerGBMonthly.Gross != "1.19" { 1851 t.Errorf("unexpected Traffic.PerTB.Gross: %v", pricing.Volume.PerGBMonthly.Gross) 1852 } 1853 1854 if pricing.Traffic.PerTB.Currency != "EUR" { 1855 t.Errorf("unexpected Traffic.PerTB.Currency: %v", pricing.Traffic.PerTB.Currency) 1856 } 1857 if pricing.Traffic.PerTB.VATRate != "19.00" { 1858 t.Errorf("unexpected Traffic.PerTB.VATRate: %v", pricing.Traffic.PerTB.VATRate) 1859 } 1860 if pricing.Traffic.PerTB.Net != "1" { 1861 t.Errorf("unexpected Traffic.PerTB.Net: %v", pricing.Traffic.PerTB.Net) 1862 } 1863 if pricing.Traffic.PerTB.Gross != "1.19" { 1864 t.Errorf("unexpected Traffic.PerTB.Gross: %v", pricing.Traffic.PerTB.Gross) 1865 } 1866 1867 if pricing.ServerBackup.Percentage != "20" { 1868 t.Errorf("unexpected ServerBackup.Percentage: %v", pricing.ServerBackup.Percentage) 1869 } 1870 1871 if len(pricing.ServerTypes) != 1 { 1872 t.Errorf("unexpected number of server types: %d", len(pricing.ServerTypes)) 1873 } else { 1874 p := pricing.ServerTypes[0] 1875 1876 if p.ServerType.ID != 4 { 1877 t.Errorf("unexpected ServerType.ID: %d", p.ServerType.ID) 1878 } 1879 if p.ServerType.Name != "CX11" { 1880 t.Errorf("unexpected ServerType.Name: %v", p.ServerType.Name) 1881 } 1882 1883 if len(p.Pricings) != 1 { 1884 t.Errorf("unexpected number of prices: %d", len(p.Pricings)) 1885 } else { 1886 if p.Pricings[0].Location.Name != "fsn1" { 1887 t.Errorf("unexpected Location.Name: %v", p.Pricings[0].Location.Name) 1888 } 1889 1890 if p.Pricings[0].Hourly.Currency != "EUR" { 1891 t.Errorf("unexpected Hourly.Currency: %v", p.Pricings[0].Hourly.Currency) 1892 } 1893 if p.Pricings[0].Hourly.VATRate != "19.00" { 1894 t.Errorf("unexpected Hourly.VATRate: %v", p.Pricings[0].Hourly.VATRate) 1895 } 1896 if p.Pricings[0].Hourly.Net != "1" { 1897 t.Errorf("unexpected Hourly.Net: %v", p.Pricings[0].Hourly.Net) 1898 } 1899 if p.Pricings[0].Hourly.Gross != "1.19" { 1900 t.Errorf("unexpected Hourly.Gross: %v", p.Pricings[0].Hourly.Gross) 1901 } 1902 1903 if p.Pricings[0].Monthly.Currency != "EUR" { 1904 t.Errorf("unexpected Monthly.Currency: %v", p.Pricings[0].Monthly.Currency) 1905 } 1906 if p.Pricings[0].Monthly.VATRate != "19.00" { 1907 t.Errorf("unexpected Monthly.VATRate: %v", p.Pricings[0].Monthly.VATRate) 1908 } 1909 if p.Pricings[0].Monthly.Net != "1" { 1910 t.Errorf("unexpected Monthly.Net: %v", p.Pricings[0].Monthly.Net) 1911 } 1912 if p.Pricings[0].Monthly.Gross != "1.19" { 1913 t.Errorf("unexpected Monthly.Gross: %v", p.Pricings[0].Monthly.Gross) 1914 } 1915 } 1916 } 1917 1918 if len(pricing.LoadBalancerTypes) != 1 { 1919 t.Errorf("unexpected number of Load Balancer types: %d", len(pricing.LoadBalancerTypes)) 1920 } else { 1921 p := pricing.LoadBalancerTypes[0] 1922 1923 if p.LoadBalancerType.ID != 4 { 1924 t.Errorf("unexpected LoadBalancerType.ID: %d", p.LoadBalancerType.ID) 1925 } 1926 if p.LoadBalancerType.Name != "LX11" { 1927 t.Errorf("unexpected LoadBalancerType.Name: %v", p.LoadBalancerType.Name) 1928 } 1929 1930 if len(p.Pricings) != 1 { 1931 t.Errorf("unexpected number of prices: %d", len(p.Pricings)) 1932 } else { 1933 if p.Pricings[0].Location.Name != "fsn1" { 1934 t.Errorf("unexpected Location.Name: %v", p.Pricings[0].Location.Name) 1935 } 1936 1937 if p.Pricings[0].Hourly.Currency != "EUR" { 1938 t.Errorf("unexpected Hourly.Currency: %v", p.Pricings[0].Hourly.Currency) 1939 } 1940 if p.Pricings[0].Hourly.VATRate != "19.00" { 1941 t.Errorf("unexpected Hourly.VATRate: %v", p.Pricings[0].Hourly.VATRate) 1942 } 1943 if p.Pricings[0].Hourly.Net != "1" { 1944 t.Errorf("unexpected Hourly.Net: %v", p.Pricings[0].Hourly.Net) 1945 } 1946 if p.Pricings[0].Hourly.Gross != "1.19" { 1947 t.Errorf("unexpected Hourly.Gross: %v", p.Pricings[0].Hourly.Gross) 1948 } 1949 1950 if p.Pricings[0].Monthly.Currency != "EUR" { 1951 t.Errorf("unexpected Monthly.Currency: %v", p.Pricings[0].Monthly.Currency) 1952 } 1953 if p.Pricings[0].Monthly.VATRate != "19.00" { 1954 t.Errorf("unexpected Monthly.VATRate: %v", p.Pricings[0].Monthly.VATRate) 1955 } 1956 if p.Pricings[0].Monthly.Net != "1" { 1957 t.Errorf("unexpected Monthly.Net: %v", p.Pricings[0].Monthly.Net) 1958 } 1959 if p.Pricings[0].Monthly.Gross != "1.19" { 1960 t.Errorf("unexpected Monthly.Gross: %v", p.Pricings[0].Monthly.Gross) 1961 } 1962 } 1963 } 1964} 1965 1966func TestLoadBalancerCreateOptsToSchema(t *testing.T) { 1967 testCases := map[string]struct { 1968 Opts LoadBalancerCreateOpts 1969 Request schema.LoadBalancerCreateRequest 1970 }{ 1971 "minimal": { 1972 Opts: LoadBalancerCreateOpts{ 1973 Name: "test", 1974 LoadBalancerType: &LoadBalancerType{Name: "lb11"}, 1975 Algorithm: &LoadBalancerAlgorithm{Type: LoadBalancerAlgorithmTypeRoundRobin}, 1976 NetworkZone: NetworkZoneEUCentral, 1977 }, 1978 Request: schema.LoadBalancerCreateRequest{ 1979 Name: "test", 1980 LoadBalancerType: "lb11", 1981 Algorithm: &schema.LoadBalancerCreateRequestAlgorithm{ 1982 Type: string(LoadBalancerAlgorithmTypeRoundRobin), 1983 }, 1984 NetworkZone: String(string(NetworkZoneEUCentral)), 1985 }, 1986 }, 1987 "all set": { 1988 Opts: LoadBalancerCreateOpts{ 1989 Name: "test", 1990 LoadBalancerType: &LoadBalancerType{Name: "lb11"}, 1991 Algorithm: &LoadBalancerAlgorithm{Type: LoadBalancerAlgorithmTypeRoundRobin}, 1992 NetworkZone: NetworkZoneEUCentral, 1993 Labels: map[string]string{"foo": "bar"}, 1994 PublicInterface: Bool(true), 1995 Network: &Network{ID: 3}, 1996 Services: []LoadBalancerCreateOptsService{ 1997 { 1998 Protocol: LoadBalancerServiceProtocolHTTP, 1999 DestinationPort: Int(80), 2000 Proxyprotocol: Bool(true), 2001 HTTP: &LoadBalancerCreateOptsServiceHTTP{ 2002 CookieName: String("keks"), 2003 CookieLifetime: Duration(5 * time.Minute), 2004 RedirectHTTP: Bool(true), 2005 StickySessions: Bool(true), 2006 Certificates: []*Certificate{{ID: 1}, {ID: 2}}, 2007 }, 2008 HealthCheck: &LoadBalancerCreateOptsServiceHealthCheck{ 2009 Protocol: LoadBalancerServiceProtocolHTTP, 2010 Port: Int(80), 2011 Interval: Duration(5 * time.Second), 2012 Timeout: Duration(1 * time.Second), 2013 Retries: Int(3), 2014 HTTP: &LoadBalancerCreateOptsServiceHealthCheckHTTP{ 2015 Domain: String("example.com"), 2016 Path: String("/health"), 2017 Response: String("ok"), 2018 StatusCodes: []string{"2??", "3??"}, 2019 TLS: Bool(true), 2020 }, 2021 }, 2022 }, 2023 }, 2024 Targets: []LoadBalancerCreateOptsTarget{ 2025 { 2026 Type: LoadBalancerTargetTypeServer, 2027 Server: LoadBalancerCreateOptsTargetServer{ 2028 Server: &Server{ID: 5}, 2029 }, 2030 }, 2031 { 2032 Type: LoadBalancerTargetTypeIP, 2033 IP: LoadBalancerCreateOptsTargetIP{IP: "1.2.3.4"}, 2034 }, 2035 }, 2036 }, 2037 Request: schema.LoadBalancerCreateRequest{ 2038 Name: "test", 2039 LoadBalancerType: "lb11", 2040 Algorithm: &schema.LoadBalancerCreateRequestAlgorithm{ 2041 Type: string(LoadBalancerAlgorithmTypeRoundRobin), 2042 }, 2043 NetworkZone: String(string(NetworkZoneEUCentral)), 2044 Labels: func() *map[string]string { 2045 labels := map[string]string{"foo": "bar"} 2046 return &labels 2047 }(), 2048 PublicInterface: Bool(true), 2049 Network: Int(3), 2050 Services: []schema.LoadBalancerCreateRequestService{ 2051 { 2052 Protocol: string(LoadBalancerServiceProtocolHTTP), 2053 DestinationPort: Int(80), 2054 Proxyprotocol: Bool(true), 2055 HTTP: &schema.LoadBalancerCreateRequestServiceHTTP{ 2056 CookieName: String("keks"), 2057 CookieLifetime: Int(5 * 60), 2058 RedirectHTTP: Bool(true), 2059 StickySessions: Bool(true), 2060 Certificates: intSlice([]int{1, 2}), 2061 }, 2062 HealthCheck: &schema.LoadBalancerCreateRequestServiceHealthCheck{ 2063 Protocol: string(LoadBalancerServiceProtocolHTTP), 2064 Port: Int(80), 2065 Interval: Int(5), 2066 Timeout: Int(1), 2067 Retries: Int(3), 2068 HTTP: &schema.LoadBalancerCreateRequestServiceHealthCheckHTTP{ 2069 Domain: String("example.com"), 2070 Path: String("/health"), 2071 Response: String("ok"), 2072 StatusCodes: stringSlice([]string{"2??", "3??"}), 2073 TLS: Bool(true), 2074 }, 2075 }, 2076 }, 2077 }, 2078 Targets: []schema.LoadBalancerCreateRequestTarget{ 2079 { 2080 Type: "server", 2081 Server: &schema.LoadBalancerCreateRequestTargetServer{ 2082 ID: 5, 2083 }, 2084 }, 2085 { 2086 Type: "ip", 2087 IP: &schema.LoadBalancerCreateRequestTargetIP{ 2088 IP: "1.2.3.4", 2089 }, 2090 }, 2091 }, 2092 }, 2093 }, 2094 } 2095 for name, testCase := range testCases { 2096 t.Run(name, func(t *testing.T) { 2097 req := loadBalancerCreateOptsToSchema(testCase.Opts) 2098 if !cmp.Equal(testCase.Request, req) { 2099 t.Log(cmp.Diff(testCase.Request, req)) 2100 t.Fail() 2101 } 2102 }) 2103 } 2104} 2105 2106func TestLoadBalancerAddServiceOptsToSchema(t *testing.T) { 2107 testCases := map[string]struct { 2108 Opts LoadBalancerAddServiceOpts 2109 Request schema.LoadBalancerActionAddServiceRequest 2110 }{ 2111 "minimal": { 2112 Opts: LoadBalancerAddServiceOpts{ 2113 Protocol: LoadBalancerServiceProtocolHTTP, 2114 }, 2115 Request: schema.LoadBalancerActionAddServiceRequest{ 2116 Protocol: string(LoadBalancerServiceProtocolHTTP), 2117 }, 2118 }, 2119 "all set": { 2120 Opts: LoadBalancerAddServiceOpts{ 2121 Protocol: LoadBalancerServiceProtocolHTTP, 2122 DestinationPort: Int(80), 2123 Proxyprotocol: Bool(true), 2124 HTTP: &LoadBalancerAddServiceOptsHTTP{ 2125 CookieName: String("keks"), 2126 CookieLifetime: Duration(5 * time.Minute), 2127 RedirectHTTP: Bool(true), 2128 StickySessions: Bool(true), 2129 Certificates: []*Certificate{{ID: 1}, {ID: 2}}, 2130 }, 2131 HealthCheck: &LoadBalancerAddServiceOptsHealthCheck{ 2132 Protocol: LoadBalancerServiceProtocolHTTP, 2133 Port: Int(80), 2134 Interval: Duration(5 * time.Second), 2135 Timeout: Duration(1 * time.Second), 2136 Retries: Int(3), 2137 HTTP: &LoadBalancerAddServiceOptsHealthCheckHTTP{ 2138 Domain: String("example.com"), 2139 Path: String("/health"), 2140 Response: String("ok"), 2141 StatusCodes: []string{"2??", "3??"}, 2142 TLS: Bool(true), 2143 }, 2144 }, 2145 }, 2146 Request: schema.LoadBalancerActionAddServiceRequest{ 2147 Protocol: string(LoadBalancerServiceProtocolHTTP), 2148 DestinationPort: Int(80), 2149 Proxyprotocol: Bool(true), 2150 HTTP: &schema.LoadBalancerActionAddServiceRequestHTTP{ 2151 CookieName: String("keks"), 2152 CookieLifetime: Int(5 * 60), 2153 RedirectHTTP: Bool(true), 2154 StickySessions: Bool(true), 2155 Certificates: intSlice([]int{1, 2}), 2156 }, 2157 HealthCheck: &schema.LoadBalancerActionAddServiceRequestHealthCheck{ 2158 Protocol: string(LoadBalancerServiceProtocolHTTP), 2159 Port: Int(80), 2160 Interval: Int(5), 2161 Timeout: Int(1), 2162 Retries: Int(3), 2163 HTTP: &schema.LoadBalancerActionAddServiceRequestHealthCheckHTTP{ 2164 Domain: String("example.com"), 2165 Path: String("/health"), 2166 Response: String("ok"), 2167 StatusCodes: stringSlice([]string{"2??", "3??"}), 2168 TLS: Bool(true), 2169 }, 2170 }, 2171 }, 2172 }, 2173 "no health check": { 2174 Opts: LoadBalancerAddServiceOpts{ 2175 Protocol: LoadBalancerServiceProtocolHTTP, 2176 DestinationPort: Int(80), 2177 Proxyprotocol: Bool(true), 2178 HTTP: &LoadBalancerAddServiceOptsHTTP{ 2179 CookieName: String("keks"), 2180 CookieLifetime: Duration(5 * time.Minute), 2181 RedirectHTTP: Bool(true), 2182 StickySessions: Bool(true), 2183 Certificates: []*Certificate{{ID: 1}, {ID: 2}}, 2184 }, 2185 }, 2186 Request: schema.LoadBalancerActionAddServiceRequest{ 2187 Protocol: string(LoadBalancerServiceProtocolHTTP), 2188 DestinationPort: Int(80), 2189 Proxyprotocol: Bool(true), 2190 HTTP: &schema.LoadBalancerActionAddServiceRequestHTTP{ 2191 CookieName: String("keks"), 2192 CookieLifetime: Int(5 * 60), 2193 RedirectHTTP: Bool(true), 2194 StickySessions: Bool(true), 2195 Certificates: intSlice([]int{1, 2}), 2196 }, 2197 HealthCheck: nil, 2198 }, 2199 }, 2200 } 2201 for name, testCase := range testCases { 2202 t.Run(name, func(t *testing.T) { 2203 req := loadBalancerAddServiceOptsToSchema(testCase.Opts) 2204 if !cmp.Equal(testCase.Request, req) { 2205 t.Log(cmp.Diff(testCase.Request, req)) 2206 t.Fail() 2207 } 2208 }) 2209 } 2210} 2211 2212func TestLoadBalancerUpdateServiceOptsToSchema(t *testing.T) { 2213 testCases := map[string]struct { 2214 Opts LoadBalancerUpdateServiceOpts 2215 Request schema.LoadBalancerActionUpdateServiceRequest 2216 }{ 2217 "empty": { 2218 Opts: LoadBalancerUpdateServiceOpts{}, 2219 Request: schema.LoadBalancerActionUpdateServiceRequest{}, 2220 }, 2221 "all set": { 2222 Opts: LoadBalancerUpdateServiceOpts{ 2223 Protocol: LoadBalancerServiceProtocolHTTP, 2224 DestinationPort: Int(80), 2225 Proxyprotocol: Bool(true), 2226 HTTP: &LoadBalancerUpdateServiceOptsHTTP{ 2227 CookieName: String("keks"), 2228 CookieLifetime: Duration(5 * time.Minute), 2229 RedirectHTTP: Bool(true), 2230 StickySessions: Bool(true), 2231 Certificates: []*Certificate{{ID: 1}, {ID: 2}}, 2232 }, 2233 HealthCheck: &LoadBalancerUpdateServiceOptsHealthCheck{ 2234 Protocol: LoadBalancerServiceProtocolHTTP, 2235 Port: Int(80), 2236 Interval: Duration(5 * time.Second), 2237 Timeout: Duration(1 * time.Second), 2238 Retries: Int(3), 2239 HTTP: &LoadBalancerUpdateServiceOptsHealthCheckHTTP{ 2240 Domain: String("example.com"), 2241 Path: String("/health"), 2242 Response: String("ok"), 2243 StatusCodes: []string{"2??", "3??"}, 2244 TLS: Bool(true), 2245 }, 2246 }, 2247 }, 2248 Request: schema.LoadBalancerActionUpdateServiceRequest{ 2249 Protocol: String(string(LoadBalancerServiceProtocolHTTP)), 2250 DestinationPort: Int(80), 2251 Proxyprotocol: Bool(true), 2252 HTTP: &schema.LoadBalancerActionUpdateServiceRequestHTTP{ 2253 CookieName: String("keks"), 2254 CookieLifetime: Int(5 * 60), 2255 RedirectHTTP: Bool(true), 2256 StickySessions: Bool(true), 2257 Certificates: intSlice([]int{1, 2}), 2258 }, 2259 HealthCheck: &schema.LoadBalancerActionUpdateServiceRequestHealthCheck{ 2260 Protocol: String(string(LoadBalancerServiceProtocolHTTP)), 2261 Port: Int(80), 2262 Interval: Int(5), 2263 Timeout: Int(1), 2264 Retries: Int(3), 2265 HTTP: &schema.LoadBalancerActionUpdateServiceRequestHealthCheckHTTP{ 2266 Domain: String("example.com"), 2267 Path: String("/health"), 2268 Response: String("ok"), 2269 StatusCodes: stringSlice([]string{"2??", "3??"}), 2270 TLS: Bool(true), 2271 }, 2272 }, 2273 }, 2274 }, 2275 "no health check": { 2276 Opts: LoadBalancerUpdateServiceOpts{ 2277 Protocol: LoadBalancerServiceProtocolHTTP, 2278 DestinationPort: Int(80), 2279 Proxyprotocol: Bool(true), 2280 HTTP: &LoadBalancerUpdateServiceOptsHTTP{ 2281 CookieName: String("keks"), 2282 CookieLifetime: Duration(5 * time.Minute), 2283 RedirectHTTP: Bool(true), 2284 StickySessions: Bool(true), 2285 Certificates: []*Certificate{{ID: 1}, {ID: 2}}, 2286 }, 2287 }, 2288 Request: schema.LoadBalancerActionUpdateServiceRequest{ 2289 Protocol: String(string(LoadBalancerServiceProtocolHTTP)), 2290 DestinationPort: Int(80), 2291 Proxyprotocol: Bool(true), 2292 HTTP: &schema.LoadBalancerActionUpdateServiceRequestHTTP{ 2293 CookieName: String("keks"), 2294 CookieLifetime: Int(5 * 60), 2295 RedirectHTTP: Bool(true), 2296 StickySessions: Bool(true), 2297 Certificates: intSlice([]int{1, 2}), 2298 }, 2299 HealthCheck: nil, 2300 }, 2301 }, 2302 } 2303 for name, testCase := range testCases { 2304 t.Run(name, func(t *testing.T) { 2305 req := loadBalancerUpdateServiceOptsToSchema(testCase.Opts) 2306 if !cmp.Equal(testCase.Request, req) { 2307 t.Log(cmp.Diff(testCase.Request, req)) 2308 t.Fail() 2309 } 2310 }) 2311 } 2312} 2313 2314func TestServerMetricsFromSchema(t *testing.T) { 2315 tests := []struct { 2316 name string 2317 respFn func() *schema.ServerGetMetricsResponse 2318 expected *ServerMetrics 2319 expectedErr string 2320 }{ 2321 { 2322 name: "values not tuples", 2323 respFn: func() *schema.ServerGetMetricsResponse { 2324 var resp schema.ServerGetMetricsResponse 2325 2326 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2327 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2328 resp.Metrics.TimeSeries = map[string]schema.ServerTimeSeriesVals{ 2329 "cpu": { 2330 Values: []interface{}{"some value"}, 2331 }, 2332 } 2333 2334 return &resp 2335 }, 2336 expectedErr: "failed to convert value to tuple: some value", 2337 }, 2338 { 2339 name: "invalid tuple size", 2340 respFn: func() *schema.ServerGetMetricsResponse { 2341 var resp schema.ServerGetMetricsResponse 2342 2343 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2344 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2345 resp.Metrics.TimeSeries = map[string]schema.ServerTimeSeriesVals{ 2346 "cpu": { 2347 Values: []interface{}{ 2348 []interface{}{1435781471.622, "43", "something else"}, 2349 }, 2350 }, 2351 } 2352 2353 return &resp 2354 }, 2355 expectedErr: "invalid tuple size: 3: [1.435781471622e+09 43 something else]", 2356 }, 2357 { 2358 name: "invalid time stamp", 2359 respFn: func() *schema.ServerGetMetricsResponse { 2360 var resp schema.ServerGetMetricsResponse 2361 2362 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2363 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2364 resp.Metrics.TimeSeries = map[string]schema.ServerTimeSeriesVals{ 2365 "cpu": { 2366 Values: []interface{}{ 2367 []interface{}{"1435781471.622", "43"}, 2368 }, 2369 }, 2370 } 2371 2372 return &resp 2373 }, 2374 expectedErr: "convert to float64: 1435781471.622", 2375 }, 2376 { 2377 name: "invalid value", 2378 respFn: func() *schema.ServerGetMetricsResponse { 2379 var resp schema.ServerGetMetricsResponse 2380 2381 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2382 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2383 resp.Metrics.TimeSeries = map[string]schema.ServerTimeSeriesVals{ 2384 "cpu": { 2385 Values: []interface{}{ 2386 []interface{}{1435781471.622, 43}, 2387 }, 2388 }, 2389 } 2390 2391 return &resp 2392 }, 2393 expectedErr: "not a string: 43", 2394 }, 2395 { 2396 name: "valid response", 2397 respFn: func() *schema.ServerGetMetricsResponse { 2398 var resp schema.ServerGetMetricsResponse 2399 2400 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2401 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2402 resp.Metrics.TimeSeries = map[string]schema.ServerTimeSeriesVals{ 2403 "cpu": { 2404 Values: []interface{}{ 2405 []interface{}{1435781470.622, "42"}, 2406 []interface{}{1435781471.622, "43"}, 2407 }, 2408 }, 2409 "disk.0.iops.read": { 2410 Values: []interface{}{ 2411 []interface{}{1435781480.622, "100"}, 2412 []interface{}{1435781481.622, "150"}, 2413 }, 2414 }, 2415 "disk.0.iops.write": { 2416 Values: []interface{}{ 2417 []interface{}{1435781480.622, "50"}, 2418 []interface{}{1435781481.622, "55"}, 2419 }, 2420 }, 2421 "network.0.pps.in": { 2422 Values: []interface{}{ 2423 []interface{}{1435781490.622, "70"}, 2424 []interface{}{1435781491.622, "75"}, 2425 }, 2426 }, 2427 "network.0.pps.out": { 2428 Values: []interface{}{ 2429 []interface{}{1435781590.622, "60"}, 2430 []interface{}{1435781591.622, "65"}, 2431 }, 2432 }, 2433 } 2434 2435 return &resp 2436 }, 2437 expected: &ServerMetrics{ 2438 Start: mustParseTime(t, "2017-01-01T00:00:00Z"), 2439 End: mustParseTime(t, "2017-01-01T23:00:00Z"), 2440 TimeSeries: map[string][]ServerMetricsValue{ 2441 "cpu": { 2442 {Timestamp: 1435781470.622, Value: "42"}, 2443 {Timestamp: 1435781471.622, Value: "43"}, 2444 }, 2445 "disk.0.iops.read": { 2446 {Timestamp: 1435781480.622, Value: "100"}, 2447 {Timestamp: 1435781481.622, Value: "150"}, 2448 }, 2449 "disk.0.iops.write": { 2450 {Timestamp: 1435781480.622, Value: "50"}, 2451 {Timestamp: 1435781481.622, Value: "55"}, 2452 }, 2453 "network.0.pps.in": { 2454 {Timestamp: 1435781490.622, Value: "70"}, 2455 {Timestamp: 1435781491.622, Value: "75"}, 2456 }, 2457 "network.0.pps.out": { 2458 {Timestamp: 1435781590.622, Value: "60"}, 2459 {Timestamp: 1435781591.622, Value: "65"}, 2460 }, 2461 }, 2462 }, 2463 }, 2464 } 2465 2466 for _, tt := range tests { 2467 tt := tt 2468 t.Run(tt.name, func(t *testing.T) { 2469 resp := tt.respFn() 2470 actual, err := serverMetricsFromSchema(resp) 2471 if err != nil && tt.expectedErr == "" { 2472 t.Fatalf("expected no error; got: %v", err) 2473 } 2474 if err != nil && tt.expectedErr != err.Error() { 2475 t.Fatalf("expected error: %s; got: %v", tt.expectedErr, err) 2476 } 2477 if !cmp.Equal(tt.expected, actual) { 2478 t.Errorf("unexpected result:\n%s", cmp.Diff(tt.expected, actual)) 2479 } 2480 }) 2481 } 2482} 2483 2484func TestLoadBalancerMetricsFromSchema(t *testing.T) { 2485 tests := []struct { 2486 name string 2487 respFn func() *schema.LoadBalancerGetMetricsResponse 2488 expected *LoadBalancerMetrics 2489 expectedErr string 2490 }{ 2491 { 2492 name: "values not tuples", 2493 respFn: func() *schema.LoadBalancerGetMetricsResponse { 2494 var resp schema.LoadBalancerGetMetricsResponse 2495 2496 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2497 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2498 resp.Metrics.TimeSeries = map[string]schema.LoadBalancerTimeSeriesVals{ 2499 "open_connections": { 2500 Values: []interface{}{"some value"}, 2501 }, 2502 } 2503 2504 return &resp 2505 }, 2506 expectedErr: "failed to convert value to tuple: some value", 2507 }, 2508 { 2509 name: "invalid tuple size", 2510 respFn: func() *schema.LoadBalancerGetMetricsResponse { 2511 var resp schema.LoadBalancerGetMetricsResponse 2512 2513 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2514 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2515 resp.Metrics.TimeSeries = map[string]schema.LoadBalancerTimeSeriesVals{ 2516 "open_connections": { 2517 Values: []interface{}{ 2518 []interface{}{1435781471.622, "43", "something else"}, 2519 }, 2520 }, 2521 } 2522 2523 return &resp 2524 }, 2525 expectedErr: "invalid tuple size: 3: [1.435781471622e+09 43 something else]", 2526 }, 2527 { 2528 name: "invalid time stamp", 2529 respFn: func() *schema.LoadBalancerGetMetricsResponse { 2530 var resp schema.LoadBalancerGetMetricsResponse 2531 2532 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2533 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2534 resp.Metrics.TimeSeries = map[string]schema.LoadBalancerTimeSeriesVals{ 2535 "open_connections": { 2536 Values: []interface{}{ 2537 []interface{}{"1435781471.622", "43"}, 2538 }, 2539 }, 2540 } 2541 2542 return &resp 2543 }, 2544 expectedErr: "convert to float64: 1435781471.622", 2545 }, 2546 { 2547 name: "invalid value", 2548 respFn: func() *schema.LoadBalancerGetMetricsResponse { 2549 var resp schema.LoadBalancerGetMetricsResponse 2550 2551 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2552 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2553 resp.Metrics.TimeSeries = map[string]schema.LoadBalancerTimeSeriesVals{ 2554 "open_connections": { 2555 Values: []interface{}{ 2556 []interface{}{1435781471.622, 43}, 2557 }, 2558 }, 2559 } 2560 2561 return &resp 2562 }, 2563 expectedErr: "not a string: 43", 2564 }, 2565 { 2566 name: "valid response", 2567 respFn: func() *schema.LoadBalancerGetMetricsResponse { 2568 var resp schema.LoadBalancerGetMetricsResponse 2569 2570 resp.Metrics.Start = mustParseTime(t, "2017-01-01T00:00:00Z") 2571 resp.Metrics.End = mustParseTime(t, "2017-01-01T23:00:00Z") 2572 resp.Metrics.TimeSeries = map[string]schema.LoadBalancerTimeSeriesVals{ 2573 "open_connections": { 2574 Values: []interface{}{ 2575 []interface{}{1435781470.622, "42"}, 2576 []interface{}{1435781471.622, "43"}, 2577 }, 2578 }, 2579 "connections_per_second": { 2580 Values: []interface{}{ 2581 []interface{}{1435781480.622, "100"}, 2582 []interface{}{1435781481.622, "150"}, 2583 }, 2584 }, 2585 "requests_per_second": { 2586 Values: []interface{}{ 2587 []interface{}{1435781480.622, "50"}, 2588 []interface{}{1435781481.622, "55"}, 2589 }, 2590 }, 2591 "bandwidth.in": { 2592 Values: []interface{}{ 2593 []interface{}{1435781490.622, "70"}, 2594 []interface{}{1435781491.622, "75"}, 2595 }, 2596 }, 2597 "bandwidth.out": { 2598 Values: []interface{}{ 2599 []interface{}{1435781590.622, "60"}, 2600 []interface{}{1435781591.622, "65"}, 2601 }, 2602 }, 2603 } 2604 2605 return &resp 2606 }, 2607 expected: &LoadBalancerMetrics{ 2608 Start: mustParseTime(t, "2017-01-01T00:00:00Z"), 2609 End: mustParseTime(t, "2017-01-01T23:00:00Z"), 2610 TimeSeries: map[string][]LoadBalancerMetricsValue{ 2611 "open_connections": { 2612 {Timestamp: 1435781470.622, Value: "42"}, 2613 {Timestamp: 1435781471.622, Value: "43"}, 2614 }, 2615 "connections_per_second": { 2616 {Timestamp: 1435781480.622, Value: "100"}, 2617 {Timestamp: 1435781481.622, Value: "150"}, 2618 }, 2619 "requests_per_second": { 2620 {Timestamp: 1435781480.622, Value: "50"}, 2621 {Timestamp: 1435781481.622, Value: "55"}, 2622 }, 2623 "bandwidth.in": { 2624 {Timestamp: 1435781490.622, Value: "70"}, 2625 {Timestamp: 1435781491.622, Value: "75"}, 2626 }, 2627 "bandwidth.out": { 2628 {Timestamp: 1435781590.622, Value: "60"}, 2629 {Timestamp: 1435781591.622, Value: "65"}, 2630 }, 2631 }, 2632 }, 2633 }, 2634 } 2635 2636 for _, tt := range tests { 2637 tt := tt 2638 t.Run(tt.name, func(t *testing.T) { 2639 resp := tt.respFn() 2640 actual, err := loadBalancerMetricsFromSchema(resp) 2641 if err != nil && tt.expectedErr == "" { 2642 t.Fatalf("expected no error; got: %v", err) 2643 } 2644 if err != nil && tt.expectedErr != err.Error() { 2645 t.Fatalf("expected error: %s; got: %v", tt.expectedErr, err) 2646 } 2647 if !cmp.Equal(tt.expected, actual) { 2648 t.Errorf("unexpected result:\n%s", cmp.Diff(tt.expected, actual)) 2649 } 2650 }) 2651 } 2652} 2653 2654func TestFirewallFromSchema(t *testing.T) { 2655 data := []byte(`{ 2656 "id": 897, 2657 "name": "my firewall", 2658 "labels": { 2659 "key": "value", 2660 "key2": "value2" 2661 }, 2662 "created": "2016-01-30T23:50:00+00:00", 2663 "rules": [ 2664 { 2665 "direction": "in", 2666 "source_ips": [ 2667 "28.239.13.1/32", 2668 "28.239.14.0/24", 2669 "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" 2670 ], 2671 "destination_ips": [ 2672 "28.239.13.1/32", 2673 "28.239.14.0/24", 2674 "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" 2675 ], 2676 "protocol": "tcp", 2677 "port": "80" 2678 } 2679 ], 2680 "applied_to": [ 2681 { 2682 "server": { 2683 "id": 42 2684 }, 2685 "type": "server" 2686 } 2687 ] 2688 } 2689`) 2690 var f schema.Firewall 2691 if err := json.Unmarshal(data, &f); err != nil { 2692 t.Fatal(err) 2693 } 2694 firewall := FirewallFromSchema(f) 2695 2696 if firewall.ID != 897 { 2697 t.Errorf("unexpected ID: %v", firewall.ID) 2698 } 2699 if firewall.Name != "my firewall" { 2700 t.Errorf("unexpected Name: %v", firewall.Name) 2701 } 2702 if firewall.Labels["key"] != "value" || firewall.Labels["key2"] != "value2" { 2703 t.Errorf("unexpected Labels: %v", firewall.Labels) 2704 } 2705 if !firewall.Created.Equal(time.Date(2016, 01, 30, 23, 50, 00, 0, time.UTC)) { 2706 t.Errorf("unexpected Created date: %v", firewall.Created) 2707 } 2708 if len(firewall.Rules) != 1 { 2709 t.Errorf("unexpected Rules count: %d", len(firewall.Rules)) 2710 } 2711 if firewall.Rules[0].Direction != FirewallRuleDirectionIn { 2712 t.Errorf("unexpected Rule Direction: %s", firewall.Rules[0].Direction) 2713 } 2714 if len(firewall.Rules[0].SourceIPs) != 3 { 2715 t.Errorf("unexpected Rule SourceIPs count: %d", len(firewall.Rules[0].SourceIPs)) 2716 } 2717 if len(firewall.Rules[0].DestinationIPs) != 3 { 2718 t.Errorf("unexpected Rule DestinationIPs count: %d", len(firewall.Rules[0].DestinationIPs)) 2719 } 2720 if firewall.Rules[0].Protocol != FirewallRuleProtocolTCP { 2721 t.Errorf("unexpected Rule Protocol: %s", firewall.Rules[0].Protocol) 2722 } 2723 if *firewall.Rules[0].Port != "80" { 2724 t.Errorf("unexpected Rule Port: %s", *firewall.Rules[0].Port) 2725 } 2726 if len(firewall.AppliedTo) != 1 { 2727 t.Errorf("unexpected UsedBy count: %d", len(firewall.AppliedTo)) 2728 } 2729 if firewall.AppliedTo[0].Type != FirewallResourceTypeServer { 2730 t.Errorf("unexpected UsedBy Type: %s", firewall.AppliedTo[0].Type) 2731 } 2732 if firewall.AppliedTo[0].Server.ID != 42 { 2733 t.Errorf("unexpected UsedBy Server ID: %d", firewall.AppliedTo[0].Server.ID) 2734 } 2735} 2736