Skip to content

Commit

Permalink
updated loadtest file, added more tests for csv import, fixed bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
joshghent committed Oct 8, 2024
1 parent ad1c2a9 commit 16a0a35
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Ango/Get code prod droplet.bru
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ post {

body:json {
{
"batchid": "b198ca85-1ffc-4896-b0ba-c02c51f18e21",
"batchid": "11111111-1111-1111-1111-111111111111",
"clientid": "217be7c8-679c-4e08-bffc-db3451bdcdbf",
"customerid": "50b0b41b-c665-4409-a2bb-a4fc18828dc2"
}
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ run:
.PHONY: test
test:
go test ./...

.PHONY: loadtest
loadtest:
go run loadtest/main.go
23 changes: 16 additions & 7 deletions loadtest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,31 @@ package main

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"sort"
"sync"
"time"

"github.com/google/uuid"
)

const (
numRequests = 1000 // Total number of requests to send
concurrency = 100 // Number of concurrent requests
// url = "https://ango-73r94.ondigitalocean.app/api/get-code"
url = "http://209.97.180.192:3000/api/get-code"
url = "http://e80048okk804gs0k8o8c8css.209.97.180.192.sslip.io/api/v1/code/redeem"
)

var (
jsonData = []byte(`{
"batchid": "11111111-1111-1111-1111-111111111111",
"clientid": "217be7c8-679c-4e08-bffc-db3451bdcdbf",
"customerid": "fba9230a-a521-430e-aaf8-8aefbf588071"
}`)
jsonTemplate = struct {
BatchID string `json:"batchid"`
ClientID string `json:"clientid"`
CustomerID string `json:"customerid"`
}{
BatchID: "11111111-1111-1111-1111-111111111111",
ClientID: "217be7c8-679c-4e08-bffc-db3451bdcdbf",
}
codeMutex sync.Mutex
codes = make(map[string]struct{})
times []time.Duration
Expand All @@ -43,6 +48,10 @@ func main() {
for j := 0; j < numRequests/concurrency; j++ {
startTime := time.Now()

// Generate a new UUID for each request
jsonTemplate.CustomerID = uuid.New().String()
jsonData, _ := json.Marshal(jsonTemplate)

resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
failedMutex.Lock()
Expand Down
16 changes: 15 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@ func uploadCodesHandler(c *gin.Context) {
return
}

// Check if the CSV contains required columns
csvReader := csv.NewReader(file)

Check failure on line 176 in main.go

View workflow job for this annotation

GitHub Actions / test

undefined: csv
headers, err := csvReader.Read()
if err != nil {
c.JSON(400, gin.H{"error": "Failed to read CSV headers"})
return
}
if !containsColumns(headers, []string{"code", "client_id"}) {

Check failure on line 182 in main.go

View workflow job for this annotation

GitHub Actions / test

undefined: containsColumns
c.JSON(400, gin.H{"error": "CSV must contain 'code' and 'client_id' columns"})
return
}

// Reset file pointer to the beginning
file.Seek(0, 0)

// Get batch name from form data
batchName := c.PostForm("batch_name")
if batchName == "" {
Expand All @@ -197,5 +212,4 @@ func uploadCodesHandler(c *gin.Context) {
}

c.JSON(200, gin.H{"message": "Codes uploaded successfully"})

}
2 changes: 1 addition & 1 deletion service.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func uploadCodes(ctx context.Context, file io.Reader, batchID string) error {
return fmt.Errorf("invalid record format at row %d", i+2)
}
stmt += fmt.Sprintf("($%d, $%d, $%d),", i*3+1, i*3+2, i*3+3)
values = append(values, record[0], batchID, record[2])
values = append(values, record[0], batchID, record[1])
}
stmt = stmt[:len(stmt)-1] // Remove the trailing comma

Expand Down
204 changes: 204 additions & 0 deletions service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package main
import (
"bytes"
"context"
"encoding/json"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"

Expand Down Expand Up @@ -158,3 +161,204 @@ func TestGetCodeHandler_InvalidJSON(t *testing.T) {
})
}
}

func TestGetBatchesHandler(t *testing.T) {
// Setup database connection for tests
var err error
db, err = connectToDB() // Ensuring db is set globally as it might be used elsewhere
if err != nil {
t.Fatalf("Unable to connect to database: %v\n", err)
}
defer db.Close()

// Create a new gin router
router := gin.Default()
router.GET("/api/v1/batches", getBatchesHandler)

t.Run("Fetch batches successfully", func(t *testing.T) {
// Create a new request
req, _ := http.NewRequest("GET", "/api/v1/batches", nil)
w := httptest.NewRecorder()

// Serve the request
router.ServeHTTP(w, req)

// Assert the response code
assert.Equal(t, 200, w.Code)

// Parse the response body
var response []Batch
err = json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)

// Assert that we got some batches
assert.NotEmpty(t, response)

// Check the structure of the first batch
firstBatch := response[0]
assert.NotEmpty(t, firstBatch.ID)
assert.NotEmpty(t, firstBatch.Name)
assert.NotNil(t, firstBatch.Rules)
assert.NotNil(t, firstBatch.Expired)
})
}

func TestUploadCodesHandler(t *testing.T) {
// Setup database connection for tests
var err error
db, err = connectToDB() // Ensuring db is set globally as it might be used elsewhere
if err != nil {
t.Fatalf("Unable to connect to database: %v\n", err)
}
defer db.Close()

// Create a new gin router
router := gin.Default()
router.POST("/api/v1/codes/upload", uploadCodesHandler)

t.Run("Successful upload", func(t *testing.T) {
// Create a new multipart writer
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)

// Add the batch name and rules
_ = writer.WriteField("batch_name", "Test Batch")
_ = writer.WriteField("rules", `{"maxpercustomer": 2, "timelimit": 7}`)

// Create the file part
part, _ := writer.CreateFormFile("file", "test.csv")
_, _ = part.Write([]byte("client_id,batch_id,code\n217be7c8-679c-4e08-bffc-db3451bdcdbf,11111111-1111-1111-1111-111111111111,TESTCODE123"))

writer.Close()

// Create a new request
req, _ := http.NewRequest("POST", "/api/v1/codes/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
w := httptest.NewRecorder()

// Serve the request
router.ServeHTTP(w, req)

// Assert the response code
assert.Equal(t, 200, w.Code)

// Parse the response body
var response map[string]string
err = json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)

// Check the response message
assert.Equal(t, "Codes uploaded successfully", response["message"])

// Check if the record is in the database
var count int
err = db.QueryRow(context.Background(), "SELECT COUNT(*) FROM codes WHERE code = $1", "TESTCODE123").Scan(&count)
assert.NoError(t, err)
assert.Equal(t, 1, count)
})

t.Run("Incorrectly formatted CSV", func(t *testing.T) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
_ = writer.WriteField("batch_name", "Test Batch")
part, _ := writer.CreateFormFile("file", "test.csv")
_, _ = part.Write([]byte("invalid,csv,format"))
writer.Close()

req, _ := http.NewRequest("POST", "/api/v1/codes/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
w := httptest.NewRecorder()

router.ServeHTTP(w, req)

assert.Equal(t, 500, w.Code)
assert.Contains(t, w.Body.String(), "Failed to upload codes")
})

t.Run("CSV missing required columns", func(t *testing.T) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
_ = writer.WriteField("batch_name", "Test Batch")
part, _ := writer.CreateFormFile("file", "test.csv")
_, _ = part.Write([]byte("client_id,code\n217be7c8-679c-4e08-bffc-db3451bdcdbf,TESTCODE123"))
writer.Close()

req, _ := http.NewRequest("POST", "/api/v1/codes/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
w := httptest.NewRecorder()

router.ServeHTTP(w, req)

assert.Equal(t, 500, w.Code)
assert.Contains(t, w.Body.String(), "Failed to upload codes")
})

t.Run("No batch name provided", func(t *testing.T) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "test.csv")
_, _ = part.Write([]byte("client_id,batch_id,code\n217be7c8-679c-4e08-bffc-db3451bdcdbf,11111111-1111-1111-1111-111111111111,TESTCODE123"))
writer.Close()

req, _ := http.NewRequest("POST", "/api/v1/codes/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
w := httptest.NewRecorder()

router.ServeHTTP(w, req)

assert.Equal(t, 400, w.Code)
assert.Contains(t, w.Body.String(), "Batch name is required")
})

t.Run("No rules provided", func(t *testing.T) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
_ = writer.WriteField("batch_name", "Test Batch")
part, _ := writer.CreateFormFile("file", "test.csv")
_, _ = part.Write([]byte("client_id,batch_id,code\n217be7c8-679c-4e08-bffc-db3451bdcdbf,11111111-1111-1111-1111-111111111111,TESTCODE123"))
writer.Close()

req, _ := http.NewRequest("POST", "/api/v1/codes/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
w := httptest.NewRecorder()

router.ServeHTTP(w, req)

assert.Equal(t, 200, w.Code)
assert.Contains(t, w.Body.String(), "Codes uploaded successfully")
})

t.Run("No CSV provided", func(t *testing.T) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
_ = writer.WriteField("batch_name", "Test Batch")
writer.Close()

req, _ := http.NewRequest("POST", "/api/v1/codes/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
w := httptest.NewRecorder()

router.ServeHTTP(w, req)

assert.Equal(t, 400, w.Code)
assert.Contains(t, w.Body.String(), "No CSV file provided")
})

t.Run("File is not a CSV", func(t *testing.T) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
_ = writer.WriteField("batch_name", "Test Batch")
part, _ := writer.CreateFormFile("file", "test.txt")
_, _ = part.Write([]byte("This is not a CSV file"))
writer.Close()

req, _ := http.NewRequest("POST", "/api/v1/codes/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
w := httptest.NewRecorder()

router.ServeHTTP(w, req)

assert.Equal(t, 400, w.Code)
assert.Contains(t, w.Body.String(), "File must be a CSV")
})
}

0 comments on commit 16a0a35

Please sign in to comment.