gull/handlers/handlers_test.go

206 lines
5.8 KiB
Go
Raw Permalink Normal View History

2020-05-14 10:23:42 +02:00
package handlers
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gorilla/mux"
)
// Initialize an in-memory database for testing
func setup() *App {
app := &App{}
app.Initialize("sqlite3", ":memory:")
return app
}
// Discard the in-memory database
func teardown(app *App) {
app.DB.Close()
}
func TestCreate(t *testing.T) {
tests := map[string]struct {
url string
alias string
status int
}{
"https": {url: "https://google.com", alias: "ggls", status: http.StatusCreated},
"http": {url: "http://google.com", alias: "ggl", status: http.StatusCreated},
"url already exists": {url: "http://google.com", alias: "", status: http.StatusCreated},
"alias already exists": {url: "http://asdf.com", alias: "ggl", status: http.StatusCreated},
"both url and alias exist": {url: "http://asdf.com", alias: "ggl", status: http.StatusCreated},
}
app := setup()
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
2020-05-25 05:17:43 +02:00
origURL := &urlEntry{
2020-05-14 10:23:42 +02:00
URL: tc.url,
Alias: tc.alias,
}
JSONData, _ := json.Marshal(origURL)
// Set up a new request.
req, err := http.NewRequest("POST", "/", bytes.NewBuffer(JSONData))
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
http.HandlerFunc(app.CreateShortURL).ServeHTTP(rr, req)
// Test that the status code is correct.
if status := rr.Code; status != tc.status {
t.Errorf("Status code is invalid. Expected %d. Got %d instead", tc.status, status)
}
// Alias might have been randomly generated so get from result instead
2020-05-25 05:17:43 +02:00
temp := &jsonRes{}
2020-05-14 10:23:42 +02:00
json.Unmarshal(rr.Body.Bytes(), temp)
origURL.Alias = strings.TrimPrefix(temp.ShortURL, "/s/")
// Test that the created url entry is correct.
2020-05-25 05:17:43 +02:00
createdURL := urlEntry{}
2020-05-14 10:23:42 +02:00
app.DB.Where("url = ?", origURL.URL).First(&createdURL)
if createdURL != *origURL {
t.Errorf("Created entry is invalid. Expected %+v. Got %+v instead", origURL, createdURL)
}
})
}
teardown(app)
}
func TestInvalidCreate(t *testing.T) {
tests := map[string]struct {
url string
alias string
status int
}{
"bad": {url: "https/agoogle.com", alias: "ggls", status: http.StatusBadRequest},
"no colon": {url: "http//google.com", alias: "ggl", status: http.StatusBadRequest},
"empty": {url: "", alias: "", status: http.StatusBadRequest},
"asdf": {url: "asdf", alias: "", status: http.StatusBadRequest},
"spaces": {url: "https://google.com", alias: "oh no spaces", status: http.StatusBadRequest},
"question mark": {url: "https://google.com", alias: "huh?", status: http.StatusBadRequest},
"percent": {url: "https://google.com", alias: "test%20stuff", status: http.StatusBadRequest},
2020-05-14 10:23:42 +02:00
}
app := setup()
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
2020-05-25 05:17:43 +02:00
origURL := &urlEntry{
2020-05-14 10:23:42 +02:00
URL: tc.url,
Alias: tc.alias,
}
JSONData, _ := json.Marshal(origURL)
// Set up a new request.
req, err := http.NewRequest("POST", "application/json", bytes.NewBuffer(JSONData))
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
http.HandlerFunc(app.CreateShortURL).ServeHTTP(rr, req)
// Test that the status code is correct.
if status := rr.Code; status != tc.status {
t.Errorf("Status code is invalid. Expected %d. Got %d instead", tc.status, status)
}
// Make sure no entries are created
2020-05-25 05:17:43 +02:00
createdEntry := &urlEntry{}
2020-05-14 10:23:42 +02:00
if !app.DB.First(createdEntry).RecordNotFound() {
t.Errorf("Should not have created an entry")
}
})
}
teardown(app)
}
func TestCorruptCreate(t *testing.T) {
app := setup()
JSONData, _ := json.Marshal([]byte("garbage data"))
// Set up a new request.
req, err := http.NewRequest("POST", "application/json", bytes.NewBuffer(JSONData))
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
http.HandlerFunc(app.CreateShortURL).ServeHTTP(rr, req)
// Test that the status code is correct.
if status := rr.Code; status != http.StatusBadRequest {
t.Errorf("Status code is invalid. Expected %d. Got %d instead", http.StatusBadRequest, status)
}
// Make sure no entries are created
2020-05-25 05:17:43 +02:00
createdEntry := &urlEntry{}
2020-05-14 10:23:42 +02:00
if !app.DB.First(createdEntry).RecordNotFound() {
t.Errorf("Should not have created an entry")
}
teardown(app)
}
func TestGetURL(t *testing.T) {
seed := []struct {
url string
alias string
}{
{url: "https://google.com", alias: "ggl"},
}
tests := map[string]struct {
url string
alias string
status int
}{
"exists": {url: "https://google.com", alias: "ggl", status: http.StatusFound},
"nonexistent": {url: "", alias: "whoami", status: http.StatusNotFound},
}
app := setup()
for _, u := range seed {
2020-05-25 05:17:43 +02:00
origURL := &urlEntry{
2020-05-14 10:23:42 +02:00
URL: u.url,
Alias: u.alias,
}
app.DB.Create(origURL)
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
// Set up a new request.
req, err := http.NewRequest("GET", "/s/"+tc.alias, nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
r := mux.NewRouter()
r.HandleFunc("/s/{alias:.*}", app.GetURL).Methods("GET")
r.ServeHTTP(rr, req)
// Test that the status code is correct.
if status := rr.Code; status != tc.status {
t.Errorf("Status code is invalid. Expected %d. Got %d instead", tc.status, status)
}
if rr.HeaderMap.Get("Location") != tc.url {
t.Errorf("Created entry is invalid. Expected %+v. Got %+v instead", tc.url, rr.HeaderMap.Get("Location"))
}
})
}
teardown(app)
}
func TestFailDBBadDriver(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
}
}()
app := &App{}
app.Initialize("baddriver", ":memory:")
}
func TestFailDBBadURI(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
}
}()
app := &App{}
app.Initialize("sqlite3", "./garbagepath/data.db")
}