Refactor database interface to use *sql.DB directly
Simplified the database layer by removing custom interface wrappers and using standard library *sql.DB and *sql.Tx types directly. Changes: - Removed DBConnection and DBTransaction interfaces from database.go - Removed NewDBConnection() wrapper function - Updated TokenGenerator to use *sql.DB instead of DBConnection - Updated all validation and revocation methods to accept *sql.Tx - Updated TableManager to work with *sql.DB directly - Updated all tests to use db.Begin() instead of custom wrappers - Fixed GeneratorConfig.DB field (was DBConn) - Updated documentation in doc.go with correct API usage Benefits: - Simpler API with fewer abstractions - Works directly with database/sql standard library - Compatible with GORM (via gormDB.DB()) and Bun (share same *sql.DB) - Easier to understand and maintain - No unnecessary wrapper layers Breaking changes: - GeneratorConfig.DBConn renamed to GeneratorConfig.DB - Removed NewDBConnection() function - pass *sql.DB directly - ValidateAccess/ValidateRefresh now accept *sql.Tx instead of DBTransaction - Token.Revoke/CheckNotRevoked now accept *sql.Tx instead of DBTransaction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
273
hws/errors_test.go
Normal file
273
hws/errors_test.go
Normal file
@@ -0,0 +1,273 @@
|
||||
package hws_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"git.haelnorr.com/h/golib/hws"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type goodPage struct{}
|
||||
type badPage struct{}
|
||||
|
||||
func goodRender(code int) (hws.ErrorPage, error) {
|
||||
return goodPage{}, nil
|
||||
}
|
||||
func badRender1(code int) (hws.ErrorPage, error) {
|
||||
return badPage{}, nil
|
||||
}
|
||||
func badRender2(code int) (hws.ErrorPage, error) {
|
||||
return nil, errors.New("I'm an error")
|
||||
}
|
||||
|
||||
func (g goodPage) Render(ctx context.Context, w io.Writer) error {
|
||||
w.Write([]byte("Test write to ResponseWriter"))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b badPage) Render(ctx context.Context, w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test_AddErrorPage(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
server := createTestServer(t, &buf)
|
||||
|
||||
goodRender := goodRender
|
||||
badRender1 := badRender1
|
||||
badRender2 := badRender2
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
renderer hws.ErrorPageFunc
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
name: "Valid Renderer",
|
||||
renderer: goodRender,
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid Renderer 1",
|
||||
renderer: badRender1,
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid Renderer 2",
|
||||
renderer: badRender2,
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := server.AddErrorPage(tt.renderer)
|
||||
if tt.valid {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ThrowError(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
server := createTestServer(t, &buf)
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
|
||||
t.Run("Server not started", func(t *testing.T) {
|
||||
err := server.ThrowError(rr, req, hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "Error",
|
||||
Error: errors.New("Error"),
|
||||
})
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
startTestServer(t, server)
|
||||
defer server.Shutdown(t.Context())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
request *http.Request
|
||||
error hws.HWSError
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
name: "No HWSError.Status code",
|
||||
request: nil,
|
||||
error: hws.HWSError{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "Negative HWSError.Status code",
|
||||
request: nil,
|
||||
error: hws.HWSError{StatusCode: -1},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "No HWSError.Message",
|
||||
request: nil,
|
||||
error: hws.HWSError{StatusCode: http.StatusInternalServerError},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "No HWSError.Error",
|
||||
request: nil,
|
||||
error: hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "No request provided",
|
||||
request: nil,
|
||||
error: hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
Error: errors.New("Error"),
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "Valid",
|
||||
request: httptest.NewRequest("GET", "/", nil),
|
||||
error: hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
Error: errors.New("Error"),
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
err := server.ThrowError(rr, tt.request, tt.error)
|
||||
if tt.valid {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
t.Log(err)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
t.Run("Log level set correctly", func(t *testing.T) {
|
||||
buf.Reset()
|
||||
rr := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
err := server.ThrowError(rr, req, hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
Error: errors.New("Error"),
|
||||
Level: hws.ErrorWARN,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
_, err = buf.ReadString([]byte(" ")[0])
|
||||
loglvl, err := buf.ReadString([]byte(" ")[0])
|
||||
assert.NoError(t, err)
|
||||
if loglvl != "\x1b[33mWRN\x1b[0m " {
|
||||
err = errors.New("Log level not set correctly")
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
buf.Reset()
|
||||
err = server.ThrowError(rr, req, hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
Error: errors.New("Error"),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
_, err = buf.ReadString([]byte(" ")[0])
|
||||
loglvl, err = buf.ReadString([]byte(" ")[0])
|
||||
assert.NoError(t, err)
|
||||
if loglvl != "\x1b[31mERR\x1b[0m " {
|
||||
err = errors.New("Log level not set correctly")
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Error page doesnt render if no error page set", func(t *testing.T) {
|
||||
// Must be run before adding the error page to the test server
|
||||
rr := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
err := server.ThrowError(rr, req, hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
Error: errors.New("Error"),
|
||||
RenderErrorPage: true,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
body := rr.Body.String()
|
||||
if body != "" {
|
||||
assert.Error(t, nil)
|
||||
}
|
||||
})
|
||||
t.Run("Error page renders", func(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
// Adding the error page will carry over to all future tests and cant be undone
|
||||
server.AddErrorPage(goodRender)
|
||||
err := server.ThrowError(rr, req, hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
Error: errors.New("Error"),
|
||||
RenderErrorPage: true,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
body := rr.Body.String()
|
||||
if body == "" {
|
||||
assert.Error(t, nil)
|
||||
}
|
||||
})
|
||||
t.Run("Error page doesnt render if no told to render", func(t *testing.T) {
|
||||
// Error page already added to server
|
||||
rr := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
err := server.ThrowError(rr, req, hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
Error: errors.New("Error"),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
body := rr.Body.String()
|
||||
if body != "" {
|
||||
assert.Error(t, nil)
|
||||
}
|
||||
})
|
||||
server.Shutdown(t.Context())
|
||||
|
||||
t.Run("Doesn't error if no logger added to server", func(t *testing.T) {
|
||||
server, err := hws.NewServer(&hws.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: randomPort(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = server.AddRoutes(hws.Route{
|
||||
Path: "/",
|
||||
Method: hws.MethodGET,
|
||||
Handler: testHandler,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = server.Start(t.Context())
|
||||
require.NoError(t, err)
|
||||
<-server.Ready()
|
||||
rr := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
err = server.ThrowError(rr, req, hws.HWSError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "An error occured",
|
||||
Error: errors.New("Error"),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user