Skip to content

Commit 9972c4c

Browse files
committed
Initial testing setup
1 parent 109cd21 commit 9972c4c

File tree

6 files changed

+177
-56
lines changed

6 files changed

+177
-56
lines changed

backend/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/gorilla/mux v1.8.1
1111
github.com/jackc/pgx/v5 v5.6.0
1212
github.com/spf13/viper v1.20.1
13+
github.com/stretchr/testify v1.10.0
1314
go.uber.org/zap v1.27.0
1415
)
1516

@@ -35,6 +36,7 @@ require (
3536
github.com/Microsoft/go-winio v0.6.2 // indirect
3637
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3738
github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect
39+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3840
github.com/dustin/go-humanize v1.0.1 // indirect
3941
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect
4042
github.com/ebitengine/purego v0.8.2 // indirect
@@ -55,6 +57,7 @@ require (
5557
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
5658
github.com/pkg/errors v0.9.1 // indirect
5759
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
60+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
5861
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
5962
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
6063
github.com/sagikazarmark/locafero v0.7.0 // indirect

backend/main.go

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
pgxtrace "github.com/DataDog/dd-trace-go/contrib/jackc/pgx.v5/v2"
2323
"github.com/jackc/pgx/v5"
24+
"github.com/jackc/pgx/v5/pgxpool"
2425

2526
"github.com/google/uuid"
2627

@@ -31,43 +32,24 @@ const (
3132
connStr = "postgres://postgres:test@localhost:5432/postgres?sslmode=disable"
3233
)
3334

34-
func main() {
35-
ctx := context.Background()
36-
37-
ctx = config.ContextWithConfig(ctx, config.GetConfig(ctx))
38-
ctx = log.ContextWithLogger(ctx, log.GetLogger(ctx))
39-
40-
// Tag all logs with the version string if we have one
41-
if config.FromContext(ctx).GetString("version") != "" {
42-
ctx = log.ContextWithLogger(ctx, log.GetLogger(ctx).With(
43-
zap.String("version", config.FromContext(ctx).GetString("version")),
44-
))
45-
}
46-
47-
if config.FromContext(ctx).GetBool("tracing.enabled") {
48-
tracer.Start(
49-
tracer.WithEnv(config.FromContext(ctx).GetString("env")),
50-
tracer.WithService("cluesheet"),
51-
tracer.WithServiceVersion(config.FromContext(ctx).GetString("version")),
52-
)
53-
defer tracer.Stop()
54-
log.FromContext(ctx).Debug("started tracing")
55-
}
56-
57-
conn, err := pgxtrace.NewPool(ctx, connStr)
58-
if err != nil {
59-
log.FromContext(ctx).Fatal("failed setting up db pool", zap.Error(err))
60-
}
61-
defer conn.Close()
62-
63-
router := muxtrace.NewRouter()
64-
35+
/**
36+
* registerRoutes applies all the routes to the given mux router
37+
* It's intended to break things out of main for testing
38+
*
39+
* rootContext is the context that the router's logger and config will be read
40+
* from, it is expected to be descended from the context in main
41+
*
42+
* router is the mux router to register routes on
43+
*
44+
* conn is the database connection
45+
*/
46+
func registerRoutes(rootContext context.Context, router *muxtrace.Router, conn *pgxpool.Pool) {
6547
// Pass the logger and config in context to all requests
6648
router.Use(func(h http.Handler) http.Handler {
6749
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
6850
ctx := r.Context()
69-
ctx = config.ContextWithConfig(ctx, config.GetConfig(ctx))
70-
ctx = log.ContextWithLogger(ctx, log.GetLogger(ctx))
51+
ctx = config.ContextWithConfig(ctx, config.FromContext(rootContext))
52+
ctx = log.ContextWithLogger(ctx, log.FromContext(rootContext))
7153
r = r.WithContext(ctx)
7254
h.ServeHTTP(rw, r)
7355
})
@@ -92,7 +74,7 @@ func main() {
9274
}
9375

9476
for _, cluesheet := range cluesheets {
95-
clues, err := GetClues(ctx, conn, cluesheet.Id)
77+
clues, err := GetClues(r.Context(), conn, cluesheet.Id)
9678
if err != nil {
9779
http.Error(rw, fmt.Sprintf("failed resolving clues: '%s'", err), 500)
9880
return
@@ -129,7 +111,7 @@ func main() {
129111
return
130112
}
131113

132-
clues, err := GetClues(ctx, conn, cluesheet.Id)
114+
clues, err := GetClues(r.Context(), conn, cluesheet.Id)
133115
if err != nil {
134116
http.Error(rw, fmt.Sprintf("failed resolving clues '%s': '%s'", vars["id"], err), 500)
135117
return
@@ -166,14 +148,7 @@ func main() {
166148
return
167149
}
168150

169-
var params struct {
170-
Name string
171-
Origin *uuid.UUID
172-
Creator string
173-
Visibility *string
174-
Owners []string
175-
Groups []string
176-
}
151+
var params PostCluesheetParams
177152

178153
err = json.Unmarshal(body, &params)
179154
if err != nil {
@@ -214,7 +189,7 @@ func main() {
214189
Owners: params.Owners,
215190
Groups: params.Groups,
216191
}
217-
_, err = conn.Exec(ctx, `insert into cluesheet (id, name, origin_id, created_by, created_at, edited_by, edited_at, visibility, owners, groups) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, newSheet.Id, newSheet.Name, newSheet.Origin_id, newSheet.Created_by, newSheet.Created_at, newSheet.Edited_by, newSheet.Edited_at, newSheet.Visibility, newSheet.Owners, newSheet.Groups)
192+
_, err = conn.Exec(r.Context(), `insert into cluesheet (id, name, origin_id, created_by, created_at, edited_by, edited_at, visibility, owners, groups) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, newSheet.Id, newSheet.Name, newSheet.Origin_id, newSheet.Created_by, newSheet.Created_at, newSheet.Edited_by, newSheet.Edited_at, newSheet.Visibility, newSheet.Owners, newSheet.Groups)
218193
if err != nil {
219194
http.Error(rw, fmt.Sprintf("failed to persist cluesheet: %s", err), 500)
220195
return
@@ -445,6 +420,41 @@ func main() {
445420
rw.Write(data)
446421
})
447422

423+
}
424+
425+
func main() {
426+
ctx := context.Background()
427+
428+
ctx = config.ContextWithConfig(ctx, config.GetConfig(ctx))
429+
ctx = log.ContextWithLogger(ctx, log.GetLogger(ctx))
430+
431+
// Tag all logs with the version string if we have one
432+
if config.FromContext(ctx).GetString("version") != "" {
433+
ctx = log.ContextWithLogger(ctx, log.GetLogger(ctx).With(
434+
zap.String("version", config.FromContext(ctx).GetString("version")),
435+
))
436+
}
437+
438+
if config.FromContext(ctx).GetBool("tracing.enabled") {
439+
tracer.Start(
440+
tracer.WithEnv(config.FromContext(ctx).GetString("env")),
441+
tracer.WithService("cluesheet"),
442+
tracer.WithServiceVersion(config.FromContext(ctx).GetString("version")),
443+
)
444+
defer tracer.Stop()
445+
log.FromContext(ctx).Debug("started tracing")
446+
}
447+
448+
conn, err := pgxtrace.NewPool(ctx, connStr)
449+
if err != nil {
450+
log.FromContext(ctx).Fatal("failed setting up db pool", zap.Error(err))
451+
}
452+
defer conn.Close()
453+
454+
router := muxtrace.NewRouter()
455+
456+
registerRoutes(ctx, router, conn)
457+
448458
srv := &http.Server{
449459
Addr: ":8080",
450460
Handler: router,

backend/main_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"io"
7+
"net/http"
8+
"net/http/httptest"
9+
"testing"
10+
11+
muxtrace "github.com/DataDog/dd-trace-go/contrib/gorilla/mux/v2"
12+
pgxtrace "github.com/DataDog/dd-trace-go/contrib/jackc/pgx.v5/v2"
13+
"github.com/google/uuid"
14+
15+
"github.com/stretchr/testify/assert"
16+
17+
"csh/cluesheet/config"
18+
)
19+
20+
func TestCluesheetSnapshot(t *testing.T) {
21+
ctx := t.Context()
22+
23+
ctx = config.ContextWithConfig(ctx, config.GetConfig(ctx))
24+
25+
conn, err := pgxtrace.NewPool(ctx, connStr)
26+
t.Cleanup(conn.Close)
27+
assert.Nil(t, err, "failed to connect to postgres")
28+
29+
router := muxtrace.NewRouter()
30+
31+
registerRoutes(ctx, router, conn)
32+
33+
server := httptest.NewServer(router)
34+
t.Cleanup(server.Close)
35+
36+
var cluesheetId uuid.UUID
37+
38+
params := PostCluesheetParams{
39+
Name: "foo",
40+
Creator: "mom",
41+
Owners: []string{"mom", "willard"},
42+
Groups: []string{"rtp"},
43+
}
44+
45+
t.Run("PostCluesheet", func(t *testing.T) {
46+
buf, err := json.Marshal(params)
47+
assert.Nil(t, err, "failed to marshal params")
48+
49+
resp, err := http.Post(server.URL+"/api/v1/cluesheet", "application/json", bytes.NewReader(buf))
50+
assert.Nil(t, err, "failed to post cluesheet")
51+
52+
body, err := io.ReadAll(resp.Body)
53+
assert.Nil(t, err, "failed to read body")
54+
55+
var cluesheet Cluesheet
56+
err = json.Unmarshal(body, &cluesheet)
57+
assert.Nil(t, err, "failed to unmarshal body")
58+
59+
assert.Equal(t, params.Name, cluesheet.Name)
60+
assert.Nil(t, cluesheet.Origin_id)
61+
assert.Equal(t, params.Creator, cluesheet.Created_by)
62+
assert.Equal(t, params.Owners, cluesheet.Owners)
63+
assert.Equal(t, params.Groups, cluesheet.Groups)
64+
assert.Equal(t, "hidden", cluesheet.Visibility)
65+
assert.Nil(t, cluesheet.Clues)
66+
67+
cluesheetId = cluesheet.Id
68+
69+
t.Log("created a cluesheet", cluesheet)
70+
})
71+
72+
t.Run("GetCluesheet", func(t *testing.T) {
73+
resp, err := http.Get(server.URL + "/api/v1/cluesheet/" + cluesheetId.String())
74+
assert.Nil(t, err, "failed to get cluesheet")
75+
76+
body, err := io.ReadAll(resp.Body)
77+
assert.Nil(t, err, "failed to read body")
78+
79+
var cluesheet Cluesheet
80+
err = json.Unmarshal(body, &cluesheet)
81+
assert.Nil(t, err, "failed to unmarshal body")
82+
83+
assert.Equal(t, cluesheetId, cluesheet.Id)
84+
assert.Equal(t, params.Name, cluesheet.Name)
85+
assert.Nil(t, cluesheet.Origin_id)
86+
assert.Equal(t, params.Creator, cluesheet.Created_by)
87+
assert.Equal(t, params.Owners, cluesheet.Owners)
88+
assert.Equal(t, params.Groups, cluesheet.Groups)
89+
assert.Equal(t, "hidden", cluesheet.Visibility)
90+
assert.Nil(t, cluesheet.Clues)
91+
92+
t.Log("got a cluesheet", cluesheet)
93+
})
94+
}

backend/model.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ import (
1818
)
1919

2020
type Cluesheet struct {
21-
Id uuid.UUID
22-
Name string
23-
Origin_id *uuid.UUID /* originating cluesheet */
24-
Created_by string /* ipa unique id */
25-
Created_at time.Time /* no timezone by default */
26-
Edited_by string /* ipa unique id */
27-
Edited_at time.Time /* no timezone */
28-
Visibility string /* TODO: int key? or defined enum? I think SQL enums are difficult to work with in migrations */
29-
Owners []string
30-
Groups []string
31-
Clues *[]Clue `json:",omitzero"`
21+
Id uuid.UUID `json:"id"`
22+
Name string `json:"name"`
23+
Origin_id *uuid.UUID `json:"origin_id"` /* originating cluesheet */
24+
Created_by string `json:"created_by"` /* ipa unique id */
25+
Created_at time.Time `json:"created_at"` /* no timezone by default */
26+
Edited_by string `json:"edited_by"` /* ipa unique id */
27+
Edited_at time.Time `json:"edited_at"` /* no timezone */
28+
Visibility string `json:"visibility"` /* TODO: int key? or defined enum? I think SQL enums are difficult to work with in migrations */
29+
Owners []string `json:"owners"`
30+
Groups []string `json:"groups"`
31+
Clues *[]Clue `json:"clues,omitzero"`
3232
}
3333

3434
type Clue struct {

backend/params.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package main
2+
3+
import (
4+
"github.com/google/uuid"
5+
)
6+
7+
type PostCluesheetParams struct {
8+
Name string
9+
Origin *uuid.UUID
10+
Creator string
11+
Visibility *string
12+
Owners []string
13+
Groups []string
14+
}

compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
services:
22
db:
3-
image: postgres:17
3+
image: docker.io/library/postgres:17
44
container_name: cluesheet_postgres
55
ports:
66
- 5432:5432

0 commit comments

Comments
 (0)