Skip to content

Commit e22ceab

Browse files
refactor(pihole): reduce cyclomatic complexity of TestProviderV6 (#5876)
* refactor(pihole): reduce cyclomatic complexity of TestProviderV6 * chore(pihole): increase coverage * style: linting * style: linting * fix: remove coverage html
1 parent 1f9edcb commit e22ceab

File tree

5 files changed

+309
-327
lines changed

5 files changed

+309
-327
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ cscope.*
4242

4343
# coverage output
4444
cover.out
45+
coverage.html
4546
*.coverprofile
4647
external-dns
4748

.golangci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ linters:
4141
- name: confusing-naming
4242
disabled: true
4343
cyclop: # Lower cyclomatic complexity threshold after the max complexity is lowered
44-
max-complexity: 43
44+
max-complexity: 37 # Controller/execute.go:147:1: calculated cyclomatic complexity for function buildProvider is 37
4545
testifylint:
4646
# Enable all checkers (https://github.com/Antonboom/testifylint#checkers).
4747
# Default: false

provider/pihole/clientV6_test.go

Lines changed: 98 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ func newTestServerV6(t *testing.T, hdlr http.HandlerFunc) *httptest.Server {
9292
return svr
9393
}
9494

95+
type errorTransportV6 struct{}
96+
97+
func (t *errorTransportV6) RoundTrip(req *http.Request) (*http.Response, error) {
98+
return nil, errors.New("network error")
99+
}
100+
95101
func TestNewPiholeClientV6(t *testing.T) {
96102
// Test correct error on no server provided
97103
_, err := newPiholeClientV6(PiholeConfig{APIVersion: "6"})
@@ -117,15 +123,18 @@ func TestNewPiholeClientV6(t *testing.T) {
117123
srvr := newTestServerV6(t, func(w http.ResponseWriter, r *http.Request) {
118124
if r.URL.Path == "/api/auth" && r.Method == http.MethodPost {
119125
var requestData map[string]string
120-
json.NewDecoder(r.Body).Decode(&requestData)
126+
err := json.NewDecoder(r.Body).Decode(&requestData)
127+
if err != nil {
128+
t.Fatal(err)
129+
}
121130
defer r.Body.Close()
122131

123132
w.Header().Set("Content-Type", "application/json")
124133

125134
if requestData["password"] != "correct" {
126135
// Return unsuccessful authentication response
127136
w.WriteHeader(http.StatusUnauthorized)
128-
w.Write([]byte(`{
137+
_, err = w.Write([]byte(`{
129138
"session": {
130139
"valid": false,
131140
"totp": false,
@@ -135,11 +144,14 @@ func TestNewPiholeClientV6(t *testing.T) {
135144
},
136145
"took": 0.2
137146
}`))
147+
if err != nil {
148+
t.Fatal(err)
149+
}
138150
return
139151
}
140152

141153
// Return successful authentication response
142-
w.Write([]byte(`{
154+
_, err = w.Write([]byte(`{
143155
"session": {
144156
"valid": true,
145157
"totp": false,
@@ -185,7 +197,7 @@ func TestListRecordsV6(t *testing.T) {
185197
w.Header().Set("Content-Type", "application/json")
186198

187199
// Return A records
188-
w.Write([]byte(`{
200+
if _, err := w.Write([]byte(`{
189201
"config": {
190202
"dns": {
191203
"hosts": [
@@ -205,7 +217,9 @@ func TestListRecordsV6(t *testing.T) {
205217
}
206218
},
207219
"took": 5
208-
}`))
220+
}`)); err != nil {
221+
t.Fatal(err)
222+
}
209223
} else if r.URL.Path == "/api/config/dns/cnameRecords" && r.Method == http.MethodGet {
210224

211225
w.WriteHeader(http.StatusOK)
@@ -384,9 +398,12 @@ func TestErrorsV6(t *testing.T) {
384398
Server: "not an url",
385399
APIVersion: "6",
386400
}
387-
clErrURL, _ := newPiholeClientV6(cfgErrURL)
401+
clErrURL, err := newPiholeClientV6(cfgErrURL)
402+
if err != nil {
403+
t.Fatal(err)
404+
}
388405

389-
_, err := clErrURL.listRecords(context.Background(), endpoint.RecordTypeCNAME)
406+
_, err = clErrURL.listRecords(context.Background(), endpoint.RecordTypeCNAME)
390407
if err == nil {
391408
t.Fatal("Expected error for using invalid URL")
392409
}
@@ -785,6 +802,80 @@ func TestDoRetryOne(t *testing.T) {
785802

786803
}
787804

805+
func TestDoV6AdditionalCases(t *testing.T) {
806+
t.Run("http client error", func(t *testing.T) {
807+
client := &piholeClientV6{
808+
httpClient: &http.Client{
809+
Transport: &errorTransportV6{},
810+
},
811+
}
812+
req, _ := http.NewRequest(http.MethodGet, "http://localhost", nil)
813+
_, err := client.do(req)
814+
if err == nil {
815+
t.Fatal("expected an error, but got none")
816+
}
817+
if !strings.Contains(err.Error(), "network error") {
818+
t.Fatalf("expected error to contain 'network error', but got '%v'", err)
819+
}
820+
})
821+
822+
t.Run("item already present", func(t *testing.T) {
823+
server := newTestServerV6(t, func(w http.ResponseWriter, r *http.Request) {
824+
w.WriteHeader(http.StatusBadRequest)
825+
w.Write([]byte(`{
826+
"error": {
827+
"key": "bad_request",
828+
"message": "Item already present",
829+
"hint": "The item you're trying to add already exists"
830+
},
831+
"took": 0.1
832+
}`))
833+
})
834+
defer server.Close()
835+
836+
client := &piholeClientV6{
837+
httpClient: server.Client(),
838+
token: "test-token",
839+
}
840+
req, _ := http.NewRequest(http.MethodPut, server.URL+"/api/test", nil)
841+
resp, err := client.do(req)
842+
if err != nil {
843+
t.Fatalf("expected no error for 'Item already present', but got '%v'", err)
844+
}
845+
if resp == nil {
846+
t.Fatal("expected response, but got nil")
847+
}
848+
})
849+
850+
t.Run("404 on DELETE", func(t *testing.T) {
851+
server := newTestServerV6(t, func(w http.ResponseWriter, r *http.Request) {
852+
w.WriteHeader(http.StatusNotFound)
853+
w.Write([]byte(`{
854+
"error": {
855+
"key": "not_found",
856+
"message": "Item not found",
857+
"hint": "The item you're trying to delete does not exist"
858+
},
859+
"took": 0.1
860+
}`))
861+
})
862+
defer server.Close()
863+
864+
client := &piholeClientV6{
865+
httpClient: server.Client(),
866+
token: "test-token",
867+
}
868+
req, _ := http.NewRequest(http.MethodDelete, server.URL+"/api/test", nil)
869+
resp, err := client.do(req)
870+
if err != nil {
871+
t.Fatalf("expected no error for 404 on DELETE, but got '%v'", err)
872+
}
873+
if resp == nil {
874+
t.Fatal("expected response, but got nil")
875+
}
876+
})
877+
}
878+
788879
func TestCreateRecordV6(t *testing.T) {
789880
var ep *endpoint.Endpoint
790881
srvr := newTestServerV6(t, func(w http.ResponseWriter, r *http.Request) {

provider/pihole/client_test.go

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,31 @@ func TestNewPiholeClient(t *testing.T) {
5757

5858
// Create a test server for auth tests
5959
srvr := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
60-
r.ParseForm()
60+
err := r.ParseForm()
61+
if err != nil {
62+
t.Fatal(err)
63+
}
6164
pw := r.Form.Get("pw")
6265
if pw != "correct" {
6366
// Pihole actually server side renders the fact that you failed, normal 200
64-
w.Write([]byte("Invalid"))
67+
_, err = w.Write([]byte("Invalid"))
68+
if err != nil {
69+
t.Fatal(err)
70+
}
6571
return
6672
}
6773
// This is a subset of what happens on successful login
68-
w.Write([]byte(`
74+
_, err = w.Write([]byte(`
6975
<!doctype html>
7076
<html lang="en">
7177
<body>
7278
<div id="token" hidden>supersecret</div>
7379
</body>
7480
</html>
7581
`))
82+
if err != nil {
83+
t.Fatal(err)
84+
}
7685
})
7786
defer srvr.Close()
7887

@@ -124,12 +133,15 @@ func CheckRecordRetrieval(t *testing.T, cl *piholeClient, recordType string, exp
124133

125134
func TestListRecords(t *testing.T) {
126135
srvr := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
127-
r.ParseForm()
136+
err := r.ParseForm()
137+
if err != nil {
138+
t.Fatal(err)
139+
}
128140
if r.Form.Get("action") != "get" {
129141
t.Error("Expected 'get' action in form from client")
130142
}
131143
if strings.Contains(r.URL.Path, "cname") {
132-
w.Write([]byte(`
144+
_, err = w.Write([]byte(`
133145
{
134146
"data": [
135147
["test4.example.com", "cname.example.com"],
@@ -138,10 +150,13 @@ func TestListRecords(t *testing.T) {
138150
]
139151
}
140152
`))
153+
if err != nil {
154+
t.Fatal(err)
155+
}
141156
return
142157
}
143158
// Pihole makes no distinction between A and AAAA records
144-
w.Write([]byte(`
159+
_, err = w.Write([]byte(`
145160
{
146161
"data": [
147162
["test1.example.com", "192.168.1.1"],
@@ -153,6 +168,9 @@ func TestListRecords(t *testing.T) {
153168
]
154169
}
155170
`))
171+
if err != nil {
172+
t.Fatal(err)
173+
}
156174
})
157175
defer srvr.Close()
158176

@@ -243,41 +261,32 @@ func testErrorScenarios(t *testing.T, srvrErr *httptest.Server) {
243261
func TestErrorScenarios(t *testing.T) {
244262
// Test errors token
245263
srvrErr := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
246-
r.ParseForm()
264+
err := r.ParseForm()
265+
if err != nil {
266+
t.Fatal(err)
267+
}
247268
pw := r.Form.Get("pw")
248269
if pw != "" {
249270
if pw != "correct" {
250-
// Pihole actually server side renders the fact that you failed, normal 200
251-
w.Write([]byte("Invalid"))
271+
_, err = w.Write([]byte("Invalid"))
272+
if err != nil {
273+
t.Fatal(err)
274+
}
252275
return
253276
}
254277
}
255278
if strings.Contains(r.URL.Path, "admin/scripts/pi-hole/php/customcname.php") && r.Form.Get("token") == "correct" {
256-
w.Write([]byte(`
279+
_, err = w.Write([]byte(`
257280
{
258281
"nodata": [
259282
["nodata", "no"]
260283
]
261284
}
262-
`))
263-
return
264-
}
265-
if strings.Contains(r.URL.Path, "admin/index.php?login") {
266-
w.Write([]byte(`
267-
<!doctype html>
268-
<html lang="en">
269-
<body>
270-
<div id="token" hidden>supersecret</div>
271-
</body>
272-
</html>
273285
`))
286+
if err != nil {
287+
t.Fatal(err)
288+
}
274289
}
275-
// Token Expired
276-
w.Write([]byte(`
277-
{
278-
"auth": "expired"
279-
}
280-
`))
281290
})
282291
defer srvrErr.Close()
283292

0 commit comments

Comments
 (0)