[agent/claude:opus] DX audit and fix. 1) Review CLAUDE.md — update any outdate... #1
5 changed files with 389 additions and 9 deletions
|
|
@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||
|
||||
## Project Overview
|
||||
|
||||
`core/go-infra` provides infrastructure provider API clients (Hetzner Cloud, Hetzner Robot, CloudNS) and a YAML-based infrastructure configuration parser. Zero framework dependencies — stdlib + yaml only.
|
||||
`core/go-infra` provides infrastructure provider API clients (Hetzner Cloud, Hetzner Robot, CloudNS) and a YAML-based infrastructure configuration parser. Dependencies: `go-log` (error handling), `go-io` (file I/O), `yaml.v3`, and `testify` (tests).
|
||||
|
||||
## Build & Test
|
||||
|
||||
|
|
@ -35,6 +35,8 @@ These are subcommands for the parent `core` CLI, registered via `cli.RegisterCom
|
|||
## Coding Standards
|
||||
|
||||
- UK English in comments and strings
|
||||
- **Error handling**: Use `coreerr.E()` from `go-log`, never `fmt.Errorf` or `errors.New`
|
||||
- **File I/O**: Use `coreio.Local.Read()` from `go-io`, never `os.ReadFile`
|
||||
- Tests use `testify` (`assert` + `require`)
|
||||
- Test naming: `TestType_Method_Good`, `TestType_Method_Bad`, `TestType_Method_Ugly` suffixes (Good = happy path, Bad = expected errors, Ugly = edge cases)
|
||||
- Tests use `httptest.NewServer` for HTTP mocking — no mock libraries
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ func TestAPIClient_Do_Bad_ClientError(t *testing.T) {
|
|||
|
||||
err = c.Do(req, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "test-api 404")
|
||||
assert.Contains(t, err.Error(), "test-api: HTTP 404")
|
||||
assert.Contains(t, err.Error(), "not found")
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +226,7 @@ func TestAPIClient_Do_Bad_ExhaustsRetries(t *testing.T) {
|
|||
|
||||
err = c.Do(req, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "exhaust-test 500")
|
||||
assert.Contains(t, err.Error(), "exhaust-test: HTTP 500")
|
||||
// 1 initial + 2 retries = 3 attempts
|
||||
assert.Equal(t, int32(3), attempts.Load())
|
||||
}
|
||||
|
|
@ -476,7 +476,7 @@ func TestAPIClient_DoRaw_Bad_ClientError(t *testing.T) {
|
|||
|
||||
_, err = c.DoRaw(req)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "raw-test 403")
|
||||
assert.Contains(t, err.Error(), "raw-test: HTTP 403")
|
||||
}
|
||||
|
||||
func TestAPIClient_DoRaw_Good_RetriesServerError(t *testing.T) {
|
||||
|
|
|
|||
170
cloudns_test.go
170
cloudns_test.go
|
|
@ -78,7 +78,7 @@ func TestCloudNSClient_DoRaw_Bad_HTTPError(t *testing.T) {
|
|||
|
||||
_, err = client.doRaw(req)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "cloudns API 403")
|
||||
assert.Contains(t, err.Error(), "cloudns API: HTTP 403")
|
||||
}
|
||||
|
||||
func TestCloudNSClient_DoRaw_Bad_ServerError(t *testing.T) {
|
||||
|
|
@ -102,7 +102,7 @@ func TestCloudNSClient_DoRaw_Bad_ServerError(t *testing.T) {
|
|||
|
||||
_, err = client.doRaw(req)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "cloudns API 500")
|
||||
assert.Contains(t, err.Error(), "cloudns API: HTTP 500")
|
||||
}
|
||||
|
||||
// --- Zone JSON parsing ---
|
||||
|
|
@ -517,6 +517,172 @@ func TestCloudNSRecord_JSON_Good_EmptyMap(t *testing.T) {
|
|||
assert.Empty(t, records)
|
||||
}
|
||||
|
||||
// --- UpdateRecord round-trip ---
|
||||
|
||||
func TestCloudNSClient_UpdateRecord_Good_ViaDoRaw(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, http.MethodPost, r.Method)
|
||||
assert.Equal(t, "example.com", r.URL.Query().Get("domain-name"))
|
||||
assert.Equal(t, "42", r.URL.Query().Get("record-id"))
|
||||
assert.Equal(t, "www", r.URL.Query().Get("host"))
|
||||
assert.Equal(t, "A", r.URL.Query().Get("record-type"))
|
||||
assert.Equal(t, "5.6.7.8", r.URL.Query().Get("record"))
|
||||
assert.Equal(t, "3600", r.URL.Query().Get("ttl"))
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"status":"Success","statusDescription":"The record was updated successfully."}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewCloudNSClient("12345", "secret")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("cloudns API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
err := client.UpdateRecord(context.Background(), "example.com", "42", "www", "A", "5.6.7.8", 3600)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCloudNSClient_UpdateRecord_Bad_FailedStatus(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"status":"Failed","statusDescription":"Record not found."}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewCloudNSClient("12345", "secret")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("cloudns API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
err := client.UpdateRecord(context.Background(), "example.com", "999", "www", "A", "5.6.7.8", 3600)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "Record not found")
|
||||
}
|
||||
|
||||
// --- EnsureRecord round-trip ---
|
||||
|
||||
func TestCloudNSClient_EnsureRecord_Good_AlreadyCorrect(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"1":{"id":"1","type":"A","host":"www","record":"1.2.3.4","ttl":"3600","status":1}}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewCloudNSClient("12345", "secret")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("cloudns API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
changed, err := client.EnsureRecord(context.Background(), "example.com", "www", "A", "1.2.3.4", 3600)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, changed, "should not change when record already correct")
|
||||
}
|
||||
|
||||
func TestCloudNSClient_EnsureRecord_Good_NeedsUpdate(t *testing.T) {
|
||||
callCount := 0
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
callCount++
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if callCount == 1 {
|
||||
// ListRecords — returns existing record with old value
|
||||
_, _ = w.Write([]byte(`{"1":{"id":"1","type":"A","host":"www","record":"1.2.3.4","ttl":"3600","status":1}}`))
|
||||
} else {
|
||||
// UpdateRecord
|
||||
assert.Equal(t, http.MethodPost, r.Method)
|
||||
assert.Equal(t, "5.6.7.8", r.URL.Query().Get("record"))
|
||||
_, _ = w.Write([]byte(`{"status":"Success","statusDescription":"The record was updated successfully."}`))
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewCloudNSClient("12345", "secret")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("cloudns API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
changed, err := client.EnsureRecord(context.Background(), "example.com", "www", "A", "5.6.7.8", 3600)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, changed, "should change when record needs update")
|
||||
}
|
||||
|
||||
func TestCloudNSClient_EnsureRecord_Good_NeedsCreate(t *testing.T) {
|
||||
callCount := 0
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
callCount++
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if callCount == 1 {
|
||||
// ListRecords — no matching record
|
||||
_, _ = w.Write([]byte(`{"1":{"id":"1","type":"A","host":"other","record":"1.2.3.4","ttl":"3600","status":1}}`))
|
||||
} else {
|
||||
// CreateRecord
|
||||
assert.Equal(t, http.MethodPost, r.Method)
|
||||
assert.Equal(t, "www", r.URL.Query().Get("host"))
|
||||
_, _ = w.Write([]byte(`{"status":"Success","statusDescription":"The record was created successfully.","data":{"id":99}}`))
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewCloudNSClient("12345", "secret")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("cloudns API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
changed, err := client.EnsureRecord(context.Background(), "example.com", "www", "A", "1.2.3.4", 3600)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, changed, "should change when record needs to be created")
|
||||
}
|
||||
|
||||
// --- ClearACMEChallenge round-trip ---
|
||||
|
||||
func TestCloudNSClient_ClearACMEChallenge_Good_ViaDoRaw(t *testing.T) {
|
||||
callCount := 0
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
callCount++
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if callCount == 1 {
|
||||
// ListRecords — returns ACME challenge records
|
||||
_, _ = w.Write([]byte(`{
|
||||
"1":{"id":"1","type":"A","host":"www","record":"1.2.3.4","ttl":"3600","status":1},
|
||||
"2":{"id":"2","type":"TXT","host":"_acme-challenge","record":"token1","ttl":"60","status":1}
|
||||
}`))
|
||||
} else {
|
||||
// DeleteRecord
|
||||
assert.Equal(t, http.MethodPost, r.Method)
|
||||
assert.Equal(t, "2", r.URL.Query().Get("record-id"))
|
||||
_, _ = w.Write([]byte(`{"status":"Success","statusDescription":"The record was deleted successfully."}`))
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewCloudNSClient("12345", "secret")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("cloudns API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
err := client.ClearACMEChallenge(context.Background(), "example.com")
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, callCount, 2, "should have called list + delete")
|
||||
}
|
||||
|
||||
func TestCloudNSClient_DoRaw_Good_AuthQueryParams(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "49500", r.URL.Query().Get("auth-id"))
|
||||
|
|
|
|||
|
|
@ -79,6 +79,55 @@ func TestLoad_Ugly(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConfig_HostsByRole_Good(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Hosts: map[string]*Host{
|
||||
"de": {FQDN: "de.example.com", Role: "app"},
|
||||
"de2": {FQDN: "de2.example.com", Role: "app"},
|
||||
"noc": {FQDN: "noc.example.com", Role: "bastion"},
|
||||
"build": {FQDN: "build.example.com", Role: "builder"},
|
||||
},
|
||||
}
|
||||
|
||||
apps := cfg.HostsByRole("app")
|
||||
if len(apps) != 2 {
|
||||
t.Errorf("HostsByRole(app) = %d, want 2", len(apps))
|
||||
}
|
||||
if _, ok := apps["de"]; !ok {
|
||||
t.Error("expected de in app hosts")
|
||||
}
|
||||
if _, ok := apps["de2"]; !ok {
|
||||
t.Error("expected de2 in app hosts")
|
||||
}
|
||||
|
||||
bastions := cfg.HostsByRole("bastion")
|
||||
if len(bastions) != 1 {
|
||||
t.Errorf("HostsByRole(bastion) = %d, want 1", len(bastions))
|
||||
}
|
||||
|
||||
empty := cfg.HostsByRole("nonexistent")
|
||||
if len(empty) != 0 {
|
||||
t.Errorf("HostsByRole(nonexistent) = %d, want 0", len(empty))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfig_AppServers_Good(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Hosts: map[string]*Host{
|
||||
"de": {FQDN: "de.example.com", Role: "app"},
|
||||
"noc": {FQDN: "noc.example.com", Role: "bastion"},
|
||||
},
|
||||
}
|
||||
|
||||
apps := cfg.AppServers()
|
||||
if len(apps) != 1 {
|
||||
t.Errorf("AppServers() = %d, want 1", len(apps))
|
||||
}
|
||||
if _, ok := apps["de"]; !ok {
|
||||
t.Error("expected de in AppServers()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpandPath(t *testing.T) {
|
||||
home, _ := os.UserHomeDir()
|
||||
|
||||
|
|
|
|||
169
hetzner_test.go
169
hetzner_test.go
|
|
@ -116,7 +116,7 @@ func TestHCloudClient_Do_Bad_APIError(t *testing.T) {
|
|||
var result struct{}
|
||||
err := client.get(context.Background(), "/servers", &result)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "hcloud API 403")
|
||||
assert.Contains(t, err.Error(), "hcloud API: HTTP 403")
|
||||
}
|
||||
|
||||
func TestHCloudClient_Do_Bad_APIErrorNoJSON(t *testing.T) {
|
||||
|
|
@ -136,7 +136,7 @@ func TestHCloudClient_Do_Bad_APIErrorNoJSON(t *testing.T) {
|
|||
|
||||
err := client.get(context.Background(), "/servers", nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "hcloud API 500")
|
||||
assert.Contains(t, err.Error(), "hcloud API: HTTP 500")
|
||||
}
|
||||
|
||||
func TestHCloudClient_Do_Good_NilResult(t *testing.T) {
|
||||
|
|
@ -218,7 +218,170 @@ func TestHRobotClient_Get_Bad_HTTPError(t *testing.T) {
|
|||
|
||||
err := client.get(context.Background(), "/server", nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "hrobot API 401")
|
||||
assert.Contains(t, err.Error(), "hrobot API: HTTP 401")
|
||||
}
|
||||
|
||||
func TestHCloudClient_ListLoadBalancers_Good(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, http.MethodGet, r.Method)
|
||||
assert.Equal(t, "/load_balancers", r.URL.Path)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"load_balancers":[{"id":789,"name":"hermes","public_net":{"enabled":true,"ipv4":{"ip":"5.6.7.8"}}}]}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewHCloudClient("test-token")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("hcloud API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
lbs, err := client.ListLoadBalancers(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, lbs, 1)
|
||||
assert.Equal(t, "hermes", lbs[0].Name)
|
||||
assert.Equal(t, 789, lbs[0].ID)
|
||||
}
|
||||
|
||||
func TestHCloudClient_GetLoadBalancer_Good(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "/load_balancers/789", r.URL.Path)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"load_balancer":{"id":789,"name":"hermes","public_net":{"enabled":true,"ipv4":{"ip":"5.6.7.8"}}}}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewHCloudClient("test-token")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("hcloud API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
lb, err := client.GetLoadBalancer(context.Background(), 789)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "hermes", lb.Name)
|
||||
}
|
||||
|
||||
func TestHCloudClient_CreateLoadBalancer_Good(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, http.MethodPost, r.Method)
|
||||
assert.Equal(t, "/load_balancers", r.URL.Path)
|
||||
|
||||
var body HCloudLBCreateRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&body)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "hermes", body.Name)
|
||||
assert.Equal(t, "lb11", body.LoadBalancerType)
|
||||
assert.Equal(t, "round_robin", body.Algorithm.Type)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"load_balancer":{"id":789,"name":"hermes","public_net":{"enabled":true,"ipv4":{"ip":"5.6.7.8"}}}}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewHCloudClient("test-token")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithAuth(func(req *http.Request) {
|
||||
req.Header.Set("Authorization", "Bearer test-token")
|
||||
}),
|
||||
WithPrefix("hcloud API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
lb, err := client.CreateLoadBalancer(context.Background(), HCloudLBCreateRequest{
|
||||
Name: "hermes",
|
||||
LoadBalancerType: "lb11",
|
||||
Location: "fsn1",
|
||||
Algorithm: HCloudLBAlgorithm{Type: "round_robin"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "hermes", lb.Name)
|
||||
assert.Equal(t, 789, lb.ID)
|
||||
}
|
||||
|
||||
func TestHCloudClient_DeleteLoadBalancer_Good(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, http.MethodDelete, r.Method)
|
||||
assert.Equal(t, "/load_balancers/789", r.URL.Path)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewHCloudClient("test-token")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithPrefix("hcloud API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
err := client.DeleteLoadBalancer(context.Background(), 789)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestHCloudClient_CreateSnapshot_Good(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, http.MethodPost, r.Method)
|
||||
assert.Equal(t, "/servers/123/actions/create_image", r.URL.Path)
|
||||
|
||||
var body map[string]string
|
||||
err := json.NewDecoder(r.Body).Decode(&body)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "daily backup", body["description"])
|
||||
assert.Equal(t, "snapshot", body["type"])
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"image":{"id":456}}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewHCloudClient("test-token")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithAuth(func(req *http.Request) {
|
||||
req.Header.Set("Authorization", "Bearer test-token")
|
||||
}),
|
||||
WithPrefix("hcloud API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
err := client.CreateSnapshot(context.Background(), 123, "daily backup")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestHRobotClient_GetServer_Good(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "/server/1.2.3.4", r.URL.Path)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"server":{"server_ip":"1.2.3.4","server_name":"noc","product":"EX44","dc":"FSN1","status":"ready","cancelled":false}}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewHRobotClient("testuser", "testpass")
|
||||
client.baseURL = ts.URL
|
||||
client.api = NewAPIClient(
|
||||
WithHTTPClient(ts.Client()),
|
||||
WithAuth(func(req *http.Request) {
|
||||
req.SetBasicAuth("testuser", "testpass")
|
||||
}),
|
||||
WithPrefix("hrobot API"),
|
||||
WithRetry(RetryConfig{}),
|
||||
)
|
||||
|
||||
server, err := client.GetServer(context.Background(), "1.2.3.4")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "noc", server.ServerName)
|
||||
assert.Equal(t, "EX44", server.Product)
|
||||
}
|
||||
|
||||
// --- Type serialisation ---
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue