Files
qv/cmd/web/handlers_test.go

922 lines
24 KiB
Go
Raw Permalink Normal View History

2024-12-28 17:58:01 +01:00
package main
import (
"bytes"
"code.dlmw.ch/dlmw/qv/internal"
"code.dlmw.ch/dlmw/qv/internal/models"
"database/sql"
2024-12-28 17:58:01 +01:00
"encoding/json"
"fmt"
"github.com/google/uuid"
2024-12-31 14:35:31 +01:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
2024-12-28 17:58:01 +01:00
"net/http"
"testing"
"time"
)
2025-01-14 17:32:44 +01:00
const baseUri = "/api/"
2024-12-28 17:58:01 +01:00
func TestCreateElection(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
id, _ := uuid.NewV7()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(id.String(), nil)
2025-01-14 17:32:44 +01:00
path := baseUri + "election"
2025-01-02 17:44:44 +01:00
2024-12-28 17:58:01 +01:00
tests := []struct {
name string
urlPath string
2024-12-31 14:35:31 +01:00
body any
2024-12-28 17:58:01 +01:00
expectedCode int
}{
{
2024-12-31 14:35:31 +01:00
name: "Valid request (small name, other language)",
2025-01-02 17:44:44 +01:00
urlPath: path,
2024-12-31 14:35:31 +01:00
body: api.CreateElectionRequest{
Choices: []string{"宮本武蔵", "伊東一刀斎"},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: false,
MaxVoters: 0,
Name: "強",
Tokens: 100,
},
expectedCode: http.StatusOK,
},
{
name: "Valid request (voters unknown with unlimited voters)",
2025-01-02 17:44:44 +01:00
urlPath: path,
2024-12-31 14:35:31 +01:00
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha"},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: false,
MaxVoters: 0,
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusOK,
},
{
name: "Valid request (with 3 choices)",
2025-01-02 17:44:44 +01:00
urlPath: path,
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha", "You"},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: false,
MaxVoters: 0,
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusOK,
},
2024-12-31 14:35:31 +01:00
{
name: "Valid request (voters unknown with max voters)",
2025-01-02 17:44:44 +01:00
urlPath: path,
2024-12-31 14:35:31 +01:00
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha"},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: false,
2025-01-21 09:24:51 +01:00
MaxVoters: 1000,
2024-12-31 14:35:31 +01:00
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusOK,
},
{
name: "Valid request (voters known with max voters)",
2025-01-02 17:44:44 +01:00
urlPath: path,
2024-12-31 14:35:31 +01:00
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha"},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: false,
MaxVoters: 10,
Name: "Guy of the year",
Tokens: 100,
},
2024-12-28 17:58:01 +01:00
expectedCode: http.StatusOK,
2024-12-31 14:35:31 +01:00
},
{
name: "Invalid request (not enough choices)",
2025-01-02 17:44:44 +01:00
urlPath: path,
2024-12-31 14:35:31 +01:00
body: api.CreateElectionRequest{
Choices: []string{"Gandhi"},
ExpiresAt: time.Unix(0, 0),
AreVotersKnown: false,
MaxVoters: 0,
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "Invalid request (expiresAt is not in the future)",
2025-01-02 17:44:44 +01:00
urlPath: path,
2024-12-31 14:35:31 +01:00
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha"},
ExpiresAt: time.Unix(0, 0),
AreVotersKnown: false,
MaxVoters: 0,
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "Invalid request (max voters must be greater than 0 for known elections)",
2025-01-02 17:44:44 +01:00
urlPath: path,
2024-12-31 14:35:31 +01:00
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha"},
ExpiresAt: time.Unix(0, 0),
AreVotersKnown: true,
MaxVoters: 0,
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "Invalid request (blank name)",
2025-01-02 17:44:44 +01:00
urlPath: path,
2024-12-31 14:35:31 +01:00
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha"},
ExpiresAt: time.Unix(0, 0),
AreVotersKnown: true,
MaxVoters: 0,
Name: "",
Tokens: 100,
},
expectedCode: http.StatusUnprocessableEntity,
2024-12-28 17:58:01 +01:00
},
{
name: "Invalid request (choices are not unique)",
2025-01-02 17:44:44 +01:00
urlPath: path,
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Gandhi"},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: false,
MaxVoters: 0,
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "Invalid request (choices contain blank entries)",
2025-01-02 17:44:44 +01:00
urlPath: path,
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha", ""},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: false,
MaxVoters: 0,
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusUnprocessableEntity,
},
2025-01-21 09:24:51 +01:00
{
name: "Invalid request for known voters election (max voters greater than 100)",
urlPath: path,
body: api.CreateElectionRequest{
Choices: []string{"Gandhi", "Buddha", ""},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: true,
MaxVoters: 101,
Name: "Guy of the year",
Tokens: 100,
},
expectedCode: http.StatusUnprocessableEntity,
},
2024-12-28 17:58:01 +01:00
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
2024-12-31 14:35:31 +01:00
requestBody, err := json.Marshal(tt.body)
2024-12-28 17:58:01 +01:00
if err != nil {
t.Fatal(err)
}
2024-12-31 14:35:31 +01:00
code, _, _ := server.post(t, tt.urlPath, bytes.NewReader(requestBody))
assert.Equal(t, tt.expectedCode, code)
2024-12-28 17:58:01 +01:00
})
}
}
func TestCreateElection_KnownVoters(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
electionId, _ := uuid.NewV7()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(electionId.String(), nil)
mockVoters := app.voters.(*mockVoterModel)
mockVoters.
On("InsertMultiple", mock.Anything, mock.Anything).
Return([]int{1}, nil)
path := baseUri + "election"
requestBody := api.CreateElectionRequest{
Choices: []string{"宮本武蔵", "伊東一刀斎"},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: true,
MaxVoters: 100,
Name: "強",
Tokens: 100,
}
requestBodyJson, err := json.Marshal(requestBody)
if err != nil {
t.Fatal(err)
}
code, _, body := server.post(t, path, bytes.NewReader(requestBodyJson))
assert.Equal(t, http.StatusOK, code)
var voterIdentities struct {
VoterIdentities []string
}
err = json.Unmarshal([]byte(body), &voterIdentities)
if err != nil {
t.Fatal(err)
}
assert.Len(t, voterIdentities.VoterIdentities, 100)
}
func TestCreateElection_ServerError(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(0, fmt.Errorf(""))
2025-01-14 17:32:44 +01:00
path := baseUri + "election"
requestBody := api.CreateElectionRequest{
Choices: []string{"宮本武蔵", "伊東一刀斎"},
ExpiresAt: time.Now().Add(24 * time.Hour),
AreVotersKnown: false,
MaxVoters: 0,
Name: "強",
Tokens: 100,
}
requestBodyJson, err := json.Marshal(requestBody)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
assert.Equal(t, 500, code)
}
2025-01-09 18:12:18 +01:00
func TestCreateVotes_UnknownVotersElection(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
id, _ := uuid.NewV7()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return(&models.Election{
ID: id.String(),
Name: "Guy of the year",
Tokens: 100,
AreVotersKnown: false,
MaxVoters: 100,
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(24 * time.Hour),
Choices: []string{"Gandhi", "Buddha"},
}, nil)
mockVoters := app.voters.(*mockVoterModel)
mockVoters.
On("Exists", mock.Anything, mock.Anything).
Return(false, nil)
mockVoters.
2025-01-13 20:06:55 +01:00
On("InsertMultiple", mock.Anything, mock.Anything).
Return([]int{1}, nil)
mockVoters.
On("CountByElection", mock.Anything).
Return(0, nil)
mockVotes := app.votes.(*mockVoteModel)
mockVotes.
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(1, nil)
2025-01-14 17:32:44 +01:00
path := baseUri + "election/1/votes"
tests := []struct {
name string
urlPath string
body any
expectedCode int
}{
{
name: "Valid request for unknown voters election",
urlPath: path,
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: nil,
},
expectedCode: http.StatusCreated,
},
{
name: "Invalid request for unknown voters election (too many tokens used)",
urlPath: path,
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 41},
},
VoterIdentity: nil,
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "Invalid request for unknown voters election (choice doesn't exist)",
urlPath: path,
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddh", Tokens: 40},
},
VoterIdentity: nil,
},
expectedCode: http.StatusUnprocessableEntity,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
requestBody, err := json.Marshal(tt.body)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, tt.urlPath, bytes.NewReader(requestBody))
assert.Equal(t, tt.expectedCode, code)
})
}
}
2025-01-09 18:12:18 +01:00
func TestCreateVotes_KnownVotersElection(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
id, _ := uuid.NewV7()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return(&models.Election{
ID: id.String(),
Name: "Guy of the year",
Tokens: 100,
AreVotersKnown: true,
MaxVoters: 100,
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(24 * time.Hour),
Choices: []string{"Gandhi", "Buddha"},
}, nil)
EXISTING_VOTER_IDENTITY := "EXISTING_VOTER_IDENTITY"
NON_EXISTING_VOTER_IDENTITY := "NON_EXISTING_VOTER_IDENTITY"
mockVoters := app.voters.(*mockVoterModel)
mockVoters.
On("Exists", EXISTING_VOTER_IDENTITY, mock.Anything).
Return(true, nil)
mockVoters.
On("Exists", NON_EXISTING_VOTER_IDENTITY, mock.Anything).
Return(false, nil)
mockVotes := app.votes.(*mockVoteModel)
mockVotes.
On("Insert", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(1, nil)
mockVotes.
On("Exists", mock.Anything, mock.Anything).
Return(false, nil)
2025-01-14 17:32:44 +01:00
path := baseUri + "election/1/votes"
tests := []struct {
name string
urlPath string
body any
expectedCode int
}{
{
name: "Valid request for unknown voters election",
urlPath: path,
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: &EXISTING_VOTER_IDENTITY,
},
expectedCode: http.StatusCreated,
},
{
name: "Invalid request for unknown voters election (non-existing voter identity)",
urlPath: path,
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: &NON_EXISTING_VOTER_IDENTITY,
},
expectedCode: http.StatusUnprocessableEntity,
},
2025-01-09 18:12:18 +01:00
{
name: "Invalid request for unknown voters election (no voter identity provided)",
urlPath: path,
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: nil,
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "Invalid request for unknown voters election (too many tokens used)",
urlPath: path,
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 41},
},
VoterIdentity: &EXISTING_VOTER_IDENTITY,
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "Invalid request for unknown voters election (choice doesn't exist)",
urlPath: path,
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddh", Tokens: 40},
},
VoterIdentity: &EXISTING_VOTER_IDENTITY,
},
expectedCode: http.StatusUnprocessableEntity,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
requestBody, err := json.Marshal(tt.body)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, tt.urlPath, bytes.NewReader(requestBody))
assert.Equal(t, tt.expectedCode, code)
})
}
}
func TestCreateVotes_NonExistingElection(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return((*models.Election)(nil), sql.ErrNoRows)
2025-01-14 17:32:44 +01:00
path := baseUri + "election/1/votes"
requestBody := api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: nil,
}
requestBodyJson, err := json.Marshal(requestBody)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
assert.Equal(t, http.StatusNotFound, code)
}
func TestCreateVotes_NonUuidElectionID(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return((*models.Election)(nil), sql.ErrNoRows)
2025-01-14 17:32:44 +01:00
path := baseUri + "election/1a/votes"
requestBody := api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: nil,
}
requestBodyJson, err := json.Marshal(requestBody)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
assert.Equal(t, http.StatusNotFound, code)
}
2025-01-09 18:12:18 +01:00
func TestCreateVotes_AlreadyVoted(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
unknownVotersElectionId, _ := uuid.NewV7()
2025-01-09 18:12:18 +01:00
unknownVotersElection := models.Election{
ID: unknownVotersElectionId.String(),
2025-01-09 18:12:18 +01:00
Name: "Guy of the year",
Tokens: 100,
AreVotersKnown: false,
MaxVoters: 10,
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(24 * time.Hour),
Choices: []string{"Gandhi", "Buddha"},
}
2025-01-09 18:12:18 +01:00
knownVotersElection := unknownVotersElection
knownVotersElectionId, _ := uuid.NewV7()
knownVotersElection.ID = knownVotersElectionId.String()
2025-01-09 18:12:18 +01:00
knownVotersElection.AreVotersKnown = true
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", knownVotersElectionId.String()).
2025-01-09 18:12:18 +01:00
Return(&knownVotersElection, nil)
mockElections.
On("GetById", unknownVotersElectionId.String()).
2025-01-09 18:12:18 +01:00
Return(&unknownVotersElection, nil)
mockVotes := app.votes.(*mockVoteModel)
mockVotes.
On("Exists", mock.Anything, mock.Anything).
Return(true, nil)
mockVoters := app.voters.(*mockVoterModel)
mockVoters.
On("Exists", mock.Anything, mock.Anything).
Return(true, nil)
layout := baseUri + "election/%v/votes"
knownVotersElectionPath := fmt.Sprintf(layout, unknownVotersElectionId)
unknownVotersElectionPath := fmt.Sprintf(layout, knownVotersElectionId)
2025-01-09 18:12:18 +01:00
voterIdentity := "anything"
tests := []struct {
name string
urlPath string
body any
expectedCode int
}{
{
name: "Invalid request for known voters election (already voted)",
urlPath: knownVotersElectionPath,
2025-01-09 18:12:18 +01:00
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: &voterIdentity,
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "Invalid request for unknown voters election (already voted)",
urlPath: unknownVotersElectionPath,
2025-01-09 18:12:18 +01:00
body: api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: &voterIdentity,
},
expectedCode: http.StatusUnprocessableEntity,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
requestBody, err := json.Marshal(tt.body)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, tt.urlPath, bytes.NewReader(requestBody))
assert.Equal(t, tt.expectedCode, code)
})
}
}
func TestCreateVotes_UnknownVotersElectionMaxVotersReached(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
id, _ := uuid.NewV7()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return(&models.Election{
ID: id.String(),
Name: "Guy of the year",
Tokens: 100,
AreVotersKnown: false,
MaxVoters: 10,
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(24 * time.Hour),
Choices: []string{"Gandhi", "Buddha"},
}, nil)
mockVoters := app.voters.(*mockVoterModel)
mockVoters.
On("Exists", mock.Anything, mock.Anything).
Return(false, nil)
mockVoters.
2025-01-13 20:06:55 +01:00
On("InsertMultiple", mock.Anything, mock.Anything).
Return([]int{1}, nil)
mockVoters.
On("CountByElection", mock.Anything).
Return(10, nil)
2025-01-14 17:32:44 +01:00
path := baseUri + "election/1/votes"
requestBody := api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: nil,
}
requestBodyJson, err := json.Marshal(requestBody)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
assert.Equal(t, http.StatusUnprocessableEntity, code)
}
2025-01-09 18:26:22 +01:00
func TestCreateVotes_ExpiredElection(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
id, _ := uuid.NewV7()
2025-01-09 18:26:22 +01:00
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return(&models.Election{
ID: id.String(),
2025-01-09 18:26:22 +01:00
Name: "Guy of the year",
Tokens: 100,
AreVotersKnown: false,
MaxVoters: 10,
CreatedAt: time.UnixMilli(1),
ExpiresAt: time.UnixMilli(100000),
Choices: []string{"Gandhi", "Buddha"},
}, nil)
mockVoters := app.voters.(*mockVoterModel)
mockVoters.
On("Exists", mock.Anything, mock.Anything).
Return(false, nil)
mockVoters.
On("Insert", mock.Anything, mock.Anything).
Return(1, nil)
mockVoters.
On("CountByElection", mock.Anything).
Return(10, nil)
2025-01-14 17:32:44 +01:00
path := baseUri + "election/1/votes"
2025-01-09 18:26:22 +01:00
requestBody := api.CreateVotesRequest{
Choices: []struct {
ChoiceText string `json:"choiceText"`
Tokens int `json:"tokens"`
}{
{ChoiceText: "Gandhi", Tokens: 60},
{ChoiceText: "Buddha", Tokens: 40},
},
VoterIdentity: nil,
}
requestBodyJson, err := json.Marshal(requestBody)
if err != nil {
t.Fatal(err)
}
code, _, _ := server.post(t, path, bytes.NewReader(requestBodyJson))
assert.Equal(t, http.StatusUnprocessableEntity, code)
}
2025-01-14 17:28:45 +01:00
func TestGetElectionResults(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
electionID, _ := uuid.NewV7()
2025-01-14 17:28:45 +01:00
votes := []models.Vote{
{
VoterIdentity: "Voter1",
ElectionID: electionID.String(),
2025-01-14 17:28:45 +01:00
ChoiceText: "Choice1",
Tokens: 2,
CreatedAt: time.Now(),
},
{
VoterIdentity: "Voter2",
ElectionID: electionID.String(),
2025-01-14 17:28:45 +01:00
ChoiceText: "Choice2",
Tokens: 4,
CreatedAt: time.Now(),
},
{
VoterIdentity: "Voter3",
ElectionID: electionID.String(),
2025-01-14 17:28:45 +01:00
ChoiceText: "Choice3",
Tokens: 6,
CreatedAt: time.Now(),
},
{
VoterIdentity: "Voter4",
ElectionID: electionID.String(),
2025-01-14 17:28:45 +01:00
ChoiceText: "Choice1",
Tokens: 8,
CreatedAt: time.Now(),
},
{
VoterIdentity: "Voter5",
ElectionID: electionID.String(),
2025-01-14 17:28:45 +01:00
ChoiceText: "Choice2",
Tokens: 10,
CreatedAt: time.Now(),
},
}
mockVotes := app.votes.(*mockVoteModel)
mockVotes.
On("GetByElection", electionID.String()).
2025-01-14 17:28:45 +01:00
Return(&votes, nil)
path := baseUri + fmt.Sprintf("election/%v/results", electionID)
2025-01-14 17:28:45 +01:00
code, _, body := server.get(t, path)
assert.Equal(t, http.StatusOK, code)
var response api.ElectionResultsResponse
err := json.Unmarshal([]byte(body), &response)
if err != nil {
t.Fatal(err)
}
for _, result := range *response.Results {
switch result.Choice {
case "Choice1":
assert.Equal(t, 3, result.Votes)
case "Choice2":
assert.Equal(t, 5, result.Votes)
case "Choice3":
assert.Equal(t, 2, result.Votes)
default:
t.Fatalf("Unexpected choice: %s", result.Choice)
}
}
}
2025-01-14 17:32:44 +01:00
2025-01-17 13:59:37 +01:00
func TestGetElectionResults_NotFound(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
mockVotes := app.votes.(*mockVoteModel)
mockVotes.
On("GetByElection", mock.Anything).
Return(&[]models.Vote{}, sql.ErrNoRows)
path := baseUri + "election/1/results"
code, _, body := server.get(t, path)
assert.Equal(t, http.StatusNotFound, code)
var response api.ElectionResultsResponse
err := json.Unmarshal([]byte(body), &response)
if err != nil {
t.Fatal(err)
}
}
2025-01-17 14:55:54 +01:00
func TestGetElection_Found(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
id, _ := uuid.NewV7()
2025-01-17 14:55:54 +01:00
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return(&models.Election{
ID: id.String(),
2025-01-17 14:55:54 +01:00
Name: "Guy of the year",
Tokens: 100,
AreVotersKnown: false,
MaxVoters: 10,
CreatedAt: time.UnixMilli(1),
ExpiresAt: time.UnixMilli(100000),
Choices: []string{"Gandhi", "Buddha"},
}, nil)
path := baseUri + "election/1"
code, _, _ := server.get(t, path)
assert.Equal(t, http.StatusOK, code)
}
func TestGetElection_NotFound(t *testing.T) {
app := newTestApplication(t)
server := newTestServer(t, app.routes())
defer server.Close()
mockElections := app.elections.(*mockElectionModel)
mockElections.
On("GetById", mock.Anything).
Return((*models.Election)(nil), sql.ErrNoRows)
path := baseUri + "election/1"
code, _, _ := server.get(t, path)
assert.Equal(t, http.StatusNotFound, code)
}