//go:build integration package main import ( "code.dlmw.ch/dlmw/qv/internal/migrations" "code.dlmw.ch/dlmw/qv/internal/models" "context" "database/sql" "errors" . "github.com/Eun/go-hit" "log/slog" "net/http" "os" "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}, } 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() } 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), ) }