Files
qv/cmd/web/main_integration.go

282 lines
5.2 KiB
Go

//go:build integration
package main
import (
"code.dlmw.ch/dlmw/qv/internal/migrations"
"code.dlmw.ch/dlmw/qv/internal/models"
"context"
"database/sql"
"errors"
"fmt"
. "github.com/Eun/go-hit"
"log/slog"
"net/http"
"os"
"strings"
"time"
)
var addr = ":8080"
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
err := os.Remove("./qv.integration.sqlite")
if err != nil {
logger.Error("couldn't delete qv.integration.sqlite")
}
db, err := openDb()
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}
defer db.Close()
err = migrations.Run(db)
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}
app := &application{
logger: logger,
elections: &models.ElectionModel{DB: db},
voters: &models.VoterModel{DB: db},
votes: &models.VoteModel{DB: db},
}
logger.Info("Starting integration tests server", "addr", addr)
srv := &http.Server{
Addr: addr,
Handler: app.routes(),
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
IdleTimeout: time.Minute,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
go func() {
logger.Info("Starting integration test server", "addr", addr)
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
logger.Error("Server error", "error", err)
os.Exit(1)
}
}()
time.Sleep(1 * time.Second) // wait until srv starts
runTests()
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
srv.Shutdown(ctx)
}
func openDb() (*sql.DB, error) {
db, err := sql.Open("sqlite3", "./qv.integration.sqlite?_foreign_keys=on")
if err == nil {
err = db.Ping()
}
return db, err
}
func runTests() {
runCreateElectionTests()
runCreateVotesTests()
}
func runCreateElectionTests() {
template := CombineSteps(
Post("http://127.0.0.1:8080/api/election"),
)
MustDo(
template,
Send().Body().String(`
{
"name": "Guy of the year",
"tokens": 100,
"areVotersKnown": false,
"maxVoters": 10,
"expiresAt": "2124-12-31T14:15:22Z",
"choices": [
"Gandhi",
"Buddha"
]
}`),
Expect().Status().Equal(http.StatusOK),
Expect().Headers("Location").Contains("/election/1"),
)
MustDo(
template,
Send().Body().String(`
{
"name": "Guy of the year",
"tokens": 100,
"areVotersKnown": false,
"maxVoters": 0,
"expiresAt": "2124-12-31T14:15:22Z",
"choices": [
"Gandhi",
"Buddha"
]
}`),
Expect().Status().Equal(http.StatusOK),
Expect().Headers("Location").Contains("/election/2"),
)
MustDo(
template,
Send().Body().String(`
{
"name": "Guy of the year",
"tokens": 100,
"areVotersKnown": true,
"maxVoters": 10,
"expiresAt": "2124-12-31T14:15:22Z",
"choices": [
"Gandhi",
"Buddha"
]
}`),
Expect().Status().Equal(http.StatusOK),
Expect().Headers("Location").Contains("/election/3"),
Expect().Body().JSON().JQ(".voterIdentities").Len().Equal(10),
)
MustDo(
template,
Send().Body().String(`
{
"name": "Guy of the year",
"tokens": 100,
"areVotersKnown": true,
"maxVoters": -1,
"expiresAt": "2124-12-31T14:15:22Z",
"choices": [
"Gandhi",
"Buddha"
]
}`),
Expect().Status().Equal(http.StatusUnprocessableEntity),
)
MustDo(
template,
Send().Body().String(`
{
"name": "Guy of the year",
"tokens": 100,
"areVotersKnown": false,
"maxVoters": -1,
"expiresAt": "2124-12-31T14:15:22Z",
"choices": [
"Gandhi"
]
}`),
Expect().Status().Equal(http.StatusUnprocessableEntity),
)
MustDo(
template,
Send().Body().String(`
{
"name": "Guy of the year",
"tokens": 100,
"areVotersKnown": false,
"maxVoters": 10,
"expiresAt": "2018-12-31T14:15:22Z",
"choices": [
"Gandhi",
"Buddha"
]
}`),
Expect().Status().Equal(http.StatusUnprocessableEntity),
)
}
func runCreateVotesTests() {
uri := "http://127.0.0.1:8080/api/election/%v/votes"
MustDo(
Post(fmt.Sprintf(uri, "1")),
Send().Body().String(`
{
"choices": [
{
"choiceText": "Buddha",
"tokens": 90
},
{
"choiceText": "Gandhi",
"tokens": 10
}
]
}`),
Expect().Status().Equal(http.StatusCreated),
)
MustDo(
Post(fmt.Sprintf(uri, "3")),
Send().Body().String(`
{
"choices": [
{
"choiceText": "Buddha",
"tokens": 90
},
{
"choiceText": "Gandhi",
"tokens": 10
}
]
}`),
Expect().Status().Equal(http.StatusUnprocessableEntity),
)
voterIdentities := make([]string, 0)
locationHeader := ""
MustDo(
Post("http://127.0.0.1:8080/api/election"),
Send().Body().String(`
{
"name": "Guy of the year",
"tokens": 100,
"areVotersKnown": true,
"maxVoters": 10,
"expiresAt": "2124-12-31T14:15:22Z",
"choices": [
"Gandhi",
"Buddha"
]
}`),
Expect().Status().Equal(http.StatusOK),
Store().Response().Body().JSON().JQ(".voterIdentities").In(&voterIdentities),
Store().Response().Headers("Location").In(&locationHeader),
)
electionId := strings.Split(locationHeader, "/")[2]
MustDo(
Post(fmt.Sprintf(uri, electionId)),
Send().Body().String(fmt.Sprintf(`
{
"voterIdentity": "%v",
"choices": [
{
"choiceText": "Buddha",
"tokens": 90
},
{
"choiceText": "Gandhi",
"tokens": 10
}
]
}`, voterIdentities[0])),
Expect().Status().Equal(http.StatusCreated),
)
}