package server import ( "bytes" "encoding/json" "fmt" "github.com/gofiber/fiber/v2" "github.com/oapi-codegen/runtime/types" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "gitlab.mareshq.com/hq/yggdrasil/internal/money" "gitlab.mareshq.com/hq/yggdrasil/pkg/slug" "gitlab.mareshq.com/hq/yggdrasil/pkg/training" "net/http" "net/http/httptest" "net/url" "testing" "time" ) func doGet(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) { u, err := url.Parse(rawURL) if err != nil { t.Fatalf("Invalid url: %s", rawURL) } req := httptest.NewRequest("GET", u.RequestURI(), nil) req.Header.Add("Accept", "application/json") req.Host = u.Host return app.Test(req) } func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) (*http.Response, error) { u, err := url.Parse(rawURL) if err != nil { t.Fatalf("Invalid url: %s", rawURL) } buf, err := json.Marshal(jsonBody) if err != nil { return nil, err } req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf)) req.Header.Add("Accept", "application/json") req.Header.Add("Content-Type", "application/json") req.Host = u.Host return app.Test(req) } func doPut(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) (*http.Response, error) { u, err := url.Parse(rawURL) if err != nil { t.Fatalf("Invalid url: %s", rawURL) } buf, err := json.Marshal(jsonBody) if err != nil { return nil, err } req := httptest.NewRequest("PUT", u.RequestURI(), bytes.NewReader(buf)) req.Header.Add("Accept", "application/json") req.Header.Add("Content-Type", "application/json") req.Host = u.Host return app.Test(req) } func doDelete(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) { u, err := url.Parse(rawURL) if err != nil { t.Fatalf("Invalid url: %s", rawURL) } req := httptest.NewRequest("DELETE", u.RequestURI(), nil) req.Header.Add("Accept", "application/json") req.Host = u.Host return app.Test(req) } func TestServer(t *testing.T) { //var err error trainingRepo := training.NewInMemoryTrainingRepository() trainingDateRepo := training.NewInMemoryDateRepository() trainingDateAttendeeRepo := training.NewInMemoryAttendeeRepository() handlers := NewAPIHandlers(trainingRepo, trainingDateRepo, trainingDateAttendeeRepo) app := NewTestingServer(handlers) t.Run("Add training", func(t *testing.T) { newTraining := NewTraining{ Name: "Testing Training", Description: "This is a test training", Days: 1, Pricing: []TrainingPrice{ { Amount: "200", Currency: "EUR", Type: OPEN, }, { Amount: "1000", Currency: "EUR", Type: CORPORATE, }, { Amount: "4900", Currency: "CZK", Type: OPEN, }, { Amount: "24000", Currency: "CZK", Type: CORPORATE, }, }, } slugString := slug.NewString(newTraining.Name) rr, _ := doPost(t, app, "/v1/trainings", newTraining) assert.Equal(t, http.StatusCreated, rr.StatusCode) var resultTraining Training err := json.NewDecoder(rr.Body).Decode(&resultTraining) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, newTraining.Name, resultTraining.Name) assert.Equal(t, slugString, resultTraining.Slug) assert.Equal(t, newTraining.Description, resultTraining.Description) assert.Equal(t, newTraining.Days, resultTraining.Days) assert.Equal(t, newTraining.Pricing, resultTraining.Pricing) }) t.Run("Training not found", func(t *testing.T) { rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d", 9999999)) assert.Equal(t, http.StatusNotFound, rr.StatusCode) var trainingError NotFoundError err := json.NewDecoder(rr.Body).Decode(&trainingError) assert.NoError(t, err, "error getting response", err) assert.Equal(t, http.StatusNotFound, trainingError.Status) }) t.Run("List all trainings", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training", Description: "This is a test training", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) rr, _ := doGet(t, app, "/v1/trainings") assert.Equal(t, http.StatusOK, rr.StatusCode) var trainings []Training err := json.NewDecoder(rr.Body).Decode(&trainings) assert.NoError(t, err, "error unmarshalling response") assert.Greater(t, len(trainings), 0) for _, trr := range trainings { assert.NotEmpty(t, trr.Name) assert.NotEmpty(t, trr.Slug) assert.NotEmpty(t, trr.Description) assert.NotEmpty(t, trr.Days) } }) t.Run("Update training", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training", Description: "This is a test training", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) updatedSlug := "updated-training" updTr := NewTraining{ Name: "Updated Training", Slug: &updatedSlug, Description: tr.Description, Days: tr.Days, Pricing: []TrainingPrice{ { Amount: decimal.NewFromInt(200).String(), Currency: money.EUR, Type: OPEN, }, }, } rr, _ := doPut(t, app, fmt.Sprintf("/v1/trainings/%d", tr.ID), updTr) assert.Equal(t, http.StatusOK, rr.StatusCode) var trr Training err := json.NewDecoder(rr.Body).Decode(&trr) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, updTr.Name, trr.Name) assert.Equal(t, updatedSlug, trr.Slug) }) t.Run("Delete training", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training", Description: "This is a test training", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d", tr.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) var trr Training err := json.NewDecoder(rr.Body).Decode(&trr) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, tr.ID, trr.Id) drr, _ := doDelete(t, app, fmt.Sprintf("/v1/trainings/%d", tr.ID)) assert.Equal(t, http.StatusNoContent, drr.StatusCode) rr, _ = doGet(t, app, fmt.Sprintf("/v1/trainings/%d", tr.ID)) assert.Equal(t, http.StatusNotFound, rr.StatusCode) var trainingError NotFoundError err = json.NewDecoder(rr.Body).Decode(&trainingError) assert.NoError(t, err, "error getting response", err) assert.Equal(t, http.StatusNotFound, trainingError.Status) lrr, _ := doGet(t, app, "/v1/trainings") assert.Equal(t, http.StatusOK, lrr.StatusCode) }) t.Run("Add training date", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 0, 0, 0, 0, time.UTC) startTime := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) newTrainingDate := NewTrainingDate{ Address: "Test Address 123, NYC", Capacity: 12, Date: types.Date{Time: date}, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: startTime.Format("15:04"), Price: Price{ Amount: "200", Currency: "EUR", }, } rr, err := doPost(t, app, fmt.Sprintf("/v1/trainings/%d/dates", tr.ID), newTrainingDate) assert.Equal(t, http.StatusCreated, rr.StatusCode) var resultTrainingDate TrainingDate err = json.NewDecoder(rr.Body).Decode(&resultTrainingDate) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, newTrainingDate.Address, resultTrainingDate.Address) assert.Equal(t, newTrainingDate.Location, resultTrainingDate.Location) assert.Equal(t, newTrainingDate.Capacity, resultTrainingDate.Capacity) assert.Equal(t, newTrainingDate.Days, resultTrainingDate.Days) assert.Equal(t, newTrainingDate.StartTime, resultTrainingDate.StartTime) assert.Equal(t, newTrainingDate.IsOnline, resultTrainingDate.IsOnline) assert.Equal(t, newTrainingDate.Price, resultTrainingDate.Price) assert.Equal(t, newTrainingDate.Date, resultTrainingDate.Date) }) t.Run("Training date not found", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d", tr.ID, 999999)) assert.Equal(t, http.StatusNotFound, rr.StatusCode) var trainingError NotFoundError err := json.NewDecoder(rr.Body).Decode(&trainingError) assert.NoError(t, err, "error getting response", err) assert.Equal(t, http.StatusNotFound, trainingError.Status) }) t.Run("List all training dates", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 0, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } trainingCount := 5 for range trainingCount { _ = handlers.trainingDateRepository.Create(tr.ID, td) } rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates", tr.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) var trainingDates []TrainingDate err := json.NewDecoder(rr.Body).Decode(&trainingDates) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, len(trainingDates), trainingCount) }) t.Run("Update training date", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 0, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) updTd := NewTrainingDate{ Address: "Updated Address 123, NYC", Capacity: 8, Date: types.Date{Time: date}, Days: tr.Days, IsOnline: true, Location: "NYC", StartTime: date.Format("15:04"), Price: Price{ Amount: "200", Currency: "EUR", }, } rr, _ := doPut(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d", tr.ID, td.ID), updTd) assert.Equal(t, http.StatusOK, rr.StatusCode) var tdrr TrainingDate err := json.NewDecoder(rr.Body).Decode(&tdrr) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, updTd.Address, tdrr.Address) assert.Equal(t, updTd.Capacity, tdrr.Capacity) assert.Equal(t, updTd.Date, tdrr.Date) assert.Equal(t, updTd.Days, tdrr.Days) assert.Equal(t, updTd.IsOnline, tdrr.IsOnline) assert.Equal(t, updTd.Location, tdrr.Location) assert.Equal(t, updTd.StartTime, tdrr.StartTime) assert.Equal(t, updTd.Price, tdrr.Price) }) t.Run("Delete training date", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 0, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d", tr.ID, td.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) var tdrr TrainingDate err := json.NewDecoder(rr.Body).Decode(&tdrr) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, td.ID, tdrr.Id) drr, _ := doDelete(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d", tr.ID, td.ID)) assert.Equal(t, http.StatusNoContent, drr.StatusCode) rr, _ = doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d", tr.ID, td.ID)) assert.Equal(t, http.StatusNotFound, rr.StatusCode) var trainingError NotFoundError err = json.NewDecoder(rr.Body).Decode(&trainingError) assert.NoError(t, err, "error getting response", err) assert.Equal(t, http.StatusNotFound, trainingError.Status) lrr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates", tr.ID)) assert.Equal(t, http.StatusOK, lrr.StatusCode) var trainingDates []TrainingDate err = json.NewDecoder(lrr.Body).Decode(&trainingDates) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, len(trainingDates), 0) }) t.Run("List upcoming training dates for training", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) now := time.Now() upcomingTrainingCount := 5 for i := -4; i <= 5; i++ { date := now.AddDate(0, 0, i) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) } rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/upcoming-dates", tr.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) var trainingDatesReturned []TrainingDate err := json.NewDecoder(rr.Body).Decode(&trainingDatesReturned) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, len(trainingDatesReturned), upcomingTrainingCount) }) t.Run("List all upcoming training dates", func(t *testing.T) { tr1 := &training.Training{ Name: "Testing Training for training date 1", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr1) tr2 := &training.Training{ Name: "Testing Training for training date 2", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr2) tr3 := &training.Training{ Name: "Testing Training for training date 3", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr3) allTrainings, _ := handlers.trainingRepository.FindAll() now := time.Now() upcomingTrainingCount := 5 for i := -4; i <= upcomingTrainingCount; i++ { date := now.AddDate(0, 0, i) td1 := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr1.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr1.ID, td1) td2 := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr2.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr2.ID, td2) td3 := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr3.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr3.ID, td3) } rr, _ := doGet(t, app, "/v1/trainings/upcoming-dates") assert.Equal(t, http.StatusOK, rr.StatusCode) var trainingDatesReturned ListAllUpcomingTrainingDatesResponse err := json.NewDecoder(rr.Body).Decode(&trainingDatesReturned) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, len(allTrainings), len(trainingDatesReturned)) for _, tdr := range trainingDatesReturned { if tdr.TrainingID == tr1.ID || tdr.TrainingID == tr2.ID || tdr.TrainingID == tr3.ID { assert.Equal(t, len(tdr.Dates), upcomingTrainingCount) } } }) t.Run("Training date attendee not found", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, 99999999)) assert.Equal(t, http.StatusNotFound, rr.StatusCode) var notFound NotFoundError err := json.NewDecoder(rr.Body).Decode(¬Found) assert.NoError(t, err, "error getting response", err) assert.Equal(t, http.StatusNotFound, notFound.Status) }) t.Run("Add training date attendee", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) newTrainingDateAttendee := NewTrainingDateAttendee{ Name: "John Doe", Email: types.Email("john.doe@example.com"), Company: "Acme Inc.", Position: "Software Engineer", Phone: "+420 123 456 789", IsStudent: new(bool), } rr, _ := doPost(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees", tr.ID, td.ID), newTrainingDateAttendee) assert.Equal(t, http.StatusCreated, rr.StatusCode) var attendeeResponse TrainingDateAttendee err := json.NewDecoder(rr.Body).Decode(&attendeeResponse) assert.NoError(t, err, "error getting response", err) assert.Equal(t, newTrainingDateAttendee.Name, attendeeResponse.Name) assert.Equal(t, newTrainingDateAttendee.Email, attendeeResponse.Email) assert.Equal(t, newTrainingDateAttendee.Company, attendeeResponse.Company) assert.Equal(t, newTrainingDateAttendee.Position, attendeeResponse.Position) assert.Equal(t, newTrainingDateAttendee.Phone, attendeeResponse.Phone) assert.Equal(t, newTrainingDateAttendee.IsStudent, attendeeResponse.IsStudent) assert.Equal(t, td.PriceAmount.String(), attendeeResponse.Bill.Amount) assert.Equal(t, td.PriceCurrency, attendeeResponse.Bill.Currency) assert.Equal(t, false, attendeeResponse.HasPaid) assert.Equal(t, false, attendeeResponse.HasAttended) }) t.Run("List all training date attendees", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) attendeeCount := 9 attendees := make([]training.Attendee, attendeeCount) for i := range attendeeCount { nAtd := &training.Attendee{ Name: "John Doe", Email: "john.doe@example.com", Company: "Acme Inc.", Position: "Software Engineer", Phone: "+420 123 456 789", IsStudent: false, BillAmount: td.PriceAmount, BillCurrency: td.PriceCurrency, HasPaid: false, HasAttended: false, } _ = handlers.trainingDateAttendeeRepository.Create(td.ID, nAtd) attendees[i] = *nAtd } rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees", tr.ID, td.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) var attendeesResponse ListTrainingDateAttendeesResponse err := json.NewDecoder(rr.Body).Decode(&attendeesResponse) assert.NoError(t, err, "error getting response", err) assert.Equal(t, attendeeCount, len(attendeesResponse)) for i, attendee := range attendeesResponse { assert.Equal(t, attendees[i].Name, attendee.Name) assert.Equal(t, attendees[i].Email, string(attendee.Email)) assert.Equal(t, attendees[i].Company, attendee.Company) assert.Equal(t, attendees[i].Position, attendee.Position) assert.Equal(t, attendees[i].IsStudent, *attendee.IsStudent) assert.Equal(t, attendees[i].Phone, attendee.Phone) assert.Equal(t, attendees[i].BillAmount.String(), attendee.Bill.Amount) assert.Equal(t, attendees[i].BillCurrency, attendee.Bill.Currency) assert.Equal(t, attendees[i].HasPaid, attendee.HasPaid) assert.Equal(t, attendees[i].HasAttended, attendee.HasAttended) } }) t.Run("Get training date attendee", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) attendee := &training.Attendee{ Name: "John Doe", Email: "john.doe@example.com", Company: "Acme Inc.", Position: "Software Engineer", Phone: "+420 123 456 789", IsStudent: false, BillAmount: td.PriceAmount, BillCurrency: td.PriceCurrency, HasPaid: false, HasAttended: false, } _ = handlers.trainingDateAttendeeRepository.Create(td.ID, attendee) rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID)) var resultTrainingDateAttendee TrainingDateAttendee err := json.NewDecoder(rr.Body).Decode(&resultTrainingDateAttendee) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, attendee.Name, resultTrainingDateAttendee.Name) assert.Equal(t, attendee.Email, string(resultTrainingDateAttendee.Email)) assert.Equal(t, attendee.Company, resultTrainingDateAttendee.Company) assert.Equal(t, attendee.Position, resultTrainingDateAttendee.Position) assert.Equal(t, attendee.IsStudent, *resultTrainingDateAttendee.IsStudent) assert.Equal(t, attendee.Phone, resultTrainingDateAttendee.Phone) assert.Equal(t, attendee.BillAmount.String(), resultTrainingDateAttendee.Bill.Amount) assert.Equal(t, attendee.BillCurrency, resultTrainingDateAttendee.Bill.Currency) assert.Equal(t, attendee.HasPaid, resultTrainingDateAttendee.HasPaid) assert.Equal(t, attendee.HasAttended, resultTrainingDateAttendee.HasAttended) }) t.Run("Update training date attendee", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) attendee := &training.Attendee{ Name: "John Doe", Email: "john.doe@example.com", Company: "Acme Inc.", Position: "Software Engineer", Phone: "+420 123 456 789", IsStudent: false, BillAmount: td.PriceAmount, BillCurrency: td.PriceCurrency, HasPaid: false, HasAttended: false, } _ = handlers.trainingDateAttendeeRepository.Create(td.ID, attendee) newTrainingDateAttendee := NewTrainingDateAttendee{ Name: "John Doe", Email: types.Email("jdoe@example.com"), Company: "Acme Corp Inc.", Position: "Senior Software Engineer", Phone: "+420 987 654 321", IsStudent: new(bool), } rr, _ := doPut(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID), newTrainingDateAttendee) assert.Equal(t, http.StatusOK, rr.StatusCode) var attendeeResponse UpdateTrainingDateAttendeeResponse err := json.NewDecoder(rr.Body).Decode(&attendeeResponse) assert.NoError(t, err, "error getting response", err) assert.Equal(t, newTrainingDateAttendee.Name, attendeeResponse.Name) assert.Equal(t, newTrainingDateAttendee.Email, attendeeResponse.Email) assert.Equal(t, newTrainingDateAttendee.Company, attendeeResponse.Company) assert.Equal(t, newTrainingDateAttendee.Position, attendeeResponse.Position) assert.Equal(t, newTrainingDateAttendee.Phone, attendeeResponse.Phone) assert.Equal(t, newTrainingDateAttendee.IsStudent, attendeeResponse.IsStudent) assert.Equal(t, td.PriceAmount.String(), attendeeResponse.Bill.Amount) assert.Equal(t, td.PriceCurrency, attendeeResponse.Bill.Currency) assert.Equal(t, attendee.HasPaid, attendeeResponse.HasPaid) assert.Equal(t, attendee.HasAttended, attendeeResponse.HasAttended) }) t.Run("Delete training date attendee", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) attendee := &training.Attendee{ Name: "John Doe", Email: "john.doe@example.com", Company: "Acme Inc.", Position: "Software Engineer", Phone: "+420 123 456 789", IsStudent: false, BillAmount: td.PriceAmount, BillCurrency: td.PriceCurrency, HasPaid: false, HasAttended: false, } _ = handlers.trainingDateAttendeeRepository.Create(td.ID, attendee) rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) rr, _ = doDelete(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID)) assert.Equal(t, http.StatusNoContent, rr.StatusCode) rr, _ = doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID)) assert.Equal(t, http.StatusNotFound, rr.StatusCode) }) t.Run("Mark training date attendee as paid", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) paid := TrainingDateAttendeePaymentUpdateRequest{ Paid: true, } attendee := &training.Attendee{ Name: "John Doe", Email: "john.doe@example.com", Company: "Acme Inc.", Position: "Software Engineer", Phone: "+420 123 456 789", IsStudent: false, BillAmount: td.PriceAmount, BillCurrency: td.PriceCurrency, HasPaid: !paid.Paid, HasAttended: false, } _ = handlers.trainingDateAttendeeRepository.Create(td.ID, attendee) rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) var attendeeResponse TrainingDateAttendee err := json.NewDecoder(rr.Body).Decode(&attendeeResponse) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, !paid.Paid, attendeeResponse.HasPaid) rr, _ = doPut(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d/paid", tr.ID, td.ID, attendee.ID), paid) assert.Equal(t, http.StatusOK, rr.StatusCode) err = json.NewDecoder(rr.Body).Decode(&attendeeResponse) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, paid.Paid, attendeeResponse.HasPaid) rr, _ = doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) err = json.NewDecoder(rr.Body).Decode(&attendeeResponse) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, paid.Paid, attendeeResponse.HasPaid) }) t.Run("Mark training date attendee as attended", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) attended := TrainingDateAttendeeAttendanceUpdateRequest{ Attended: true, } attendee := &training.Attendee{ Name: "John Doe", Email: "john.doe@example.com", Company: "Acme Inc.", Position: "Software Engineer", Phone: "+420 123 456 789", IsStudent: false, BillAmount: td.PriceAmount, BillCurrency: td.PriceCurrency, HasPaid: false, HasAttended: !attended.Attended, } _ = handlers.trainingDateAttendeeRepository.Create(td.ID, attendee) rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) var attendeeResponse TrainingDateAttendee err := json.NewDecoder(rr.Body).Decode(&attendeeResponse) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, !attended.Attended, attendeeResponse.HasAttended) rr, _ = doPut(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d/attended", tr.ID, td.ID, attendee.ID), attended) assert.Equal(t, http.StatusOK, rr.StatusCode) err = json.NewDecoder(rr.Body).Decode(&attendeeResponse) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, attended.Attended, attendeeResponse.HasAttended) rr, _ = doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/%d", tr.ID, td.ID, attendee.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) err = json.NewDecoder(rr.Body).Decode(&attendeeResponse) assert.NoError(t, err, "error unmarshalling response") assert.Equal(t, attended.Attended, attendeeResponse.HasAttended) }) t.Run("Get count of training date attendees", func(t *testing.T) { tr := &training.Training{ Name: "Testing Training for training date", Description: "This is a test training for training date", Days: 1, Pricing: []training.Price{ { Amount: decimal.NewFromInt(200), Currency: "EUR", Type: training.OpenTrainingPrice, }, }, } _ = handlers.trainingRepository.Create(tr) date := time.Date(2024, time.May, 1, 9, 0, 0, 0, time.UTC) td := &training.Date{ Address: "Test Address 123, NYC", Capacity: 12, Date: date, Days: tr.Days, IsOnline: false, Location: "NYC", StartTime: date, PriceAmount: decimal.NewFromInt(200), PriceCurrency: "EUR", } _ = handlers.trainingDateRepository.Create(tr.ID, td) attendeeCount := 9 for range attendeeCount { nAtd := &training.Attendee{ Name: "John Doe", Email: "john.doe@example.com", Company: "Acme Inc.", Position: "Software Engineer", Phone: "+420 123 456 789", IsStudent: false, BillAmount: td.PriceAmount, BillCurrency: td.PriceCurrency, HasPaid: false, HasAttended: false, } _ = handlers.trainingDateAttendeeRepository.Create(td.ID, nAtd) } rr, _ := doGet(t, app, fmt.Sprintf("/v1/trainings/%d/dates/%d/attendees/count", tr.ID, td.ID)) assert.Equal(t, http.StatusOK, rr.StatusCode) var attendeesResponse GetTrainingDateAttendeeCountResponse err := json.NewDecoder(rr.Body).Decode(&attendeesResponse) assert.NoError(t, err, "error getting response", err) assert.Equal(t, int8(attendeeCount), attendeesResponse.Count) }) }