udemy-go-web-1/internal/handlers/handlers_test.go

583 lines
15 KiB
Go
Raw Normal View History

package handlers
import (
"context"
2024-07-14 12:51:12 +00:00
"encoding/json"
2024-07-16 11:22:46 +00:00
"go-udemy-web-1/internal/driver"
"go-udemy-web-1/internal/models"
"log"
"net/http"
"net/http/httptest"
2024-07-15 19:36:02 +00:00
"net/url"
2024-07-16 11:22:46 +00:00
"reflect"
2024-07-14 12:51:12 +00:00
"strconv"
"strings"
"testing"
"time"
)
type postData struct {
key string
value string
}
2024-07-16 11:22:46 +00:00
// {{{ Test NewRepo
func Test_NewRepo(t *testing.T) {
var db driver.DB
repo := NewRepo(&app, &db)
if reflect.TypeOf(repo).String() != "*handlers.Repository" {
t.Errorf("repo is of type %s instead of *handlers.Repository", reflect.TypeOf(repo).String())
}
}
// }}}
// {{{ Simple get tests
var theTests = []struct {
name string
url string
method string
expectedStatusCode int
}{
{"home", "/", "GET", http.StatusOK},
{"about", "/about", "GET", http.StatusOK},
{"gq", "/generals-quarters", "GET", http.StatusOK},
{"ms", "/majors-suite", "GET", http.StatusOK},
{"sa", "/availability", "GET", http.StatusOK},
{"contact", "/contact", "GET", http.StatusOK},
}
func TestHandlers(t *testing.T) {
routes := getRoutes()
ts := httptest.NewTLSServer(routes)
defer ts.Close()
for _, e := range theTests {
resp, err := ts.Client().Get(ts.URL + e.url)
if err != nil {
t.Log(err)
t.Fatal(err)
}
if resp.StatusCode != e.expectedStatusCode {
2024-07-14 09:59:43 +00:00
t.Errorf("for %s, expected %d but got %d\n", e.name, e.expectedStatusCode, resp.StatusCode)
}
}
}
2024-07-16 11:22:46 +00:00
// }}}
// {{{ Make Reservation Tests
var makeReservationTests = []struct {
name string
roomID int
expectedStatusCode int
}{
{"ok", 1, http.StatusOK},
{"no session", 0, http.StatusTemporaryRedirect},
{"non-existant room", 100, http.StatusTemporaryRedirect},
}
func TestRepository_MakeReservation(t *testing.T) {
for _, test := range makeReservationTests {
reservation := models.Reservation{
RoomID: test.roomID,
Room: models.Room{
ID: test.roomID,
RoomName: "Room name",
},
}
req, _ := http.NewRequest("GET", "/make-reservation", nil)
ctx := getCtx(req)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
if test.roomID == 0 {
session.Put(ctx, "reservation", nil)
} else {
session.Put(ctx, "reservation", reservation)
}
handler := http.HandlerFunc(Repo.MakeReservation)
handler.ServeHTTP(rr, req)
if rr.Code != test.expectedStatusCode {
2024-07-14 09:59:43 +00:00
t.Errorf("for %s, reservation handler returned response code: got %d, wanted %d\n",
test.name, rr.Code, http.StatusOK)
}
}
}
// }}}
// {{{ PostMakeReservation tests
var postMakeReservationTests = []struct {
name string
2024-07-14 09:59:43 +00:00
reservationInfo []postData
expectedStatusCode int
}{
{
"ok",
2024-07-14 09:59:43 +00:00
[]postData{
{key: "first_name", value: "John"},
{key: "last_name", value: "Smith"},
{key: "email", value: "john@smith.com"},
{key: "phone", value: "1234"},
{key: "room_id", value: "1"},
{key: "start_date", value: "2050-01-01"},
{key: "end_date", value: "2050-01-02"},
},
2024-07-14 12:51:12 +00:00
http.StatusSeeOther,
},
{
"no_session",
2024-07-14 09:59:43 +00:00
[]postData{
{key: "first_name", value: "John"},
{key: "last_name", value: "Smith"},
{key: "email", value: "john@smith.com"},
{key: "phone", value: "1234"},
{key: "room_id", value: "0"},
{key: "start_date", value: "2050-01-01"},
{key: "end_date", value: "2050-01-02"},
},
2024-07-14 12:51:12 +00:00
http.StatusTemporaryRedirect,
},
2024-07-16 11:22:46 +00:00
{"no_post_data", []postData{}, http.StatusTemporaryRedirect},
{
"missing first name",
2024-07-14 09:59:43 +00:00
[]postData{
{key: "last_name", value: "Smith"},
{key: "email", value: "john@smith.com"},
{key: "phone", value: "1234"},
2024-07-14 12:51:12 +00:00
{key: "room_id", value: "1"},
2024-07-14 09:59:43 +00:00
{key: "start_date", value: "2050-01-01"},
{key: "end_date", value: "2050-01-02"},
},
2024-07-14 12:51:12 +00:00
http.StatusOK,
},
{
"wrong first name",
2024-07-14 09:59:43 +00:00
[]postData{
{key: "first_name", value: "J"},
{key: "last_name", value: "Smith"},
{key: "email", value: "john@smith.com"},
{key: "phone", value: "1234"},
2024-07-14 12:51:12 +00:00
{key: "room_id", value: "1"},
2024-07-14 09:59:43 +00:00
{key: "start_date", value: "2050-01-01"},
{key: "end_date", value: "2050-01-02"},
},
2024-07-14 12:51:12 +00:00
http.StatusOK,
},
{
"wrong email",
2024-07-14 09:59:43 +00:00
[]postData{
{key: "first_name", value: "John"},
{key: "last_name", value: "Smith"},
{key: "email", value: "john@smith"},
{key: "phone", value: "1234"},
2024-07-14 12:51:12 +00:00
{key: "room_id", value: "1"},
2024-07-14 09:59:43 +00:00
{key: "start_date", value: "2050-01-01"},
{key: "end_date", value: "2050-01-02"},
},
2024-07-14 12:51:12 +00:00
http.StatusOK,
},
{
"insert reservation error",
2024-07-14 09:59:43 +00:00
[]postData{
{key: "first_name", value: "John"},
{key: "last_name", value: "Smith"},
{key: "email", value: "john@smith.com"},
{key: "phone", value: "1234"},
{key: "room_id", value: "2"},
{key: "start_date", value: "2050-01-01"},
{key: "end_date", value: "2050-01-02"},
},
2024-07-14 12:51:12 +00:00
http.StatusTemporaryRedirect,
},
{
"insert room restriction error",
2024-07-14 09:59:43 +00:00
[]postData{
{key: "first_name", value: "John"},
{key: "last_name", value: "Smith"},
{key: "email", value: "john@smith.com"},
{key: "phone", value: "1234"},
{key: "room_id", value: "100"},
{key: "start_date", value: "2050-01-01"},
{key: "end_date", value: "2050-01-02"},
},
2024-07-14 12:51:12 +00:00
http.StatusTemporaryRedirect,
},
}
func TestRepository_PostMakeReservation(t *testing.T) {
for _, test := range postMakeReservationTests {
2024-07-14 12:51:12 +00:00
roomID := 1
2024-07-15 19:36:02 +00:00
reqBody := url.Values{}
2024-07-16 11:22:46 +00:00
var req *http.Request
if len(test.reservationInfo) > 0 {
2024-07-15 19:36:02 +00:00
for _, element := range test.reservationInfo {
reqBody.Add(element.key, element.value)
2024-07-14 12:51:12 +00:00
if element.key == "room_id" {
roomID, _ = strconv.Atoi(element.value)
}
}
2024-07-16 11:22:46 +00:00
req, _ = http.NewRequest("POST", "/make-reservation", strings.NewReader(reqBody.Encode()))
} else {
req, _ = http.NewRequest("POST", "/make-reservation", nil)
}
layout := "2006-01-02"
sd, _ := time.Parse(layout, "2050-01-01")
ed, _ := time.Parse(layout, "2050-01-02")
reservation := models.Reservation{
2024-07-14 12:51:12 +00:00
RoomID: roomID,
StartDate: sd,
EndDate: ed,
}
ctx := getCtx(req)
req = req.WithContext(ctx)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
rr := httptest.NewRecorder()
2024-07-14 12:51:12 +00:00
if roomID == 0 {
session.Put(ctx, "reservation", nil)
} else {
session.Put(ctx, "reservation", reservation)
}
handler := http.HandlerFunc(Repo.PostMakeReservation)
handler.ServeHTTP(rr, req)
if rr.Code != test.expectedStatusCode {
2024-07-14 12:51:12 +00:00
t.Errorf("for %s, reservation handler returned response code: got %d, wanted %d\n",
test.name, rr.Code, test.expectedStatusCode)
}
}
}
2024-07-14 12:51:12 +00:00
// }}}
// {{{ Test AvailabilityJSON
var availabilityJSONTests = []struct {
name string
queryInfo []postData
expectedStatusJSON jsonResponse
}{
{"ok", []postData{
{key: "start", value: "2050-01-01"},
{key: "end", value: "2050-01-02"},
{key: "room_id", value: "1"},
}, jsonResponse{
OK: true,
Message: "",
StartDate: "2050-01-01",
EndDate: "2050-01-02",
RoomID: "1",
}},
2024-07-14 12:57:13 +00:00
{"not available", []postData{
{key: "start", value: "2050-01-01"},
{key: "end", value: "2050-01-02"},
{key: "room_id", value: "2"},
}, jsonResponse{
OK: false,
Message: "",
StartDate: "2050-01-01",
EndDate: "2050-01-02",
RoomID: "2",
}},
{"wrong start date", []postData{
2024-07-14 12:51:12 +00:00
{key: "start", value: "2050-01"},
{key: "end", value: "2050-01-02"},
{key: "room_id", value: "1"},
}, jsonResponse{
OK: false,
Message: "Wrong startDate",
}},
2024-07-14 12:57:13 +00:00
{"wrong end date", []postData{
{key: "start", value: "2050-01-01"},
{key: "end", value: "wrong"},
{key: "room_id", value: "1"},
}, jsonResponse{
OK: false,
Message: "Wrong endDate",
}},
{"wrong room id", []postData{
{key: "start", value: "2050-01-01"},
{key: "end", value: "2050-01-02"},
{key: "room_id", value: "x"},
}, jsonResponse{
OK: false,
Message: "Wrong roomID",
}},
{"not available", []postData{
{key: "start", value: "2050-01-01"},
{key: "end", value: "2050-01-02"},
{key: "room_id", value: "100"},
}, jsonResponse{
OK: false,
Message: "Error connecting to database",
}},
2024-07-16 11:22:46 +00:00
{"no form", []postData{}, jsonResponse{
OK: false,
Message: "Internal server error",
}},
2024-07-14 12:51:12 +00:00
}
func Test_AvailabilityJSON(t *testing.T) {
for _, test := range availabilityJSONTests {
2024-07-16 11:22:46 +00:00
var req *http.Request
2024-07-15 19:36:02 +00:00
reqBody := url.Values{}
2024-07-16 11:22:46 +00:00
if len(test.queryInfo) > 0 {
for _, element := range test.queryInfo {
reqBody.Add(element.key, element.value)
}
2024-07-14 12:51:12 +00:00
2024-07-16 11:22:46 +00:00
req, _ = http.NewRequest("POST", "/make-reservation", strings.NewReader(reqBody.Encode()))
} else {
req, _ = http.NewRequest("POST", "/make-reservation", nil)
}
2024-07-14 12:51:12 +00:00
ctx := getCtx(req)
req = req.WithContext(ctx)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
rr := httptest.NewRecorder()
handler := http.HandlerFunc(Repo.AvailabilityJSON)
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Errorf("for %s, reservation handler returned response code: got %d, wanted %d\n",
test.name, rr.Code, http.StatusOK)
}
var j jsonResponse
err := json.Unmarshal(rr.Body.Bytes(), &j)
if err != nil {
t.Errorf("for %s, failed to parse json", test.name)
}
if j != test.expectedStatusJSON {
expected, _ := json.MarshalIndent(test.expectedStatusJSON, "", " ")
t.Errorf("for %s, returned json is wrong, expected: %s, returned: %s",
test.name, expected, rr.Body.String())
}
}
}
// }}}
// {{{ Test ReservationSummary
var reservationSummaryTests = []struct {
name string
haveSession bool
expectedStatusCode int
}{
{"ok", true, http.StatusOK},
{"nok", false, http.StatusTemporaryRedirect},
}
func Test_ReservationSummary(t *testing.T) {
for _, test := range reservationSummaryTests {
req, _ := http.NewRequest("GET", "/reservation-summary", nil)
ctx := getCtx(req)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
layout := "2006-01-02"
sd, _ := time.Parse(layout, "2050-01-01")
ed, _ := time.Parse(layout, "2050-01-02")
reservation := models.Reservation{
StartDate: sd,
EndDate: ed,
FirstName: "John",
LastName: "Smith",
Email: "john@smith.com",
RoomID: 1,
}
if test.haveSession {
session.Put(req.Context(), "reservation", reservation)
}
handler := http.HandlerFunc(Repo.ReservationSummary)
handler.ServeHTTP(rr, req)
if rr.Code != test.expectedStatusCode {
t.Errorf("for %s, reservation handler returned response code: got %d, wanted %d\n",
test.name, rr.Code, test.expectedStatusCode)
}
}
}
// }}}
// {{{ Test PostAvailability
var postAvailabilityTests = []struct {
name string
queryInfo []postData
expectedStatusCode int
}{
{"ok", []postData{
{key: "start", value: "2050-01-01"},
{key: "end", value: "2050-01-02"},
}, http.StatusOK},
{"database error", []postData{
{key: "start", value: "2050-01-03"},
{key: "end", value: "2050-01-04"},
}, http.StatusTemporaryRedirect},
{"no availability", []postData{
{key: "start", value: "2050-01-05"},
{key: "end", value: "2050-01-06"},
}, http.StatusSeeOther},
{"wrong start date", []postData{
{key: "start", value: "2050-05"},
{key: "end", value: "2050-01-06"},
}, http.StatusTemporaryRedirect},
{"wrong end date", []postData{
{key: "start", value: "2050-01-05"},
{key: "end", value: "01-06"},
}, http.StatusTemporaryRedirect},
2024-07-16 11:22:46 +00:00
{"wrong end date", []postData{}, http.StatusTemporaryRedirect},
}
func Test_PostAvailability(t *testing.T) {
for _, test := range postAvailabilityTests {
2024-07-16 11:22:46 +00:00
var req *http.Request
if len(test.queryInfo) > 0 {
reqBody := url.Values{}
for _, element := range test.queryInfo {
reqBody.Add(element.key, element.value)
}
2024-07-16 11:22:46 +00:00
req, _ = http.NewRequest("POST", "/availability", strings.NewReader(reqBody.Encode()))
} else {
req, _ = http.NewRequest("POST", "/availability", nil)
}
ctx := getCtx(req)
req = req.WithContext(ctx)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
rr := httptest.NewRecorder()
handler := http.HandlerFunc(Repo.PostAvailability)
handler.ServeHTTP(rr, req)
if rr.Code != test.expectedStatusCode {
t.Errorf("for %s, reservation handler returned response code: got %d, wanted %d\n",
test.name, rr.Code, test.expectedStatusCode)
}
}
}
2024-07-16 11:22:46 +00:00
// }}}
// {{{ Test ChooseRoom
var chooseRoomTests = []struct {
name string
request string
haveSession bool
expectedStatusCode int
}{
{"ok", "/choose-room/1", true, http.StatusSeeOther},
{"wrong room id", "/choose-room/1wrong", true, http.StatusTemporaryRedirect},
{"no session", "/choose-room/1", false, http.StatusTemporaryRedirect},
}
func Test_ChooseRoom(t *testing.T) {
for _, test := range chooseRoomTests {
req, _ := http.NewRequest("GET", test.request, nil)
ctx := getCtx(req)
req = req.WithContext(ctx)
layout := "2006-01-02"
sd, _ := time.Parse(layout, "2050-01-01")
ed, _ := time.Parse(layout, "2050-01-02")
reservation := models.Reservation{
StartDate: sd,
EndDate: ed,
}
if test.haveSession {
session.Put(req.Context(), "reservation", reservation)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(Repo.ChooseRoom)
handler.ServeHTTP(rr, req)
if rr.Code != test.expectedStatusCode {
t.Errorf("for %s, reservation handler returned response code: got %d, wanted %d\n",
test.name, rr.Code, test.expectedStatusCode)
}
}
}
// }}}
// {{{ Test BookRoom
var bookRoomTests = []struct {
name string
queryInfo []postData
expectedStatusCode int
}{
{"ok", []postData{
{key: "id", value: "1"},
{key: "s", value: "2050-01-01"},
{key: "e", value: "2050-01-02"},
}, http.StatusSeeOther},
{"wrong start date", []postData{
{key: "id", value: "1"},
{key: "s", value: "20-01-01"},
{key: "e", value: "2050-01-02"},
}, http.StatusTemporaryRedirect},
{"wrong end date", []postData{
{key: "id", value: "1"},
{key: "s", value: "2050-01-01"},
{key: "e", value: "2050-0-02"},
}, http.StatusTemporaryRedirect},
{"wrong room id", []postData{
{key: "id", value: "w"},
{key: "s", value: "2050-01-01"},
{key: "e", value: "2050-01-02"},
}, http.StatusTemporaryRedirect},
}
func Test_BookRoom(t *testing.T) {
for _, test := range bookRoomTests {
request := "/book-room?"
for _, element := range test.queryInfo {
request += element.key + "=" + element.value + "&"
}
request = request[:len(request)-1]
req, _ := http.NewRequest("GET", request, nil)
ctx := getCtx(req)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
handler := http.HandlerFunc(Repo.BookRoom)
handler.ServeHTTP(rr, req)
if rr.Code != test.expectedStatusCode {
t.Errorf("for %s, reservation handler returned response code: got %d, wanted %d\n",
test.name, rr.Code, test.expectedStatusCode)
}
}
}
// }}}
// {{{ Test Helpers
func getCtx(req *http.Request) context.Context {
ctx, err := session.Load(req.Context(), req.Header.Get("X-Session"))
if err != nil {
log.Println(err)
}
return ctx
}
// }}}