-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Test: Update makefile to include testing commands * Test: Add initial testing files * test: add test for props() function * test: add test for recoverPanic middleware * test: add handlers_test.go * test: add test for background function * chore: address staticcheck errors * ci: add github-action.yml
- Loading branch information
1 parent
3756ab6
commit f2a2bd5
Showing
13 changed files
with
485 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
name: "CI" | ||
|
||
on: | ||
pull_request: | ||
branches: [ main ] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
go: [ '1.22.x', '1.23.x' ] | ||
|
||
steps: | ||
- name: "Checking out code..." | ||
uses: actions/checkout@v4 | ||
- name: "Installing Go..." | ||
uses: WillAbides/setup-go-faster@v1 | ||
with: | ||
go-version: ${{ matrix.go }} | ||
- name: "Install dependencies..." | ||
run: go mod download | ||
- name: "Verifying dependencies..." | ||
run: go mod verify | ||
- name: "Vetting code..." | ||
run: go vet ./... | ||
- uses: dominikh/staticcheck-action@v1 | ||
with: | ||
version: "latest" | ||
install-go: false | ||
cache-key: ${{ matrix.go }} | ||
- name: "Running tests..." | ||
run: go test -race -vet=off ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/rynhndrcksn/go-starter-site/internal/assert" | ||
) | ||
|
||
func TestHomeHandler(t *testing.T) { | ||
// Make a new test application. | ||
app := newTestApplication(t) | ||
|
||
// Make a new test server to make calls with. | ||
ts := newTestServer(t, app.sessionManager.LoadAndSave(app.routes())) | ||
defer ts.Close() | ||
|
||
// Make a request to the handler being tested. | ||
code, _, body := ts.get(t, "/") | ||
|
||
// Assert we're getting a 200 code response. | ||
assert.Equal(t, code, http.StatusOK) | ||
|
||
// Assert that the body contains the text from the <title> tag. | ||
assert.StringContains(t, body, "<title>Home - Site</title>") | ||
} | ||
|
||
func TestNotFoundHandler(t *testing.T) { | ||
// Make a new test application. | ||
app := newTestApplication(t) | ||
|
||
// Make a new test server to make calls with. | ||
ts := newTestServer(t, app.sessionManager.LoadAndSave(app.routes())) | ||
defer ts.Close() | ||
|
||
// Make a request to the handler being tested. | ||
code, _, body := ts.get(t, "/not-found") | ||
|
||
// Assert we're getting a 200 code response. | ||
assert.Equal(t, code, http.StatusNotFound) | ||
|
||
// Assert that the body contains the text from the <title> tag. | ||
assert.StringContains(t, body, "<title>Not Found - Site</title>") | ||
} | ||
|
||
func TestServerErrorHandler(t *testing.T) { | ||
// Make a new test application. | ||
app := newTestApplication(t) | ||
|
||
// Make a new test server to make calls with. | ||
ts := newTestServer(t, app.sessionManager.LoadAndSave(app.routeThatPanics())) | ||
defer ts.Close() | ||
|
||
// Make a request to the handler being tested. | ||
code, _, body := ts.get(t, "/server-error") | ||
|
||
// Assert we're getting a 200 code response. | ||
assert.Equal(t, code, http.StatusInternalServerError) | ||
|
||
// Assert that the body contains the text from the <title> tag. | ||
assert.StringContains(t, body, "<title>Server Error - Site</title>") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
"testing" | ||
) | ||
|
||
func TestBackground(t *testing.T) { | ||
req, err := http.NewRequest(http.MethodGet, "/", nil) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
tests := []struct { | ||
name string | ||
r *http.Request | ||
fn func() | ||
}{ | ||
{ | ||
name: "Background works normally", | ||
r: req, | ||
fn: func() { | ||
t.Log("This is a background test") | ||
}, | ||
}, | ||
{ | ||
name: "Background recovers from panics", | ||
r: req, | ||
fn: func() { | ||
panic("this is a panic") | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
app := newTestApplication(t) | ||
app.background(tt.r, tt.fn) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/rynhndrcksn/go-starter-site/internal/assert" | ||
) | ||
|
||
func TestCommonHeaders(t *testing.T) { | ||
// Initialize a new httptest.ResponseRecorder and fake http.Request. | ||
rr := httptest.NewRecorder() | ||
|
||
r, err := http.NewRequest(http.MethodGet, "/", nil) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// Create a mock HTTP handler that we can pass to our commonHeaders middleware, which writes a 200 status code and an "OK" response body. | ||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
_, _ = w.Write([]byte("OK")) | ||
}) | ||
|
||
// Initialize a new test application. | ||
app := newTestApplication(t) | ||
|
||
// Pass the mock HTTP handler to our commonHeaders middleware. | ||
app.commonHeaders(next).ServeHTTP(rr, r) | ||
|
||
// Call the Result() method on the http.ResponseRecorder to get the results of the test. | ||
rs := rr.Result() | ||
|
||
// Check that the middleware has correctly set the Content-Security-Policy header on the response. | ||
expectedValue := "default-src 'self';frame-ancestors 'none';" | ||
assert.Equal(t, rs.Header.Get("Content-Security-Policy"), expectedValue) | ||
|
||
// Check that the middleware has correctly set the Referrer-Policy header on the response. | ||
expectedValue = "origin-when-cross-origin" | ||
assert.Equal(t, rs.Header.Get("Referrer-Policy"), expectedValue) | ||
|
||
expectedValue = "max-age=63072000; includeSubDomains; preload" | ||
assert.Equal(t, rs.Header.Get("Strict-Transport-Security"), expectedValue) | ||
|
||
// Check that the middleware has correctly set the X-Content-Type-Options header on the response. | ||
expectedValue = "nosniff" | ||
assert.Equal(t, rs.Header.Get("X-Content-Type-Options"), expectedValue) | ||
|
||
// Check that the middleware has correctly set the X-Frame-Options header on the response. | ||
expectedValue = "deny" | ||
assert.Equal(t, rs.Header.Get("X-Frame-Options"), expectedValue) | ||
|
||
// Check that the middleware has correctly called the next handler in line and the response status code and body are as expected. | ||
assert.Equal(t, rs.StatusCode, http.StatusOK) | ||
|
||
defer func(Body io.ReadCloser) { | ||
err = Body.Close() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
}(rs.Body) | ||
body, err := io.ReadAll(rs.Body) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
body = bytes.TrimSpace(body) | ||
|
||
assert.Equal(t, string(body), "OK") | ||
} | ||
|
||
func TestRecoverPanic(t *testing.T) { | ||
// Initialize a new httptest.ResponseRecorder and fake http.Request. | ||
rr := httptest.NewRecorder() | ||
|
||
r, err := http.NewRequest(http.MethodGet, "/", nil) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// Create a mock HTTP handler that we can pass to our recoverPanic middleware, which panics. | ||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
panic("this is a panic") | ||
}) | ||
|
||
// Initialize a new test application. | ||
app := newTestApplication(t) | ||
|
||
// Pass the mock HTTP handler to the recoverPanic middleware. | ||
// Note: we need to wrap the recoverPanic middleware inside a call | ||
// to "app.sessionManager.LoadAndSave()", otherwise scs panics. | ||
app.sessionManager.LoadAndSave(app.recoverPanic(next)).ServeHTTP(rr, r) | ||
|
||
// Call the Result() method on the http.ResponseRecorder to get the results of the test. | ||
rs := rr.Result() | ||
|
||
// Check that the middleware worked and the response is what's wanted. | ||
assert.Equal(t, rs.Header.Get("Connection"), "close") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package main | ||
|
||
import ( | ||
"maps" | ||
"testing" | ||
"time" | ||
|
||
"github.com/rynhndrcksn/go-starter-site/internal/assert" | ||
) | ||
|
||
func TestHumanDate(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
tm time.Time | ||
want string | ||
}{ | ||
{ | ||
name: "UTC", | ||
tm: time.Date(2024, 01, 1, 12, 0, 0, 0, time.UTC), | ||
want: "01 Jan 2024 at 12:00", | ||
}, | ||
{ | ||
name: "Empty", | ||
tm: time.Time{}, | ||
want: "", | ||
}, | ||
{ | ||
name: "PST", | ||
tm: time.Date(2024, 01, 1, 12, 0, 0, 0, time.FixedZone("UTC-8", 8*60*60)), | ||
want: "01 Jan 2024 at 04:00", | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
hd := humanDate(tt.tm) | ||
assert.Equal(t, hd, tt.want) | ||
}) | ||
} | ||
} | ||
|
||
func TestProps(t *testing.T) { | ||
validMap := make(map[string]any, 2) | ||
validMap["key1"] = "value1" | ||
validMap["key2"] = 5 | ||
validMap["key3"] = true | ||
tests := []struct { | ||
name string | ||
input []any | ||
wantMap map[string]any | ||
wantErr error | ||
}{ | ||
{ | ||
name: "Passed in 0 items", | ||
input: []any{}, | ||
wantMap: nil, | ||
wantErr: errPropsKeyValueCountIsZero, | ||
}, | ||
{ | ||
name: "Mismatched key value pairs", | ||
input: []any{"key1", "value1", "key2"}, | ||
wantMap: nil, | ||
wantErr: errPropsKeyValueCountMismatch, | ||
}, | ||
{ | ||
name: "Valid amount of key value pairs", | ||
input: []any{"key1", "value1", "key2", 5, "key3", true}, | ||
wantMap: validMap, | ||
wantErr: nil, | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
gotMap, gotErr := props(test.input...) | ||
assert.Equal(t, gotErr, test.wantErr) | ||
assert.Equal(t, maps.Equal(gotMap, test.wantMap), true) | ||
}) | ||
} | ||
} |
Oops, something went wrong.