Repository: osbuild/osbuild-composer
Pull request #225 (2020-02-10 21:23:06)

Add coveralls.io code coverage github-action

bcl: > Can you elaborate on the intention here? Is this meant to amend coverage information to the CI output, or will the coverage data just be printed to the CI logs?

Well, I'd prefer to push things to a service like coveralls.io but nobody liked that patch :)
I think it's useful to be able to see the coverage levels for submitted PRs, even if it isn't easy to compare it to the parent commit.
teg: I didn't have a chance to look into your other proposal (yet). But I think having some service would be more useful. I think that just lacked some justification/discussion. What does it give us, how does it work, etc.
bcl: You can take a look at lorax and pykickstart as good examples of how coveralls.io looks over time:

* https://coveralls.io/github/weldr/lorax
* https://coveralls.io/github/pykickstart/pykickstart

It is linked to the github repo the same way travis-ci is, and when the upload runs from inside travis it includes the credentials to link to the correct repo without having to do a bunch of extra setup.

I'm sure there are other services out there, this is just the one I'm most familiar with, and we have been using it for years with minimal issues with it.

Patch:
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 000000000..826e36add
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,35 @@
+name: Coverage
+
+# NOTE(mhayden): Restricting branches prevents jobs from being doubled since
+# a push to a pull request triggers two events.
+on:
+  pull_request:
+    branches:
+      - "*"
+  push:
+    branches:
+      - master
+
+jobs:
+  test:
+    name: Test with Coverage
+    runs-on: ubuntu-latest
+    steps:
+    - name: Set up Go
+      uses: actions/setup-go@v1
+      with:
+        go-version: '1.13'
+    - name: Check out code
+      uses: actions/checkout@v2
+    - name: Install dependencies
+      run: |
+        go mod download
+    - name: Run Unit tests
+      run: |
+        go test -race -covermode atomic -coverprofile=profile.cov ./...
+    - name: Send coverage
+      env:
+        COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      run: |
+        GO111MODULE=off go get github.com/mattn/goveralls
+        $(go env GOPATH)/bin/goveralls -coverprofile=profile.cov -service=github
diff --git a/internal/client/blueprints.go b/internal/client/blueprints.go
index 99ade9cef..2df7e8381 100644
--- a/internal/client/blueprints.go
+++ b/internal/client/blueprints.go
@@ -5,12 +5,13 @@ package client
 import (
 	"encoding/json"
 	"fmt"
+	"net/http"
 	"strings"
 )
 
 // PostTOMLBlueprintV0 sends a TOML blueprint string to the API
 // and returns an APIResponse
-func PostTOMLBlueprintV0(socket, blueprint string) (*APIResponse, error) {
+func PostTOMLBlueprintV0(socket *http.Client, blueprint string) (*APIResponse, error) {
 	body, resp, err := PostTOML(socket, "/api/v0/blueprints/new", blueprint)
 	if resp != nil || err != nil {
 		return resp, err
@@ -20,7 +21,7 @@ func PostTOMLBlueprintV0(socket, blueprint string) (*APIResponse, error) {
 
 // PostTOMLWorkspaceV0 sends a TOML blueprint string to the API
 // and returns an APIResponse
-func PostTOMLWorkspaceV0(socket, blueprint string) (*APIResponse, error) {
+func PostTOMLWorkspaceV0(socket *http.Client, blueprint string) (*APIResponse, error) {
 	body, resp, err := PostTOML(socket, "/api/v0/blueprints/workspace", blueprint)
 	if resp != nil || err != nil {
 		return resp, err
@@ -30,7 +31,7 @@ func PostTOMLWorkspaceV0(socket, blueprint string) (*APIResponse, error) {
 
 // PostJSONBlueprintV0 sends a JSON blueprint string to the API
 // and returns an APIResponse
-func PostJSONBlueprintV0(socket, blueprint string) (*APIResponse, error) {
+func PostJSONBlueprintV0(socket *http.Client, blueprint string) (*APIResponse, error) {
 	body, resp, err := PostJSON(socket, "/api/v0/blueprints/new", blueprint)
 	if resp != nil || err != nil {
 		return resp, err
@@ -40,7 +41,7 @@ func PostJSONBlueprintV0(socket, blueprint string) (*APIResponse, error) {
 
 // PostJSONWorkspaceV0 sends a JSON blueprint string to the API
 // and returns an APIResponse
-func PostJSONWorkspaceV0(socket, blueprint string) (*APIResponse, error) {
+func PostJSONWorkspaceV0(socket *http.Client, blueprint string) (*APIResponse, error) {
 	body, resp, err := PostJSON(socket, "/api/v0/blueprints/workspace", blueprint)
 	if resp != nil || err != nil {
 		return resp, err
@@ -49,7 +50,7 @@ func PostJSONWorkspaceV0(socket, blueprint string) (*APIResponse, error) {
 }
 
 // DeleteBlueprintV0 deletes the named blueprint and returns an APIResponse
-func DeleteBlueprintV0(socket, bpName string) (*APIResponse, error) {
+func DeleteBlueprintV0(socket *http.Client, bpName string) (*APIResponse, error) {
 	body, resp, err := DeleteRaw(socket, "/api/v0/blueprints/delete/"+bpName)
 	if resp != nil || err != nil {
 		return resp, err
@@ -58,7 +59,7 @@ func DeleteBlueprintV0(socket, bpName string) (*APIResponse, error) {
 }
 
 // DeleteWorkspaceV0 deletes the named blueprint's workspace and returns an APIResponse
-func DeleteWorkspaceV0(socket, bpName string) (*APIResponse, error) {
+func DeleteWorkspaceV0(socket *http.Client, bpName string) (*APIResponse, error) {
 	body, resp, err := DeleteRaw(socket, "/api/v0/blueprints/workspace/"+bpName)
 	if resp != nil || err != nil {
 		return resp, err
@@ -67,7 +68,7 @@ func DeleteWorkspaceV0(socket, bpName string) (*APIResponse, error) {
 }
 
 // ListBlueprintsV0 returns a list of blueprint names
-func ListBlueprintsV0(socket string) ([]string, *APIResponse, error) {
+func ListBlueprintsV0(socket *http.Client) ([]string, *APIResponse, error) {
 	body, resp, err := GetJSONAll(socket, "/api/v0/blueprints/list")
 	if resp != nil || err != nil {
 		return nil, resp, err
@@ -81,7 +82,7 @@ func ListBlueprintsV0(socket string) ([]string, *APIResponse, error) {
 }
 
 // GetBlueprintInfoTOMLV0 returns the requested blueprint as a TOML string
-func GetBlueprintInfoTOMLV0(socket, bpName string) (string, *APIResponse, error) {
+func GetBlueprintInfoTOMLV0(socket *http.Client, bpName string) (string, *APIResponse, error) {
 	body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/info/"+bpName+"?format=toml")
 	if resp != nil || err != nil {
 		return "", resp, err
@@ -90,7 +91,7 @@ func GetBlueprintInfoTOMLV0(socket, bpName string) (string, *APIResponse, error)
 }
 
 // GetBlueprintsInfoJSONV0 returns the requested blueprints and their changed state
-func GetBlueprintsInfoJSONV0(socket, bpName string) (BlueprintsInfoV0, *APIResponse, error) {
+func GetBlueprintsInfoJSONV0(socket *http.Client, bpName string) (BlueprintsInfoV0, *APIResponse, error) {
 	body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/info/"+bpName)
 	if resp != nil || err != nil {
 		return BlueprintsInfoV0{}, resp, err
@@ -104,7 +105,7 @@ func GetBlueprintsInfoJSONV0(socket, bpName string) (BlueprintsInfoV0, *APIRespo
 }
 
 // GetBlueprintsChangesV0 returns the changes to the listed blueprints
-func GetBlueprintsChangesV0(socket string, bpNames []string) (BlueprintsChangesV0, *APIResponse, error) {
+func GetBlueprintsChangesV0(socket *http.Client, bpNames []string) (BlueprintsChangesV0, *APIResponse, error) {
 	names := strings.Join(bpNames, ",")
 	body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/changes/"+names)
 	if resp != nil || err != nil {
@@ -119,7 +120,7 @@ func GetBlueprintsChangesV0(socket string, bpNames []string) (BlueprintsChangesV
 }
 
 // UndoBlueprintChangeV0 reverts a blueprint to a previous commit
-func UndoBlueprintChangeV0(socket, blueprint, commit string) (*APIResponse, error) {
+func UndoBlueprintChangeV0(socket *http.Client, blueprint, commit string) (*APIResponse, error) {
 	request := fmt.Sprintf("/api/v0/blueprints/undo/%s/%s", blueprint, commit)
 	body, resp, err := PostRaw(socket, request, "", nil)
 	if resp != nil || err != nil {
@@ -129,7 +130,7 @@ func UndoBlueprintChangeV0(socket, blueprint, commit string) (*APIResponse, erro
 }
 
 // TagBlueprintV0 tags the current blueprint commit as a new revision
-func TagBlueprintV0(socket, blueprint string) (*APIResponse, error) {
+func TagBlueprintV0(socket *http.Client, blueprint string) (*APIResponse, error) {
 	body, resp, err := PostRaw(socket, "/api/v0/blueprints/tag/"+blueprint, "", nil)
 	if resp != nil || err != nil {
 		return resp, err
@@ -138,7 +139,7 @@ func TagBlueprintV0(socket, blueprint string) (*APIResponse, error) {
 }
 
 // DepsolveBlueprintV0 depsolves the listed blueprint
-func DepsolveBlueprintV0(socket, blueprint string) (BlueprintsDepsolveV0, *APIResponse, error) {
+func DepsolveBlueprintV0(socket *http.Client, blueprint string) (BlueprintsDepsolveV0, *APIResponse, error) {
 	body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/depsolve/"+blueprint)
 	if resp != nil || err != nil {
 		return BlueprintsDepsolveV0{}, resp, err
@@ -153,7 +154,7 @@ func DepsolveBlueprintV0(socket, blueprint string) (BlueprintsDepsolveV0, *APIRe
 
 // FreezeBlueprintV0 depsolves the listed blueprint and returns the blueprint with frozen package
 // versions
-func FreezeBlueprintV0(socket, blueprint string) (BlueprintsFreezeV0, *APIResponse, error) {
+func FreezeBlueprintV0(socket *http.Client, blueprint string) (BlueprintsFreezeV0, *APIResponse, error) {
 	body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/freeze/"+blueprint)
 	if resp != nil || err != nil {
 		return BlueprintsFreezeV0{}, resp, err
diff --git a/internal/client/client.go b/internal/client/client.go
index e2c1c73fa..f1ae7e1a0 100644
--- a/internal/client/client.go
+++ b/internal/client/client.go
@@ -4,14 +4,11 @@ package client
 
 import (
 	"bytes"
-	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"io/ioutil"
-	"net"
 	"net/http"
-	"time"
 )
 
 // Request handles sending the request, handling errors, returning the response
@@ -22,17 +19,7 @@ import (
 //
 // If it is successful a http.Response will be returned. If there is an error, the response will be
 // nil and error will be returned.
-func Request(socket, method, path, body string, headers map[string]string) (*http.Response, error) {
-	client := http.Client{
-		// TODO This may be too short/simple for downloading images
-		Timeout: 60 * time.Second,
-		Transport: &http.Transport{
-			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
-				return net.Dial("unix", socket)
-			},
-		},
-	}
-
+func Request(socket *http.Client, method, path, body string, headers map[string]string) (*http.Response, error) {
 	req, err := http.NewRequest(method, "http://localhost"+path, bytes.NewReader([]byte(body)))
 	if err != nil {
 		return nil, err
@@ -42,7 +29,7 @@ func Request(socket, method, path, body string, headers map[string]string) (*htt
 		req.Header.Set(h, v)
 	}
 
-	resp, err := client.Do(req)
+	resp, err := socket.Do(req)
 	if err != nil {
 		return nil, err
 	}
@@ -112,7 +99,7 @@ func apiError(resp *http.Response) (*APIResponse, error) {
 
 // GetRaw returns raw data from a GET request
 // Errors from the API are returned as an APIResponse, client errors are returned as error
-func GetRaw(socket, method, path string) ([]byte, *APIResponse, error) {
+func GetRaw(socket *http.Client, method, path string) ([]byte, *APIResponse, error) {
 	resp, err := Request(socket, method, path, "", map[string]string{})
 	if err != nil {
 		return nil, nil, err
@@ -138,7 +125,7 @@ func GetRaw(socket, method, path string) ([]byte, *APIResponse, error) {
 // and then with limit=TOTAL to fetch all of the results.
 // The path passed to GetJSONAll should not include the limit or offset query parameters
 // Errors from the API are returned as an APIResponse, client errors are returned as error
-func GetJSONAll(socket, path string) ([]byte, *APIResponse, error) {
+func GetJSONAll(socket *http.Client, path string) ([]byte, *APIResponse, error) {
 	body, api, err := GetRaw(socket, "GET", path+"?limit=0")
 	if api != nil || err != nil {
 		return nil, api, err
@@ -167,7 +154,7 @@ func GetJSONAll(socket, path string) ([]byte, *APIResponse, error) {
 
 // PostRaw sends a POST with raw data and returns the raw response body
 // Errors from the API are returned as an APIResponse, client errors are returned as error
-func PostRaw(socket, path, body string, headers map[string]string) ([]byte, *APIResponse, error) {
+func PostRaw(socket *http.Client, path, body string, headers map[string]string) ([]byte, *APIResponse, error) {
 	resp, err := Request(socket, "POST", path, body, headers)
 	if err != nil {
 		return nil, nil, err
@@ -190,21 +177,21 @@ func PostRaw(socket, path, body string, headers map[string]string) ([]byte, *API
 
 // PostTOML sends a POST with TOML data and the Content-Type header set to "text/x-toml"
 // Errors from the API are returned as an APIResponse, client errors are returned as error
-func PostTOML(socket, path, body string) ([]byte, *APIResponse, error) {
+func PostTOML(socket *http.Client, path, body string) ([]byte, *APIResponse, error) {
 	headers := map[string]string{"Content-Type": "text/x-toml"}
 	return PostRaw(socket, path, body, headers)
 }
 
 // PostJSON sends a POST with JSON data and the Content-Type header set to "application/json"
 // Errors from the API are returned as an APIResponse, client errors are returned as error
-func PostJSON(socket, path, body string) ([]byte, *APIResponse, error) {
+func PostJSON(socket *http.Client, path, body string) ([]byte, *APIResponse, error) {
 	headers := map[string]string{"Content-Type": "application/json"}
 	return PostRaw(socket, path, body, headers)
 }
 
 // DeleteRaw sends a DELETE request
 // Errors from the API are returned as an APIResponse, client errors are returned as error
-func DeleteRaw(socket, path string) ([]byte, *APIResponse, error) {
+func DeleteRaw(socket *http.Client, path string) ([]byte, *APIResponse, error) {
 	resp, err := Request(socket, "DELETE", path, "", nil)
 	if err != nil {
 		return nil, nil, err
diff --git a/internal/client/weldr.go b/internal/client/weldr.go
index 711c898de..dcb9feede 100644
--- a/internal/client/weldr.go
+++ b/internal/client/weldr.go
@@ -4,10 +4,11 @@ package client
 
 import (
 	"encoding/json"
+	"net/http"
 )
 
 // GetStatusV0 makes a GET request to /api/status and returns the v0 response as a StatusResponseV0
-func GetStatusV0(socket string) (reply StatusV0, resp *APIResponse, err error) {
+func GetStatusV0(socket *http.Client) (reply StatusV0, resp *APIResponse, err error) {
 	body, resp, err := GetRaw(socket, "GET", "/api/status")
 	if resp != nil || err != nil {
 		return reply, resp, err
diff --git a/internal/weldrcheck/blueprints.go b/internal/weldrcheck/blueprints.go
index f65bf293a..e00d454fb 100644
--- a/internal/weldrcheck/blueprints.go
+++ b/internal/weldrcheck/blueprints.go
@@ -4,6 +4,7 @@ package weldrcheck
 
 import (
 	"log"
+	"net/http"
 	"reflect"
 	"sort"
 	"strings"
@@ -14,7 +15,7 @@ import (
 )
 
 type checkBlueprintsV0 struct {
-	socket string
+	socket *http.Client
 }
 
 // Run will execute the API V0 Blueprint check functions
diff --git a/internal/weldrcheck/check.go b/internal/weldrcheck/check.go
index b22edd681..9a075908a 100644
--- a/internal/weldrcheck/check.go
+++ b/internal/weldrcheck/check.go
@@ -4,6 +4,7 @@ package weldrcheck
 
 import (
 	"log"
+	"net/http"
 	"os"
 	"sort"
 	"strconv"
@@ -32,7 +33,7 @@ func isStringInSlice(slice []string, s string) bool {
 
 // Run the API V0 checks against the server
 // Return true if all the checks pass
-func runV0Checks(socket string) (pass bool) {
+func runV0Checks(socket *http.Client) (pass bool) {
 	pass = true
 
 	bpv0 := checkBlueprintsV0{socket}
@@ -47,7 +48,7 @@ func runV0Checks(socket string) (pass bool) {
 }
 
 // Run the V1 checks against the server
-func runV1Checks(socket string) (pass bool) {
+func runV1Checks(socket *http.Client) (pass bool) {
 	pass = true
 
 	if pass {
@@ -60,14 +61,9 @@ func runV1Checks(socket string) (pass bool) {
 
 // Run executes all of the weldr API checks against a running API server
 // This is designed to run against any WELDR API server, not just osbuild-composer
-func Run(socket string) {
-	log.Printf("Running API check on %s", socket)
+func Run(socket *http.Client) {
+	log.Print("Running API check")
 
-	// Does the socket exist?
-	if _, err := os.Stat(socket); os.IsNotExist(err) {
-		log.Printf("ERROR: API socket %s is missing", socket)
-		os.Exit(1)
-	}
 	// Does the server respond to /api/status?
 	status, resp, err := client.GetStatusV0(socket)
 	if err != nil {


Test patch:
diff --git a/cmd/osbuild-weldr-tests/main.go b/cmd/osbuild-weldr-tests/main.go
index 7a7002832..d04171c2a 100644
--- a/cmd/osbuild-weldr-tests/main.go
+++ b/cmd/osbuild-weldr-tests/main.go
@@ -3,9 +3,24 @@
 package main
 
 import (
+	"context"
+	"net"
+	"net/http"
+	"time"
+
 	"github.com/osbuild/osbuild-composer/internal/weldrcheck"
 )
 
 func main() {
-	weldrcheck.Run("/run/weldr/api.socket")
+	client := &http.Client{
+		// TODO This may be too short/simple for downloading images
+		Timeout: 60 * time.Second,
+		Transport: &http.Transport{
+			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
+				return net.Dial("unix", "/run/weldr/api.socket")
+			},
+		},
+	}
+
+	weldrcheck.Run(client)
 }
diff --git a/internal/client/client_test.go b/internal/client/client_test.go
index f11c79e02..4b68f0d7d 100644
--- a/internal/client/client_test.go
+++ b/internal/client/client_test.go
@@ -3,6 +3,7 @@
 package client
 
 import (
+	"context"
 	"io/ioutil"
 	"log"
 	"net"
@@ -10,6 +11,7 @@ import (
 	"os"
 	"strings"
 	"testing"
+	"time"
 
 	test_distro "github.com/osbuild/osbuild-composer/internal/distro/fedoratest"
 	rpmmd_mock "github.com/osbuild/osbuild-composer/internal/mocks/rpmmd"
@@ -21,9 +23,12 @@ import (
 // socketPath is the path to the temporary unix domain socket
 var socketPath string
 
+// socket is the client connection to the server on socketPath
+var socket *http.Client
+
 func TestRequest(t *testing.T) {
 	// Make a request to the status route
-	resp, err := Request(socketPath, "GET", "/api/status", "", map[string]string{})
+	resp, err := Request(socket, "GET", "/api/status", "", map[string]string{})
 	if err != nil {
 		t.Fatalf("Request good route failed: %v", err)
 	}
@@ -32,7 +37,7 @@ func TestRequest(t *testing.T) {
 	}
 
 	// Make a request to a bad route
-	resp, err = Request(socketPath, "GET", "/invalidroute", "", map[string]string{})
+	resp, err = Request(socket, "GET", "/invalidroute", "", map[string]string{})
 	if err != nil {
 		t.Fatalf("Request bad route failed: %v", err)
 	}
@@ -47,7 +52,7 @@ func TestRequest(t *testing.T) {
 	}
 
 	// Make a request with a bad offset to trigger a JSON response with Status set to 400
-	resp, err = Request(socketPath, "GET", "/api/v0/blueprints/list?offset=bad", "", map[string]string{})
+	resp, err = Request(socket, "GET", "/api/v0/blueprints/list?offset=bad", "", map[string]string{})
 	if err != nil {
 		t.Fatalf("Request bad offset failed: %v", err)
 	}
@@ -84,7 +89,7 @@ func TestAPIResponse(t *testing.T) {
 
 func TestGetRaw(t *testing.T) {
 	// Get raw data
-	b, resp, err := GetRaw(socketPath, "GET", "/api/status")
+	b, resp, err := GetRaw(socket, "GET", "/api/status")
 	if err != nil {
 		t.Fatalf("GetRaw failed with a client error: %v", err)
 	}
@@ -95,7 +100,7 @@ func TestGetRaw(t *testing.T) {
 		t.Fatal("GetRaw returned an empty string")
 	}
 	// Get an API error
-	b, resp, err = GetRaw(socketPath, "GET", "/api/v0/blueprints/list?offset=bad")
+	b, resp, err = GetRaw(socket, "GET", "/api/v0/blueprints/list?offset=bad")
 	if err != nil {
 		t.Fatalf("GetRaw bad request failed with a client error: %v", err)
 	}
@@ -114,7 +119,7 @@ func TestGetRaw(t *testing.T) {
 
 func TestGetJSONAll(t *testing.T) {
 	// Get all the projects
-	b, resp, err := GetJSONAll(socketPath, "/api/v0/projects/list")
+	b, resp, err := GetJSONAll(socket, "/api/v0/projects/list")
 	if err != nil {
 		t.Fatalf("GetJSONAll failed with a client error: %v", err)
 	}
@@ -126,7 +131,7 @@ func TestGetJSONAll(t *testing.T) {
 	}
 
 	// Run it on a route that doesn't support offset/limit
-	b, resp, err = GetJSONAll(socketPath, "/api/status")
+	b, resp, err = GetJSONAll(socket, "/api/status")
 	if err == nil {
 		t.Fatalf("GetJSONAll bad route failed: %v", b)
 	}
@@ -137,7 +142,7 @@ func TestGetJSONAll(t *testing.T) {
 
 func TestPostRaw(t *testing.T) {
 	// There are no routes that accept raw POST w/o Content-Type so this ends up testing the error path
-	b, resp, err := PostRaw(socketPath, "/api/v0/blueprints/new", "nobody", nil)
+	b, resp, err := PostRaw(socket, "/api/v0/blueprints/new", "nobody", nil)
 	if err != nil {
 		t.Fatalf("PostRaw bad request failed with a client error: %v", err)
 	}
@@ -158,7 +163,7 @@ func TestPostTOML(t *testing.T) {
 	blueprint := `name = "test-blueprint"
 				  description = "TOML test blueprint"
 				  version = "0.0.1"`
-	b, resp, err := PostTOML(socketPath, "/api/v0/blueprints/new", blueprint)
+	b, resp, err := PostTOML(socket, "/api/v0/blueprints/new", blueprint)
 	if err != nil {
 		t.Fatalf("PostTOML client failed: %v", err)
 	}
@@ -174,7 +179,7 @@ func TestPostJSON(t *testing.T) {
 	blueprint := `{"name": "test-blueprint",
 				   "description": "JSON test blueprint",
 				   "version": "0.0.1"}`
-	b, resp, err := PostJSON(socketPath, "/api/v0/blueprints/new", blueprint)
+	b, resp, err := PostJSON(socket, "/api/v0/blueprints/new", blueprint)
 	if err != nil {
 		t.Fatalf("PostJSON client failed: %v", err)
 	}
@@ -216,6 +221,16 @@ func TestMain(m *testing.M) {
 		}
 	}()
 
+	// Setup client connection to socketPath
+	socket = &http.Client{
+		Timeout: 60 * time.Second,
+		Transport: &http.Transport{
+			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
+				return net.Dial("unix", socketPath)
+			},
+		},
+	}
+
 	// Run the tests
 	os.Exit(m.Run())
 }