From 00041d6fcca8af72dcfbbdf8748a80dc7502ab88 Mon Sep 17 00:00:00 2001 From: Aditya Saha Date: Tue, 9 Apr 2024 12:14:27 -0400 Subject: [PATCH] Add integration test cases --- commands/displayers/load_balancer.go | 7 +- commands/load_balancers.go | 20 +-- integration/glb_create_test.go | 185 +++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 integration/glb_create_test.go diff --git a/commands/displayers/load_balancer.go b/commands/displayers/load_balancer.go index 11dd53d17..8d8e3b34a 100644 --- a/commands/displayers/load_balancer.go +++ b/commands/displayers/load_balancer.go @@ -37,6 +37,7 @@ func (lb *LoadBalancer) Cols() []string { "ID", "IP", "Name", + "Type", "Status", "Created", "Region", @@ -58,6 +59,7 @@ func (lb *LoadBalancer) ColMap() map[string]string { "ID": "ID", "IP": "IP", "Name": "Name", + "Type": "Type", "Status": "Status", "Created": "Created At", "Region": "Region", @@ -87,9 +89,9 @@ func (lb *LoadBalancer) KV() []map[string]any { "ID": l.ID, "IP": l.IP, "Name": l.Name, + "Type": l.Type, "Status": l.Status, "Created": l.Created, - "Region": l.Region.Slug, "VPCUUID": l.VPCUUID, "Tag": l.Tag, "DropletIDs": strings.Trim(strings.Replace(fmt.Sprint(l.DropletIDs), " ", ",", -1), "[]"), @@ -99,6 +101,9 @@ func (lb *LoadBalancer) KV() []map[string]any { "ForwardingRules": strings.Join(forwardingRules, " "), "DisableLetsEncryptDNSRecords": toBool(l.DisableLetsEncryptDNSRecords), } + if l.Region != nil { + o["Region"] = l.Region.Slug + } if l.SizeSlug != "" { o["Size"] = l.SizeSlug } diff --git a/commands/load_balancers.go b/commands/load_balancers.go index 023b9c6f4..c75a9ebe0 100644 --- a/commands/load_balancers.go +++ b/commands/load_balancers.go @@ -59,7 +59,7 @@ With the load-balancer command, you can list, create, or delete load balancers, AddStringFlag(cmdLoadBalancerCreate, doctl.ArgLoadBalancerName, "", "", "The load balancer's name", requiredOpt()) AddStringFlag(cmdLoadBalancerCreate, doctl.ArgRegionSlug, "", "", - "The load balancer's region, e.g.: `nyc1`", requiredOpt()) + "The load balancer's region, e.g.: `nyc1`") AddStringFlag(cmdLoadBalancerCreate, doctl.ArgSizeSlug, "", "", fmt.Sprintf("The load balancer's size, e.g.: `lb-small`. Only one of %s and %s should be used", doctl.ArgSizeSlug, doctl.ArgSizeUnit)) AddIntFlag(cmdLoadBalancerCreate, doctl.ArgSizeUnit, "", 0, @@ -402,7 +402,7 @@ func RunLoadBalancerPurgeCache(c *CmdConfig) error { return err } - if force || AskForConfirmDelete("load balancer", 1) == nil { + if force || AskForConfirm("purge CDN cache for global load balancer") == nil { lbs := c.LoadBalancers() if err := lbs.PurgeCache(lbID); err != nil { return err @@ -423,7 +423,7 @@ func extractForwardingRules(s string) (forwardingRules []godo.ForwardingRule, er for _, v := range list { forwardingRule := new(godo.ForwardingRule) - if err := fillStructFromStringSliceArgs(forwardingRule, v); err != nil { + if err := fillStructFromStringSliceArgs(forwardingRule, v, ","); err != nil { return nil, err } @@ -440,7 +440,7 @@ func extractDomains(s []string) (domains []*godo.LBDomain, err error) { for _, v := range s { domain := new(godo.LBDomain) - if err := fillStructFromStringSliceArgs(domain, v); err != nil { + if err := fillStructFromStringSliceArgs(domain, v, " "); err != nil { return nil, err } @@ -450,12 +450,12 @@ func extractDomains(s []string) (domains []*godo.LBDomain, err error) { return domains, err } -func fillStructFromStringSliceArgs(obj any, s string) error { +func fillStructFromStringSliceArgs(obj any, s string, delimiter string) error { if len(s) == 0 { return nil } - kvs := strings.Split(s, ",") + kvs := strings.Split(s, delimiter) m := map[string]string{} for _, v := range kvs { @@ -589,7 +589,7 @@ func buildRequestFromArgs(c *CmdConfig, r *godo.LoadBalancerRequest) error { } stickySession := new(godo.StickySessions) - if err := fillStructFromStringSliceArgs(stickySession, ssa); err != nil { + if err := fillStructFromStringSliceArgs(stickySession, ssa, ","); err != nil { return err } r.StickySessions = stickySession @@ -600,7 +600,7 @@ func buildRequestFromArgs(c *CmdConfig, r *godo.LoadBalancerRequest) error { } healthCheck := new(godo.HealthCheck) - if err := fillStructFromStringSliceArgs(healthCheck, hca); err != nil { + if err := fillStructFromStringSliceArgs(healthCheck, hca, ","); err != nil { return err } r.HealthCheck = healthCheck @@ -667,7 +667,7 @@ func buildRequestFromArgs(c *CmdConfig, r *godo.LoadBalancerRequest) error { } glbSettings := new(godo.GLBSettings) - if err := fillStructFromStringSliceArgs(glbSettings, glbs); err != nil { + if err := fillStructFromStringSliceArgs(glbSettings, glbs, ","); err != nil { return err } if glbSettings.TargetProtocol != "" && glbSettings.TargetPort != 0 { @@ -680,7 +680,7 @@ func buildRequestFromArgs(c *CmdConfig, r *godo.LoadBalancerRequest) error { } cdnSettings := new(godo.CDNSettings) - if err := fillStructFromStringSliceArgs(cdnSettings, cdns); err != nil { + if err := fillStructFromStringSliceArgs(cdnSettings, cdns, ","); err != nil { return err } if r.GLBSettings != nil { diff --git a/integration/glb_create_test.go b/integration/glb_create_test.go new file mode 100644 index 000000000..2426e9d67 --- /dev/null +++ b/integration/glb_create_test.go @@ -0,0 +1,185 @@ +package integration + +import ( + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/http/httputil" + "os/exec" + "strings" + "testing" + + "github.com/sclevine/spec" + "github.com/stretchr/testify/require" +) + +var _ = suite("compute/load-balancer/create", func(t *testing.T, when spec.G, it spec.S) { + const testUUID = "4de7ac8b-495b-4884-9a69-1050c6793cd6" + var ( + expect *require.Assertions + server *httptest.Server + cmd *exec.Cmd + ) + + it.Before(func() { + expect = require.New(t) + + server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + switch req.URL.Path { + case "/v2/load_balancers": + auth := req.Header.Get("Authorization") + if auth != "Bearer some-magic-token" { + w.WriteHeader(http.StatusUnauthorized) + return + } + + if req.Method != http.MethodPost { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + reqBody, err := io.ReadAll(req.Body) + expect.NoError(err) + + expect.JSONEq(glbCreateRequest, string(reqBody)) + + w.Write([]byte(glbCreateResponse)) + default: + dump, err := httputil.DumpRequest(req, true) + if err != nil { + t.Fatal("failed to dump request") + } + + t.Fatalf("received unknown request: %s", dump) + } + })) + + cmd = exec.Command(builtBinaryPath, + "-t", "some-magic-token", + "-u", server.URL, + "compute", + "load-balancer", + ) + }) + + when("command is create with global config", func() { + it("creates a global load balancer", func() { + args := append([]string{"create"}, []string{ + "--name", "my-glb-name", + "--type", "GLOBAL", + "--domains", "name:test-domain-1 is_managed:true certificate_id:test-cert-id-1", + "--domains", "name:test-domain-2 is_managed:false certificate_id:test-cert-id-2", + "--glb-settings", "target_protocol:http,target_port:80", + "--glb-cdn-settings", "is_enabled:true", + "--target-lb-ids", "target-lb-id-1", + "--target-lb-ids", "target-lb-id-2", + }...) + cmd.Args = append(cmd.Args, args...) + + output, err := cmd.CombinedOutput() + expect.NoError(err, fmt.Sprintf("received error output: %s", output)) + expect.Equal(strings.TrimSpace(glbCreateOutput), strings.TrimSpace(string(output))) + }) + }) +}) + +const ( + glbCreateRequest = ` +{ + "name": "my-glb-name", + "algorithm": "round_robin", + "type": "GLOBAL", + "health_check": {}, + "sticky_sessions": {}, + "disable_lets_encrypt_dns_records": false, + "domains": [ + { + "name": "test-domain-1", + "is_managed": true, + "certificate_id": "test-cert-id-1" + }, + { + "name": "test-domain-2", + "is_managed": false, + "certificate_id": "test-cert-id-2" + } + ], + "glb_settings": { + "target_protocol": "http", + "target_port": 80, + "cdn": { + "is_enabled": true + } + }, + "target_load_balancer_ids": [ + "target-lb-id-1", + "target-lb-id-2" + ] +}` + glbCreateResponse = ` +{ + "load_balancer": { + "id": "cf9f1aa1-e1f8-4f3a-ad71-124c45e204b8", + "name": "my-glb-name", + "ip": "", + "size": "lb-small", + "size_unit": 1, + "type": "GLOBAL", + "algorithm": "round_robin", + "status": "new", + "created_at": "2024-04-09T16:10:11Z", + "forwarding_rules": [], + "health_check": { + "protocol": "http", + "port": 80, + "path": "/", + "check_interval_seconds": 10, + "response_timeout_seconds": 5, + "healthy_threshold": 5, + "unhealthy_threshold": 3 + }, + "sticky_sessions": { + "type": "none" + }, + "tag": "", + "droplet_ids": [], + "redirect_http_to_https": false, + "enable_proxy_protocol": false, + "enable_backend_keepalive": false, + "project_id": "1e02c6d8-aa24-477e-bc50-837b44e26cb3", + "disable_lets_encrypt_dns_records": false, + "http_idle_timeout_seconds": 60, + "domains": [ + { + "name": "test-domain-1", + "is_managed": true, + "certificate_id": "test-cert-id-1", + "status": "CREATING" + }, + { + "name": "test-domain-1-2", + "is_managed": false, + "certificate_id": "test-cert-id-2", + "status": "CREATING" + } + ], + "glb_settings": { + "target_protocol": "HTTP", + "target_port": 80, + "cdn": { + "is_enabled": true + } + }, + "target_load_balancer_ids": [ + "target-lb-id-1", + "target-lb-id-2" + ] + } +}` + glbCreateOutput = ` +Notice: Load balancer created +ID IP Name Type Status Created At Region Size Size Unit VPC UUID Tag Droplet IDs SSL Sticky Sessions Health Check Forwarding Rules Disable Lets Encrypt DNS Records +cf9f1aa1-e1f8-4f3a-ad71-124c45e204b8 my-glb-name GLOBAL new 2024-04-09T16:10:11Z lb-small 1 false type:none,cookie_name:,cookie_ttl_seconds:0 protocol:http,port:80,path:/,check_interval_seconds:10,response_timeout_seconds:5,healthy_threshold:5,unhealthy_threshold:3 false +` +)