// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "errors" "testing" "time" "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" ) func TestAPI_OperatorAutopilotGetSetConfiguration(t *testing.T) { t.Parallel() c, s := makeClient(t) defer s.Stop() s.WaitForSerfCheck(t) operator := c.Operator() config, err := operator.AutopilotGetConfiguration(nil) if err != nil { t.Fatalf("err: %v", err) } if !config.CleanupDeadServers { t.Fatalf("bad: %v", config) } // Change a config setting newConf := &AutopilotConfiguration{CleanupDeadServers: false} if err := operator.AutopilotSetConfiguration(newConf, nil); err != nil { t.Fatalf("err: %v", err) } config, err = operator.AutopilotGetConfiguration(nil) if err != nil { t.Fatalf("err: %v", err) } if config.CleanupDeadServers { t.Fatalf("bad: %v", config) } } func TestAPI_OperatorAutopilotCASConfiguration(t *testing.T) { t.Parallel() c, s := makeClient(t) defer s.Stop() retry.Run(t, func(r *retry.R) { operator := c.Operator() config, err := operator.AutopilotGetConfiguration(nil) if err != nil { r.Fatalf("err: %v", err) } if !config.CleanupDeadServers { r.Fatalf("bad: %v", config) } // Pass an invalid ModifyIndex { newConf := &AutopilotConfiguration{ CleanupDeadServers: false, ModifyIndex: config.ModifyIndex - 1, } resp, err := operator.AutopilotCASConfiguration(newConf, nil) if err != nil { r.Fatalf("err: %v", err) } if resp { r.Fatalf("bad: %v", resp) } } // Pass a valid ModifyIndex { newConf := &AutopilotConfiguration{ CleanupDeadServers: false, ModifyIndex: config.ModifyIndex, } resp, err := operator.AutopilotCASConfiguration(newConf, nil) if err != nil { r.Fatalf("err: %v", err) } if !resp { r.Fatalf("bad: %v", resp) } } }) } func TestAPI_OperatorAutopilotServerHealth(t *testing.T) { t.Parallel() c, s := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) { c.RaftProtocol = 3 }) defer s.Stop() operator := c.Operator() retry.Run(t, func(r *retry.R) { out, err := operator.AutopilotServerHealth(nil) if err != nil { r.Fatalf("err: %v", err) } if len(out.Servers) != 1 || !out.Servers[0].Healthy || out.Servers[0].Name != s.Config.NodeName { r.Fatalf("bad: %v", out) } }) } func TestAPI_OperatorAutopilotState(t *testing.T) { c, s := makeClient(t) defer s.Stop() operator := c.Operator() retry.Run(t, func(r *retry.R) { out, err := operator.AutopilotState(nil) if err != nil { r.Fatalf("err: %v", err) } srv, ok := out.Servers[s.Config.NodeID] if !ok || !srv.Healthy || srv.Name != s.Config.NodeName { r.Fatalf("bad: %v", out) } }) } func TestAPI_OperatorAutopilotServerHealth_429(t *testing.T) { mapi, client := setupMockAPI(t) reply := OperatorHealthReply{ Healthy: false, FailureTolerance: 0, Servers: []ServerHealth{ { ID: "d9fdded2-27ae-4db2-9232-9d8d0114ac98", Name: "foo", Address: "198.18.0.1:8300", SerfStatus: "alive", Version: "1.8.3", Leader: true, LastContact: NewReadableDuration(0), LastTerm: 4, LastIndex: 99, Healthy: true, Voter: true, StableSince: time.Date(2020, 9, 2, 12, 0, 0, 0, time.UTC), }, { ID: "1bcdda01-b896-41bc-a763-1a62b4260777", Name: "bar", Address: "198.18.0.2:8300", SerfStatus: "alive", Version: "1.8.3", Leader: false, LastContact: NewReadableDuration(10 * time.Millisecond), LastTerm: 4, LastIndex: 99, Healthy: true, Voter: true, StableSince: time.Date(2020, 9, 2, 12, 0, 0, 0, time.UTC), }, { ID: "661d1eac-81be-436b-bfe1-d51ffd665b9d", Name: "baz", Address: "198.18.0.3:8300", SerfStatus: "failed", Version: "1.8.3", Leader: false, LastContact: NewReadableDuration(10 * time.Millisecond), LastTerm: 4, LastIndex: 99, Healthy: false, Voter: true, }, }, } mapi.withReply("GET", "/v1/operator/autopilot/health", nil, 429, reply).Once() out, err := client.Operator().AutopilotServerHealth(nil) require.NoError(t, err) require.Equal(t, &reply, out) mapi.withReply("GET", "/v1/operator/autopilot/health", nil, 500, nil).Once() _, err = client.Operator().AutopilotServerHealth(nil) var statusE StatusError if errors.As(err, &statusE) { require.Equal(t, 500, statusE.Code) } else { t.Error("Failed to unwrap error as StatusError") } }