- Fix SaveConfig: add cfg.Commit() so credentials actually persist to disk - Fix TestResolveConfig and TestNewFromConfig: isolate from real config file by setting HOME to temp dir, preventing env/config bleed - Add RouteTypeName, GetRoutes, and GetNetworks unit tests with httptest mocks (coverage 39% → 55%) - Update CLAUDE.md: add error handling and test isolation conventions - Update docs: fix Go version (1.25 → 1.26), remove stale replace directive references, add cmd/unifi/ to architecture diagram Co-Authored-By: Virgil <virgil@lethean.io>
95 lines
3 KiB
Go
95 lines
3 KiB
Go
package unifi
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestGetNetworks(t *testing.T) {
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
// New-style controller: paths are prefixed with /proxy/network
|
|
if r.URL.Path == "/proxy/network/api/s/default/rest/networkconf" {
|
|
fmt.Fprintln(w, `{"data":[{"_id":"abc123","name":"LAN","purpose":"corporate","ip_subnet":"10.69.1.0/24","vlan":0,"vlan_enabled":false,"enabled":true,"networkgroup":"LAN","dhcpd_enabled":true,"dhcpd_start":"10.69.1.100","dhcpd_stop":"10.69.1.254"}]}`)
|
|
return
|
|
}
|
|
fmt.Fprintln(w, `{"meta":{"rc":"ok"}, "data": []}`)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
client, err := New(ts.URL, "user", "pass", "", true)
|
|
assert.NoError(t, err)
|
|
|
|
networks, err := client.GetNetworks("")
|
|
assert.NoError(t, err)
|
|
if assert.Len(t, networks, 1) {
|
|
assert.Equal(t, "abc123", networks[0].ID)
|
|
assert.Equal(t, "LAN", networks[0].Name)
|
|
assert.Equal(t, "corporate", networks[0].Purpose)
|
|
assert.Equal(t, "10.69.1.0/24", networks[0].IPSubnet)
|
|
assert.True(t, networks[0].Enabled)
|
|
assert.True(t, networks[0].DHCPEnabled)
|
|
assert.Equal(t, "10.69.1.100", networks[0].DHCPStart)
|
|
assert.Equal(t, "10.69.1.254", networks[0].DHCPStop)
|
|
}
|
|
}
|
|
|
|
func TestGetNetworks_CustomSite(t *testing.T) {
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if r.URL.Path == "/proxy/network/api/s/office/rest/networkconf" {
|
|
fmt.Fprintln(w, `{"data":[{"_id":"def456","name":"Office LAN","purpose":"corporate","ip_subnet":"172.16.0.0/24"}]}`)
|
|
return
|
|
}
|
|
fmt.Fprintln(w, `{"meta":{"rc":"ok"}, "data": []}`)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
client, err := New(ts.URL, "user", "pass", "", true)
|
|
assert.NoError(t, err)
|
|
|
|
networks, err := client.GetNetworks("office")
|
|
assert.NoError(t, err)
|
|
if assert.Len(t, networks, 1) {
|
|
assert.Equal(t, "Office LAN", networks[0].Name)
|
|
}
|
|
}
|
|
|
|
func TestGetNetworks_Empty(t *testing.T) {
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
fmt.Fprintln(w, `{"meta":{"rc":"ok"}, "data": []}`)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
client, err := New(ts.URL, "user", "pass", "", true)
|
|
assert.NoError(t, err)
|
|
|
|
networks, err := client.GetNetworks("")
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, networks)
|
|
}
|
|
|
|
func TestGetNetworks_InvalidJSON(t *testing.T) {
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if r.URL.Path == "/proxy/network/api/s/default/rest/networkconf" {
|
|
fmt.Fprintln(w, `not valid json`)
|
|
return
|
|
}
|
|
fmt.Fprintln(w, `{"meta":{"rc":"ok"}, "data": []}`)
|
|
}))
|
|
defer ts.Close()
|
|
|
|
client, err := New(ts.URL, "user", "pass", "", true)
|
|
assert.NoError(t, err)
|
|
|
|
networks, err := client.GetNetworks("")
|
|
assert.Error(t, err)
|
|
assert.Nil(t, networks)
|
|
assert.Contains(t, err.Error(), "failed to parse networks")
|
|
}
|