Stage 3.4

This commit is contained in:
2026-04-20 16:40:44 +03:00
parent 42a047a938
commit b24cbc97f3
25 changed files with 2520 additions and 123 deletions

View File

@@ -0,0 +1,148 @@
-module(booking_integration_tests).
-include_lib("eunit/include/eunit.hrl").
-include("records.hrl").
setup() ->
mnesia:start(),
mnesia:create_table(user, [
{attributes, record_info(fields, user)},
{ram_copies, [node()]}
]),
mnesia:create_table(calendar, [
{attributes, record_info(fields, calendar)},
{ram_copies, [node()]}
]),
mnesia:create_table(event, [
{attributes, record_info(fields, event)},
{ram_copies, [node()]}
]),
mnesia:create_table(booking, [
{attributes, record_info(fields, booking)},
{ram_copies, [node()]}
]),
ok.
cleanup(_) ->
mnesia:delete_table(booking),
mnesia:delete_table(event),
mnesia:delete_table(calendar),
mnesia:delete_table(user),
mnesia:stop(),
ok.
booking_integration_test_() ->
{foreach,
fun setup/0,
fun cleanup/1,
[
{"Full booking flow with auto confirmation", fun test_auto_booking_flow/0},
{"Full booking flow with manual confirmation", fun test_manual_booking_flow/0},
{"Capacity management test", fun test_capacity_management/0},
{"Multiple bookings test", fun test_multiple_bookings/0}
]}.
create_user() ->
UserId = base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}),
User = #user{
id = UserId,
email = <<UserId/binary, "@test.com">>,
password_hash = <<"hash">>,
role = user,
status = active,
created_at = calendar:universal_time(),
updated_at = calendar:universal_time()
},
mnesia:dirty_write(User),
UserId.
test_auto_booking_flow() ->
OwnerId = create_user(),
ParticipantId = create_user(),
{ok, Calendar} = core_calendar:create(OwnerId, <<"Auto">>, <<"">>, auto),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
{ok, Event} = core_event:create(Calendar#calendar.id, <<"Event">>, StartTime, 60),
{ok, Booking} = logic_booking:create_booking(ParticipantId, Event#event.id),
timer:sleep(100),
{ok, Updated} = core_booking:get_by_id(Booking#booking.id),
?assertEqual(confirmed, Updated#booking.status),
{ok, EventBookings} = logic_booking:list_event_bookings(OwnerId, Event#event.id),
?assertEqual(1, length(EventBookings)),
{ok, UserBookings} = logic_booking:list_user_bookings(ParticipantId),
?assertEqual(1, length(UserBookings)).
test_manual_booking_flow() ->
OwnerId = create_user(),
ParticipantId = create_user(),
{ok, Calendar} = core_calendar:create(OwnerId, <<"Manual">>, <<"">>, manual),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
{ok, Event} = core_event:create(Calendar#calendar.id, <<"Event">>, StartTime, 60),
{ok, Booking} = logic_booking:create_booking(ParticipantId, Event#event.id),
?assertEqual(pending, Booking#booking.status),
{ok, Confirmed} = logic_booking:confirm_booking(OwnerId, Booking#booking.id, confirm),
?assertEqual(confirmed, Confirmed#booking.status),
{ok, Cancelled} = logic_booking:cancel_booking(ParticipantId, Booking#booking.id),
?assertEqual(cancelled, Cancelled#booking.status).
test_capacity_management() ->
OwnerId = create_user(),
Participant1Id = create_user(),
Participant2Id = create_user(),
Participant3Id = create_user(),
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test">>, <<"">>, auto),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
{ok, Event} = core_event:create(Calendar#calendar.id, <<"Event">>, StartTime, 60),
{ok, _} = core_event:update(Event#event.id, [{capacity, 2}]),
{ok, Booking1} = logic_booking:create_booking(Participant1Id, Event#event.id),
{ok, _Booking2} = logic_booking:create_booking(Participant2Id, Event#event.id),
{error, event_full} = logic_booking:create_booking(Participant3Id, Event#event.id),
% Участник 1 отменяет своё бронирование
{ok, _} = logic_booking:cancel_booking(Participant1Id, Booking1#booking.id),
% Теперь третий может записаться
{ok, _} = logic_booking:create_booking(Participant3Id, Event#event.id).
test_multiple_bookings() ->
OwnerId = create_user(),
ParticipantId = create_user(),
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test">>, <<"">>, manual),
StartTime1 = {{2026, 6, 1}, {10, 0, 0}},
StartTime2 = {{2026, 6, 2}, {10, 0, 0}},
StartTime3 = {{2026, 6, 3}, {10, 0, 0}},
{ok, Event1} = core_event:create(Calendar#calendar.id, <<"Event1">>, StartTime1, 60),
{ok, Event2} = core_event:create(Calendar#calendar.id, <<"Event2">>, StartTime2, 60),
{ok, Event3} = core_event:create(Calendar#calendar.id, <<"Event3">>, StartTime3, 60),
{ok, B1} = logic_booking:create_booking(ParticipantId, Event1#event.id),
{ok, B2} = logic_booking:create_booking(ParticipantId, Event2#event.id),
{ok, _B3} = logic_booking:create_booking(ParticipantId, Event3#event.id),
{ok, _} = logic_booking:confirm_booking(OwnerId, B1#booking.id, confirm),
{ok, _} = logic_booking:confirm_booking(OwnerId, B2#booking.id, confirm),
{ok, UserBookings} = logic_booking:list_user_bookings(ParticipantId),
?assertEqual(3, length(UserBookings)),
ConfirmedCount = length([B || B <- UserBookings, B#booking.status =:= confirmed]),
?assertEqual(2, ConfirmedCount),
PendingCount = length([B || B <- UserBookings, B#booking.status =:= pending]),
?assertEqual(1, PendingCount).

126
test/core_booking_tests.erl Normal file
View File

@@ -0,0 +1,126 @@
-module(core_booking_tests).
-include_lib("eunit/include/eunit.hrl").
-include("records.hrl").
setup() ->
mnesia:start(),
mnesia:create_table(booking, [
{attributes, record_info(fields, booking)},
{ram_copies, [node()]}
]),
ok.
cleanup(_) ->
mnesia:delete_table(booking),
mnesia:stop(),
ok.
core_booking_test_() ->
{foreach,
fun setup/0,
fun cleanup/1,
[
{"Create booking test", fun test_create_booking/0},
{"Get booking by id test", fun test_get_by_id/0},
{"Get booking by event and user test", fun test_get_by_event_and_user/0},
{"List bookings by event test", fun test_list_by_event/0},
{"List bookings by user test", fun test_list_by_user/0},
{"Update booking status test", fun test_update_status/0},
{"Delete booking test", fun test_delete_booking/0}
]}.
test_create_booking() ->
EventId = <<"event123">>,
UserId = <<"user123">>,
{ok, Booking} = core_booking:create(EventId, UserId),
?assertEqual(EventId, Booking#booking.event_id),
?assertEqual(UserId, Booking#booking.user_id),
?assertEqual(pending, Booking#booking.status),
?assertEqual(undefined, Booking#booking.confirmed_at),
?assert(is_binary(Booking#booking.id)),
?assert(Booking#booking.created_at =/= undefined),
?assert(Booking#booking.updated_at =/= undefined).
test_get_by_id() ->
EventId = <<"event123">>,
UserId = <<"user123">>,
{ok, Booking} = core_booking:create(EventId, UserId),
{ok, Found} = core_booking:get_by_id(Booking#booking.id),
?assertEqual(Booking#booking.id, Found#booking.id),
{error, not_found} = core_booking:get_by_id(<<"nonexistent">>).
test_get_by_event_and_user() ->
EventId = <<"event123">>,
UserId1 = <<"user1">>,
UserId2 = <<"user2">>,
{ok, Booking1} = core_booking:create(EventId, UserId1),
{ok, _Booking2} = core_booking:create(EventId, UserId2),
{ok, Found} = core_booking:get_by_event_and_user(EventId, UserId1),
?assertEqual(Booking1#booking.id, Found#booking.id),
{error, not_found} = core_booking:get_by_event_and_user(EventId, <<"user3">>).
test_list_by_event() ->
EventId1 = <<"event1">>,
EventId2 = <<"event2">>,
UserId = <<"user123">>,
{ok, _} = core_booking:create(EventId1, UserId),
{ok, _} = core_booking:create(EventId1, <<"user2">>),
{ok, _} = core_booking:create(EventId2, UserId),
{ok, Bookings1} = core_booking:list_by_event(EventId1),
?assertEqual(2, length(Bookings1)),
{ok, Bookings2} = core_booking:list_by_event(EventId2),
?assertEqual(1, length(Bookings2)).
test_list_by_user() ->
EventId = <<"event123">>,
UserId1 = <<"user1">>,
UserId2 = <<"user2">>,
{ok, _} = core_booking:create(EventId, UserId1),
{ok, _} = core_booking:create(EventId, UserId1),
{ok, _} = core_booking:create(EventId, UserId2),
{ok, Bookings1} = core_booking:list_by_user(UserId1),
?assertEqual(2, length(Bookings1)),
{ok, Bookings2} = core_booking:list_by_user(UserId2),
?assertEqual(1, length(Bookings2)).
test_update_status() ->
EventId = <<"event123">>,
UserId = <<"user123">>,
{ok, Booking} = core_booking:create(EventId, UserId),
timer:sleep(2000), % 2 секунды
{ok, Confirmed} = core_booking:update_status(Booking#booking.id, confirmed),
?assertEqual(confirmed, Confirmed#booking.status),
?assert(Confirmed#booking.confirmed_at =/= undefined),
?assert(Confirmed#booking.updated_at > Booking#booking.updated_at),
timer:sleep(2000), % 2 секунды
{ok, Cancelled} = core_booking:update_status(Booking#booking.id, cancelled),
?assertEqual(cancelled, Cancelled#booking.status),
?assert(Cancelled#booking.updated_at > Confirmed#booking.updated_at),
{error, not_found} = core_booking:update_status(<<"nonexistent">>, confirmed).
test_delete_booking() ->
EventId = <<"event123">>,
UserId = <<"user123">>,
{ok, Booking} = core_booking:create(EventId, UserId),
{ok, deleted} = core_booking:delete(Booking#booking.id),
{error, not_found} = core_booking:get_by_id(Booking#booking.id).

View File

@@ -2,7 +2,6 @@
-include_lib("eunit/include/eunit.hrl").
-include("records.hrl").
%% Setup и cleanup
setup() ->
mnesia:start(),
mnesia:create_table(calendar, [
@@ -16,7 +15,6 @@ cleanup(_) ->
mnesia:stop(),
ok.
%% Группа тестов
core_calendar_test_() ->
{foreach,
fun setup/0,
@@ -29,18 +27,19 @@ core_calendar_test_() ->
{"Delete calendar test", fun test_delete_calendar/0}
]}.
%% Тесты
test_create_calendar() ->
OwnerId = <<"owner123">>,
Title = <<"Test Calendar">>,
Description = <<"Test Description">>,
Confirmation = auto,
{ok, Calendar} = core_calendar:create(OwnerId, Title, Description),
{ok, Calendar} = core_calendar:create(OwnerId, Title, Description, Confirmation),
?assertEqual(OwnerId, Calendar#calendar.owner_id),
?assertEqual(Title, Calendar#calendar.title),
?assertEqual(Description, Calendar#calendar.description),
?assertEqual(personal, Calendar#calendar.type),
?assertEqual(Confirmation, Calendar#calendar.confirmation),
?assertEqual(active, Calendar#calendar.status),
?assert(is_binary(Calendar#calendar.id)),
?assert(Calendar#calendar.created_at =/= undefined),
@@ -48,7 +47,7 @@ test_create_calendar() ->
test_get_by_id() ->
OwnerId = <<"owner123">>,
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test">>, <<"Desc">>),
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test">>, <<"Desc">>, manual),
{ok, Found} = core_calendar:get_by_id(Calendar#calendar.id),
?assertEqual(Calendar#calendar.id, Found#calendar.id),
@@ -59,33 +58,33 @@ test_list_by_owner() ->
OwnerId = <<"owner123">>,
OtherOwner = <<"other456">>,
{ok, _} = core_calendar:create(OwnerId, <<"Calendar 1">>, <<"">>),
{ok, _} = core_calendar:create(OwnerId, <<"Calendar 2">>, <<"">>),
{ok, _} = core_calendar:create(OtherOwner, <<"Other Calendar">>, <<"">>),
{ok, _} = core_calendar:create(OwnerId, <<"Calendar 1">>, <<"">>, manual),
{ok, _} = core_calendar:create(OwnerId, <<"Calendar 2">>, <<"">>, auto),
{ok, _} = core_calendar:create(OtherOwner, <<"Other Calendar">>, <<"">>, manual),
{ok, Calendars} = core_calendar:list_by_owner(OwnerId),
?assertEqual(2, length(Calendars)).
test_update_calendar() ->
OwnerId = <<"owner123">>,
{ok, Calendar} = core_calendar:create(OwnerId, <<"Original">>, <<"">>),
{ok, Calendar} = core_calendar:create(OwnerId, <<"Original">>, <<"">>, manual),
timer:sleep(2000),
Updates = [{title, <<"Updated">>}, {description, <<"New Desc">>}],
Updates = [{title, <<"Updated">>}, {description, <<"New Desc">>}, {confirmation, auto}],
{ok, Updated} = core_calendar:update(Calendar#calendar.id, Updates),
?assertEqual(<<"Updated">>, Updated#calendar.title),
?assertEqual(<<"New Desc">>, Updated#calendar.description),
?assertEqual(auto, Updated#calendar.confirmation),
?assert(Updated#calendar.updated_at > Calendar#calendar.updated_at),
{error, not_found} = core_calendar:update(<<"nonexistent">>, Updates).
test_delete_calendar() ->
OwnerId = <<"owner123">>,
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test">>, <<"">>),
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test">>, <<"">>, manual),
{ok, Deleted} = core_calendar:delete(Calendar#calendar.id),
?assertEqual(deleted, Deleted#calendar.status),
% Удалённый календарь не возвращается в списке активных
{ok, ActiveCalendars} = core_calendar:list_by_owner(OwnerId),
?assertEqual(0, length(ActiveCalendars)).

View File

@@ -0,0 +1,212 @@
-module(logic_booking_tests).
-include_lib("eunit/include/eunit.hrl").
-include("records.hrl").
-define(TEST_EMAIL, <<"test@example.com">>).
setup() ->
mnesia:start(),
mnesia:create_table(user, [
{attributes, record_info(fields, user)},
{ram_copies, [node()]}
]),
mnesia:create_table(calendar, [
{attributes, record_info(fields, calendar)},
{ram_copies, [node()]}
]),
mnesia:create_table(event, [
{attributes, record_info(fields, event)},
{ram_copies, [node()]}
]),
mnesia:create_table(booking, [
{attributes, record_info(fields, booking)},
{ram_copies, [node()]}
]),
ok.
cleanup(_) ->
mnesia:delete_table(booking),
mnesia:delete_table(event),
mnesia:delete_table(calendar),
mnesia:delete_table(user),
mnesia:stop(),
ok.
logic_booking_test_() ->
{foreach,
fun setup/0,
fun cleanup/1,
[
{"Create booking with auto confirmation", fun test_create_booking_auto/0},
{"Create booking with manual confirmation", fun test_create_booking_manual/0},
{"Create booking with timeout confirmation", fun test_create_booking_timeout/0},
{"Create duplicate booking", fun test_create_duplicate_booking/0},
{"Create booking for inactive event", fun test_booking_inactive_event/0},
{"Create booking when event is full", fun test_booking_event_full/0},
{"Confirm booking by owner", fun test_confirm_booking/0},
{"Decline booking by owner", fun test_decline_booking/0},
{"Cancel booking by participant", fun test_cancel_booking/0},
{"Unauthorized confirm attempt", fun test_unauthorized_confirm/0},
{"List event bookings", fun test_list_event_bookings/0},
{"List user bookings", fun test_list_user_bookings/0}
]}.
%% Вспомогательные функции
create_test_user(Role) ->
UserId = base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}),
User = #user{
id = UserId,
email = <<UserId/binary, "@test.com">>,
password_hash = <<"hash">>,
role = Role,
status = active,
created_at = calendar:universal_time(),
updated_at = calendar:universal_time()
},
mnesia:dirty_write(User),
UserId.
create_test_calendar(OwnerId, Confirmation) ->
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test Calendar">>, <<"">>, Confirmation),
Calendar#calendar.id.
create_test_event(CalendarId) ->
StartTime = {{2026, 6, 1}, {10, 0, 0}},
{ok, Event} = core_event:create(CalendarId, <<"Test Event">>, StartTime, 60),
Event#event.id.
create_test_event_with_capacity(CalendarId, Capacity) ->
StartTime = {{2026, 6, 1}, {10, 0, 0}},
{ok, Event} = core_event:create(CalendarId, <<"Test Event">>, StartTime, 60),
{ok, Updated} = core_event:update(Event#event.id, [{capacity, Capacity}]),
Updated#event.id.
%% Тесты
test_create_booking_auto() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, auto),
EventId = create_test_event(CalendarId),
{ok, Booking} = logic_booking:create_booking(ParticipantId, EventId),
timer:sleep(100),
{ok, Updated} = core_booking:get_by_id(Booking#booking.id),
?assertEqual(confirmed, Updated#booking.status).
test_create_booking_manual() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId = create_test_event(CalendarId),
{ok, Booking} = logic_booking:create_booking(ParticipantId, EventId),
?assertEqual(pending, Booking#booking.status).
test_create_booking_timeout() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, {timeout, 1}),
EventId = create_test_event(CalendarId),
{ok, Booking} = logic_booking:create_booking(ParticipantId, EventId),
?assertEqual(pending, Booking#booking.status),
timer:sleep(1500),
{ok, Updated} = core_booking:get_by_id(Booking#booking.id),
?assertEqual(confirmed, Updated#booking.status).
test_create_duplicate_booking() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId = create_test_event(CalendarId),
{ok, _} = logic_booking:create_booking(ParticipantId, EventId),
{error, already_booked} = logic_booking:create_booking(ParticipantId, EventId).
test_booking_inactive_event() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId = create_test_event(CalendarId),
{ok, _} = core_event:update(EventId, [{status, cancelled}]),
{error, event_not_active} = logic_booking:create_booking(ParticipantId, EventId).
test_booking_event_full() ->
OwnerId = create_test_user(user),
Participant1Id = create_test_user(user),
Participant2Id = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, auto),
EventId = create_test_event_with_capacity(CalendarId, 1),
{ok, _} = logic_booking:create_booking(Participant1Id, EventId),
{error, event_full} = logic_booking:create_booking(Participant2Id, EventId).
test_confirm_booking() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId = create_test_event(CalendarId),
{ok, Booking} = logic_booking:create_booking(ParticipantId, EventId),
{ok, Confirmed} = logic_booking:confirm_booking(OwnerId, Booking#booking.id, confirm),
?assertEqual(confirmed, Confirmed#booking.status).
test_decline_booking() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId = create_test_event(CalendarId),
{ok, Booking} = logic_booking:create_booking(ParticipantId, EventId),
{ok, Declined} = logic_booking:confirm_booking(OwnerId, Booking#booking.id, decline),
?assertEqual(cancelled, Declined#booking.status).
test_cancel_booking() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId = create_test_event(CalendarId),
{ok, Booking} = logic_booking:create_booking(ParticipantId, EventId),
{ok, Cancelled} = logic_booking:cancel_booking(ParticipantId, Booking#booking.id),
?assertEqual(cancelled, Cancelled#booking.status).
test_unauthorized_confirm() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
OtherId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId = create_test_event(CalendarId),
{ok, Booking} = logic_booking:create_booking(ParticipantId, EventId),
{error, access_denied} = logic_booking:confirm_booking(OtherId, Booking#booking.id, confirm).
test_list_event_bookings() ->
OwnerId = create_test_user(user),
Participant1Id = create_test_user(user),
Participant2Id = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId = create_test_event(CalendarId),
{ok, _} = logic_booking:create_booking(Participant1Id, EventId),
{ok, _} = logic_booking:create_booking(Participant2Id, EventId),
{ok, Bookings} = logic_booking:list_event_bookings(OwnerId, EventId),
?assertEqual(2, length(Bookings)).
test_list_user_bookings() ->
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, manual),
EventId1 = create_test_event(CalendarId),
EventId2 = create_test_event(CalendarId),
{ok, _} = logic_booking:create_booking(ParticipantId, EventId1),
{ok, _} = logic_booking:create_booking(ParticipantId, EventId2),
{ok, Bookings} = logic_booking:list_user_bookings(ParticipantId),
?assertEqual(2, length(Bookings)).

View File

@@ -51,17 +51,18 @@ test_create_calendar() ->
UserId = create_test_user(),
Title = <<"Test Calendar">>,
Description = <<"Test Description">>,
Confirmation = auto,
{ok, Calendar} = logic_calendar:create_calendar(UserId, Title, Description),
{ok, Calendar} = logic_calendar:create_calendar(UserId, Title, Description, Confirmation),
?assertEqual(UserId, Calendar#calendar.owner_id),
?assertEqual(Title, Calendar#calendar.title),
?assertEqual(personal, Calendar#calendar.type).
?assertEqual(personal, Calendar#calendar.type),
?assertEqual(Confirmation, Calendar#calendar.confirmation).
test_get_calendar() ->
UserId = create_test_user(),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Test">>, <<"">>),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Test">>, <<"">>, manual),
% Владелец имеет доступ
case logic_calendar:get_calendar(UserId, Calendar#calendar.id) of
{ok, Found} ->
?assertEqual(Calendar#calendar.id, Found#calendar.id);
@@ -69,77 +70,55 @@ test_get_calendar() ->
?assert(false, {unexpected_result, Other})
end,
% Другой пользователь не имеет доступа к personal календарю
OtherUserId = create_test_user(),
?assertMatch({error, access_denied},
logic_calendar:get_calendar(OtherUserId, Calendar#calendar.id)),
% Делаем календарь коммерческим
{ok, Commercial} = logic_calendar:update_calendar(UserId, Calendar#calendar.id, [{type, commercial}]),
% Теперь другой пользователь имеет доступ
{ok, _} = logic_calendar:get_calendar(OtherUserId, Commercial#calendar.id).
logic_calendar:get_calendar(OtherUserId, Calendar#calendar.id)).
test_list_calendars() ->
UserId = create_test_user(),
{ok, _} = logic_calendar:create_calendar(UserId, <<"Calendar 1">>, <<"">>),
{ok, _} = logic_calendar:create_calendar(UserId, <<"Calendar 2">>, <<"">>),
{ok, _} = logic_calendar:create_calendar(UserId, <<"Calendar 1">>, <<"">>, manual),
{ok, _} = logic_calendar:create_calendar(UserId, <<"Calendar 2">>, <<"">>, auto),
{ok, Calendars} = logic_calendar:list_calendars(UserId),
?assertEqual(2, length(Calendars)).
test_update_calendar() ->
UserId = create_test_user(),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Original">>, <<"">>),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Original">>, <<"">>, manual),
Updates = [{title, <<"Updated">>}, {type, commercial}],
Updates = [{title, <<"Updated">>}, {type, commercial}, {confirmation, auto}],
{ok, Updated} = logic_calendar:update_calendar(UserId, Calendar#calendar.id, Updates),
?assertEqual(<<"Updated">>, Updated#calendar.title),
?assertEqual(commercial, Updated#calendar.type),
?assertEqual(auto, Updated#calendar.confirmation),
% Другой пользователь не может обновить
OtherUserId = create_test_user(),
?assertMatch({error, access_denied},
logic_calendar:update_calendar(OtherUserId, Calendar#calendar.id, Updates)).
test_delete_calendar() ->
UserId = create_test_user(),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Test">>, <<"">>),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Test">>, <<"">>, manual),
{ok, Deleted} = logic_calendar:delete_calendar(UserId, Calendar#calendar.id),
?assertEqual(deleted, Deleted#calendar.status),
% После удаления доступ запрещён
?assertMatch({error, access_denied}, logic_calendar:get_calendar(UserId, Calendar#calendar.id)).
test_access_control() ->
OwnerId = create_test_user(),
OtherId = create_test_user(),
% Создаём personal календарь
{ok, PersonalCalendar} = logic_calendar:create_calendar(OwnerId, <<"Personal">>, <<"">>),
{ok, PersonalCalendar} = logic_calendar:create_calendar(OwnerId, <<"Personal">>, <<"">>, manual),
% Владелец может редактировать
?assert(logic_calendar:can_edit(OwnerId, PersonalCalendar)),
% Другой пользователь не может редактировать
?assertNot(logic_calendar:can_edit(OtherId, PersonalCalendar)),
% Другой пользователь не может просматривать personal календарь
?assertNot(logic_calendar:can_access(OtherId, PersonalCalendar)),
% Делаем календарь коммерческим
{ok, CommercialCalendar} = logic_calendar:update_calendar(OwnerId, PersonalCalendar#calendar.id, [{type, commercial}]),
% Теперь другой пользователь может просматривать
?assert(logic_calendar:can_access(OtherId, CommercialCalendar)),
% Но всё ещё не может редактировать
?assertNot(logic_calendar:can_edit(OtherId, CommercialCalendar)),
% Замораживаем календарь
{ok, Frozen} = core_calendar:update(CommercialCalendar#calendar.id, [{status, frozen}]),
% После заморозки доступ запрещён всем (кроме владельца для редактирования?)
?assertNot(logic_calendar:can_access(OtherId, Frozen)),
?assertNot(logic_calendar:can_access(OwnerId, Frozen)).

View File

@@ -56,13 +56,13 @@ create_test_user_and_calendar() ->
},
mnesia:dirty_write(User),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Test Calendar">>, <<"">>),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Test Calendar">>, <<"">>, manual),
{UserId, Calendar#calendar.id}.
test_create_recurring_event() ->
{UserId, CalendarId} = create_test_user_and_calendar(),
Title = <<"Weekly Meeting">>,
StartTime = {{2026, 5, 1}, {10, 0, 0}},
StartTime = {{2026, 6, 1}, {10, 0, 0}},
Duration = 60,
RRule = #{<<"freq">> => <<"WEEKLY">>, <<"interval">> => 1},
@@ -75,7 +75,7 @@ test_create_recurring_event() ->
test_create_recurring_invalid() ->
{UserId, CalendarId} = create_test_user_and_calendar(),
Title = <<"Invalid">>,
StartTime = {{2026, 5, 1}, {10, 0, 0}},
StartTime = {{2026, 6, 1}, {10, 0, 0}},
Duration = 60,
InvalidRRule = #{<<"freq">> => <<"YEARLY">>, <<"interval">> => 1},
@@ -85,17 +85,16 @@ test_create_recurring_invalid() ->
test_get_occurrences() ->
{UserId, CalendarId} = create_test_user_and_calendar(),
StartTime = {{2026, 6, 1}, {10, 0, 0}}, % Июнь 2026
StartTime = {{2026, 6, 1}, {10, 0, 0}},
RRule = #{<<"freq">> => <<"WEEKLY">>, <<"interval">> => 1},
{ok, Event} = logic_event:create_recurring_event(
UserId, CalendarId, <<"Weekly">>, StartTime, 60, RRule
),
RangeEnd = {{2026, 6, 29}, {10, 0, 0}}, % Конец июня
RangeEnd = {{2026, 6, 29}, {10, 0, 0}},
{ok, Occurrences} = logic_event:get_occurrences(UserId, Event#event.id, RangeEnd),
% 1, 8, 15, 22, 29 июня = 5 вхождений
?assertEqual(5, length(Occurrences)).
test_cancel_occurrence() ->
@@ -107,7 +106,7 @@ test_cancel_occurrence() ->
UserId, CalendarId, <<"Weekly">>, StartTime, 60, RRule
),
CancelTime = {{2026, 6, 8}, {10, 0, 0}}, % Второе вхождение
CancelTime = {{2026, 6, 8}, {10, 0, 0}},
{ok, cancelled} = logic_event:cancel_occurrence(UserId, Event#event.id, CancelTime).
test_occurrences_with_cancelled() ->
@@ -119,17 +118,14 @@ test_occurrences_with_cancelled() ->
UserId, CalendarId, <<"Weekly">>, StartTime, 60, RRule
),
% Отменяем второе вхождение
CancelTime = {{2026, 6, 8}, {10, 0, 0}},
{ok, cancelled} = logic_event:cancel_occurrence(UserId, Event#event.id, CancelTime),
RangeEnd = {{2026, 6, 29}, {10, 0, 0}},
{ok, Occurrences} = logic_event:get_occurrences(UserId, Event#event.id, RangeEnd),
% 1, 15, 22, 29 июня = 4 вхождения (одно отменено)
?assertEqual(4, length(Occurrences)),
% Проверяем, что отменённого вхождения нет
Starts = [O || {virtual, O} <- Occurrences],
?assertNot(lists:member(CancelTime, Starts)).

View File

@@ -51,7 +51,7 @@ create_test_user_and_calendar() ->
},
mnesia:dirty_write(User),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Test Calendar">>, <<"">>),
{ok, Calendar} = logic_calendar:create_calendar(UserId, <<"Test Calendar">>, <<"">>, manual),
{UserId, Calendar#calendar.id}.
test_create_event() ->
@@ -99,10 +99,8 @@ test_delete_event() ->
test_time_validation() ->
{UserId, CalendarId} = create_test_user_and_calendar(),
% Событие в прошлом
PastTime = {{2020, 1, 1}, {10, 0, 0}},
{error, event_in_past} = logic_event:create_event(UserId, CalendarId, <<"Past">>, PastTime, 60),
% Событие в будущем
FutureTime = {{2030, 1, 1}, {10, 0, 0}},
?assertEqual(ok, logic_event:validate_event_time(FutureTime)).

50
test/scripts/test_all.sh Normal file
View File

@@ -0,0 +1,50 @@
#!/bin/bash
echo "============================================================"
echo " EVENTHUB FULL API TEST SUITE"
echo "============================================================"
echo ""
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Проверяем, что сервер запущен
if ! curl -s "http://localhost:8080/health" | grep -q "ok"; then
echo "❌ Server is not running. Please start the server first."
exit 1
fi
PASSED=0
FAILED=0
run_test() {
echo ""
echo "▶ Running $1..."
if bash "$SCRIPTS_DIR/$1"; then
((PASSED++))
echo "$1 PASSED"
else
((FAILED++))
echo "$1 FAILED"
fi
}
run_test "test_auth_api.sh"
run_test "test_calendar_api.sh"
run_test "test_event_api.sh"
run_test "test_booking_api.sh"
echo ""
echo "============================================================"
echo " TEST SUMMARY"
echo "============================================================"
echo "Passed: $PASSED"
echo "Failed: $FAILED"
echo "============================================================"
if [ $FAILED -eq 0 ]; then
echo "🎉 ALL TESTS PASSED!"
exit 0
else
echo "❌ SOME TESTS FAILED"
exit 1
fi

View File

@@ -0,0 +1,217 @@
#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
BASE_URL="http://localhost:8080"
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
extract_json() {
echo "$1" | grep -o "\"$2\":\"[^\"]*\"" | head -1 | sed "s/\"$2\":\"//;s/\"$//"
}
http_post() {
local url=$1
local data=$2
local token=$3
if [ -n "$token" ]; then
curl -s -X POST "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "$data"
else
curl -s -X POST "$url" \
-H "Content-Type: application/json" \
-d "$data"
fi
}
http_get() {
local url=$1
local token=$2
if [ -n "$token" ]; then
curl -s -X GET "$url" \
-H "Authorization: Bearer $token"
else
curl -s -X GET "$url"
fi
}
echo "============================================================"
echo " EVENTHUB AUTHENTICATION API TEST SCRIPT"
echo "============================================================"
echo ""
log_info "Checking if server is running..."
if ! curl -s "$BASE_URL/health" | grep -q "ok"; then
log_error "Server is not running"
exit 1
fi
log_success "Server is running"
echo ""
log_info "============================================================"
log_info "TEST 1: Healthcheck"
log_info "============================================================"
response=$(http_get "$BASE_URL/health" "")
if echo "$response" | grep -q "ok"; then
log_success "Healthcheck passed: $response"
else
log_error "Healthcheck failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 2: Register new user"
log_info "============================================================"
TEST_EMAIL="test_auth_$(date +%s)@example.com"
TEST_PASSWORD="testpass123"
log_info "Registering $TEST_EMAIL..."
response=$(http_post "$BASE_URL/v1/register" "{\"email\":\"$TEST_EMAIL\",\"password\":\"$TEST_PASSWORD\"}" "")
if echo "$response" | grep -q "token"; then
TOKEN=$(extract_json "$response" "token")
USER_ID=$(extract_json "$response" "id")
log_success "Registration successful"
log_info "User ID: $USER_ID"
log_info "Token: ${TOKEN:0:30}..."
else
log_error "Registration failed: $response"
exit 1
fi
echo ""
log_info "============================================================"
log_info "TEST 3: Register with existing email (should fail)"
log_info "============================================================"
response=$(http_post "$BASE_URL/v1/register" "{\"email\":\"$TEST_EMAIL\",\"password\":\"$TEST_PASSWORD\"}" "")
if echo "$response" | grep -q "already exists"; then
log_success "Duplicate registration correctly rejected"
else
log_error "Duplicate registration not rejected: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 4: Login with correct credentials"
log_info "============================================================"
response=$(http_post "$BASE_URL/v1/login" "{\"email\":\"$TEST_EMAIL\",\"password\":\"$TEST_PASSWORD\"}" "")
if echo "$response" | grep -q "token"; then
LOGIN_TOKEN=$(extract_json "$response" "token")
REFRESH_TOKEN=$(extract_json "$response" "refresh_token")
log_success "Login successful"
log_info "Refresh token received: ${REFRESH_TOKEN:0:30}..."
else
log_error "Login failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 5: Login with wrong password (should fail)"
log_info "============================================================"
response=$(http_post "$BASE_URL/v1/login" "{\"email\":\"$TEST_EMAIL\",\"password\":\"wrongpassword\"}" "")
if echo "$response" | grep -q "Invalid credentials"; then
log_success "Wrong password correctly rejected"
else
log_error "Wrong password not rejected: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 6: Get user profile with valid token"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/user/me" "$TOKEN")
if echo "$response" | grep -q "$TEST_EMAIL"; then
log_success "Profile retrieved successfully"
log_info "Response: $response"
else
log_error "Profile retrieval failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 7: Get user profile with invalid token"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/user/me" "invalid.token.here")
if echo "$response" | grep -q "Invalid token"; then
log_success "Invalid token correctly rejected"
else
log_error "Invalid token not rejected: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 8: Get user profile without token"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/user/me" "")
if echo "$response" | grep -q "Missing or invalid Authorization"; then
log_success "Missing token correctly rejected"
else
log_error "Missing token not rejected: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 9: Refresh token"
log_info "============================================================"
if [ -n "$REFRESH_TOKEN" ]; then
response=$(http_post "$BASE_URL/v1/refresh" "{\"refresh_token\":\"$REFRESH_TOKEN\"}" "")
if echo "$response" | grep -q "token"; then
NEW_TOKEN=$(extract_json "$response" "token")
NEW_REFRESH=$(extract_json "$response" "refresh_token")
log_success "Token refreshed successfully"
log_info "New token: ${NEW_TOKEN:0:30}..."
log_info "New refresh token: ${NEW_REFRESH:0:30}..."
else
log_error "Token refresh failed: $response"
fi
log_info "Trying to reuse old refresh token (should fail)..."
response=$(http_post "$BASE_URL/v1/refresh" "{\"refresh_token\":\"$REFRESH_TOKEN\"}" "")
if echo "$response" | grep -q "Invalid refresh token"; then
log_success "Old refresh token correctly rejected"
else
log_warning "Old refresh token not rejected: $response"
fi
else
log_warning "No refresh token to test"
fi
echo ""
log_info "============================================================"
log_info "TEST 10: Access protected endpoint with new token"
log_info "============================================================"
if [ -n "$NEW_TOKEN" ]; then
response=$(http_get "$BASE_URL/v1/user/me" "$NEW_TOKEN")
if echo "$response" | grep -q "$TEST_EMAIL"; then
log_success "Protected endpoint accessible with new token"
else
log_error "Protected endpoint not accessible: $response"
fi
fi
echo ""
echo "============================================================"
log_success "AUTHENTICATION TESTS COMPLETED!"
echo "============================================================"

View File

@@ -0,0 +1,265 @@
#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
BASE_URL="http://localhost:8080"
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
extract_json() {
echo "$1" | grep -o "\"$2\":\"[^\"]*\"" | head -1 | sed "s/\"$2\":\"//;s/\"$//"
}
http_post() {
local url=$1
local data=$2
local token=$3
if [ -n "$token" ]; then
curl -s -X POST "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "$data"
else
curl -s -X POST "$url" \
-H "Content-Type: application/json" \
-d "$data"
fi
}
http_get() {
local url=$1
local token=$2
if [ -n "$token" ]; then
curl -s -X GET "$url" \
-H "Authorization: Bearer $token"
else
curl -s -X GET "$url"
fi
}
http_put() {
local url=$1
local data=$2
local token=$3
curl -s -X PUT "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "$data"
}
http_delete() {
local url=$1
local token=$2
curl -s -X DELETE "$url" \
-H "Authorization: Bearer $token"
}
echo "============================================================"
echo " EVENTHUB BOOKING API TEST SCRIPT"
echo "============================================================"
echo ""
log_info "Checking if server is running..."
if ! curl -s "$BASE_URL/health" | grep -q "ok"; then
log_error "Server is not running"
exit 1
fi
log_success "Server is running"
echo ""
log_info "============================================================"
log_info "STEP 1: Create test users"
log_info "============================================================"
OWNER_EMAIL="owner_test@example.com"
OWNER_PASSWORD="owner123"
PARTICIPANT_EMAIL="participant_test@example.com"
PARTICIPANT_PASSWORD="participant123"
# Пробуем зарегистрировать владельца
log_info "Creating calendar owner..."
response=$(http_post "$BASE_URL/v1/register" "{\"email\":\"$OWNER_EMAIL\",\"password\":\"$OWNER_PASSWORD\"}" "")
if echo "$response" | grep -q "token"; then
OWNER_TOKEN=$(extract_json "$response" "token")
OWNER_ID=$(extract_json "$response" "id")
log_success "Owner registered: $OWNER_EMAIL"
else
log_info "Owner exists, trying login..."
response=$(http_post "$BASE_URL/v1/login" "{\"email\":\"$OWNER_EMAIL\",\"password\":\"$OWNER_PASSWORD\"}" "")
OWNER_TOKEN=$(extract_json "$response" "token")
OWNER_ID=$(extract_json "$response" "id")
fi
if [ -z "$OWNER_TOKEN" ]; then
log_error "Failed to get owner token"
echo "$response"
exit 1
fi
log_success "Owner ready (ID: $OWNER_ID)"
# Пробуем зарегистрировать участника
log_info "Creating participant..."
response=$(http_post "$BASE_URL/v1/register" "{\"email\":\"$PARTICIPANT_EMAIL\",\"password\":\"$PARTICIPANT_PASSWORD\"}" "")
if echo "$response" | grep -q "token"; then
PARTICIPANT_TOKEN=$(extract_json "$response" "token")
PARTICIPANT_ID=$(extract_json "$response" "id")
log_success "Participant registered: $PARTICIPANT_EMAIL"
else
log_info "Participant exists, trying login..."
response=$(http_post "$BASE_URL/v1/login" "{\"email\":\"$PARTICIPANT_EMAIL\",\"password\":\"$PARTICIPANT_PASSWORD\"}" "")
PARTICIPANT_TOKEN=$(extract_json "$response" "token")
PARTICIPANT_ID=$(extract_json "$response" "id")
fi
if [ -z "$PARTICIPANT_TOKEN" ]; then
log_error "Failed to get participant token"
echo "$response"
exit 1
fi
log_success "Participant ready (ID: $PARTICIPANT_ID)"
echo ""
log_info "============================================================"
log_info "STEP 2: Create calendars"
log_info "============================================================"
log_info "Creating AUTO calendar..."
response=$(http_post "$BASE_URL/v1/calendars" "{\"title\":\"Auto Calendar\",\"confirmation\":\"auto\"}" "$OWNER_TOKEN")
AUTO_CALENDAR_ID=$(extract_json "$response" "id")
log_success "Auto calendar: $AUTO_CALENDAR_ID"
log_info "Creating MANUAL calendar..."
response=$(http_post "$BASE_URL/v1/calendars" "{\"title\":\"Manual Calendar\",\"confirmation\":\"manual\"}" "$OWNER_TOKEN")
MANUAL_CALENDAR_ID=$(extract_json "$response" "id")
log_success "Manual calendar: $MANUAL_CALENDAR_ID"
echo ""
log_info "============================================================"
log_info "STEP 3: Create events"
log_info "============================================================"
EVENT_START="2026-05-01T10:00:00Z"
log_info "Creating event in AUTO calendar..."
response=$(http_post "$BASE_URL/v1/calendars/$AUTO_CALENDAR_ID/events" \
"{\"title\":\"Auto Event\",\"start_time\":\"$EVENT_START\",\"duration\":60,\"capacity\":10}" "$OWNER_TOKEN")
AUTO_EVENT_ID=$(extract_json "$response" "id")
log_success "Auto event: $AUTO_EVENT_ID"
log_info "Creating event in MANUAL calendar..."
response=$(http_post "$BASE_URL/v1/calendars/$MANUAL_CALENDAR_ID/events" \
"{\"title\":\"Manual Event\",\"start_time\":\"$EVENT_START\",\"duration\":60,\"capacity\":10}" "$OWNER_TOKEN")
MANUAL_EVENT_ID=$(extract_json "$response" "id")
log_success "Manual event: $MANUAL_EVENT_ID"
echo ""
log_info "============================================================"
log_info "STEP 4: Test AUTO confirmation"
log_info "============================================================"
log_info "Participant booking AUTO event..."
response=$(http_post "$BASE_URL/v1/events/$AUTO_EVENT_ID/bookings" "" "$PARTICIPANT_TOKEN")
echo "Response: $response"
AUTO_BOOKING_STATUS=$(extract_json "$response" "status")
if [ "$AUTO_BOOKING_STATUS" = "confirmed" ]; then
log_success "Auto-booking confirmed immediately"
else
log_error "Auto-booking status: $AUTO_BOOKING_STATUS"
fi
# Сохраняем ID авто-бронирования
AUTO_BOOKING_ID=$(extract_json "$response" "id")
echo ""
log_info "============================================================"
log_info "STEP 5: Test MANUAL confirmation"
log_info "============================================================"
log_info "Participant booking MANUAL event..."
response=$(http_post "$BASE_URL/v1/events/$MANUAL_EVENT_ID/bookings" "" "$PARTICIPANT_TOKEN")
MANUAL_BOOKING_ID=$(extract_json "$response" "id")
MANUAL_BOOKING_STATUS=$(extract_json "$response" "status")
if [ "$MANUAL_BOOKING_STATUS" = "pending" ]; then
log_success "Manual-booking is pending: $MANUAL_BOOKING_ID"
else
log_error "Manual-booking status: $MANUAL_BOOKING_STATUS"
fi
log_info "Owner confirming booking..."
response=$(http_put "$BASE_URL/v1/bookings/$MANUAL_BOOKING_ID" "{\"action\":\"confirm\"}" "$OWNER_TOKEN")
CONFIRMED_STATUS=$(extract_json "$response" "status")
if [ "$CONFIRMED_STATUS" = "confirmed" ]; then
log_success "Booking confirmed by owner"
else
log_error "Confirmation failed"
fi
echo ""
log_info "============================================================"
log_info "STEP 6: Test booking lists"
log_info "============================================================"
log_info "Owner viewing event bookings..."
response=$(http_get "$BASE_URL/v1/events/$MANUAL_EVENT_ID/bookings" "$OWNER_TOKEN")
echo "Response: $response"
log_info "Participant viewing their bookings..."
response=$(http_get "$BASE_URL/v1/user/bookings" "$PARTICIPANT_TOKEN")
echo "Response: $response"
echo ""
log_info "============================================================"
log_info "STEP 7: Test booking cancellation"
log_info "============================================================"
# Используем первое бронирование для отмены
if [ -n "$AUTO_BOOKING_ID" ]; then
CANCEL_BOOKING_ID="$AUTO_BOOKING_ID"
log_info "Using auto-booking for cancellation: $CANCEL_BOOKING_ID"
else
# Создаём новое событие для теста отмены
log_info "Creating new event for cancellation test..."
response=$(http_post "$BASE_URL/v1/calendars/$MANUAL_CALENDAR_ID/events" \
"{\"title\":\"Cancel Test Event\",\"start_time\":\"$EVENT_START\",\"duration\":60,\"capacity\":10}" "$OWNER_TOKEN")
CANCEL_EVENT_ID=$(extract_json "$response" "id")
log_info "Event created: $CANCEL_EVENT_ID"
log_info "Creating booking to cancel..."
response=$(http_post "$BASE_URL/v1/events/$CANCEL_EVENT_ID/bookings" "" "$PARTICIPANT_TOKEN")
CANCEL_BOOKING_ID=$(extract_json "$response" "id")
log_info "Created: $CANCEL_BOOKING_ID"
fi
if [ -n "$CANCEL_BOOKING_ID" ]; then
log_info "Cancelling booking $CANCEL_BOOKING_ID..."
response=$(http_delete "$BASE_URL/v1/bookings/$CANCEL_BOOKING_ID" "$PARTICIPANT_TOKEN")
CANCELLED_STATUS=$(extract_json "$response" "status")
if [ "$CANCELLED_STATUS" = "cancelled" ]; then
log_success "Booking cancelled"
else
log_error "Cancellation failed: $response"
fi
else
log_error "No booking to cancel"
fi
echo ""
echo "============================================================"
log_success "TESTS COMPLETED!"
echo "============================================================"

View File

@@ -0,0 +1,217 @@
#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
BASE_URL="http://localhost:8080"
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
extract_json() {
echo "$1" | grep -o "\"$2\":\"[^\"]*\"" | head -1 | sed "s/\"$2\":\"//;s/\"$//"
}
http_post() {
local url=$1
local data=$2
local token=$3
if [ -n "$token" ]; then
curl -s -X POST "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "$data"
else
curl -s -X POST "$url" \
-H "Content-Type: application/json" \
-d "$data"
fi
}
http_get() {
local url=$1
local token=$2
if [ -n "$token" ]; then
curl -s -X GET "$url" \
-H "Authorization: Bearer $token"
else
curl -s -X GET "$url"
fi
}
http_put() {
local url=$1
local data=$2
local token=$3
curl -s -X PUT "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "$data"
}
http_delete() {
local url=$1; local token=$2
curl -s -X DELETE "$url" -H "Authorization: Bearer $token"
}
echo "============================================================"
echo " EVENTHUB CALENDAR API TEST SCRIPT"
echo "============================================================"
echo ""
log_info "Setting up test users..."
# Создаём двух пользователей
OWNER_EMAIL="calendar_owner_$(date +%s)@example.com"
OWNER_PASS="owner123"
OTHER_EMAIL="calendar_other_$(date +%s)@example.com"
OTHER_PASS="other123"
# Владелец
response=$(http_post "$BASE_URL/v1/register" "{\"email\":\"$OWNER_EMAIL\",\"password\":\"$OWNER_PASS\"}" "")
OWNER_TOKEN=$(extract_json "$response" "token")
OWNER_ID=$(extract_json "$response" "id")
log_success "Owner created: $OWNER_ID"
# Другой пользователь
response=$(http_post "$BASE_URL/v1/register" "{\"email\":\"$OTHER_EMAIL\",\"password\":\"$OTHER_PASS\"}" "")
OTHER_TOKEN=$(extract_json "$response" "token")
OTHER_ID=$(extract_json "$response" "id")
log_success "Other user created: $OTHER_ID"
echo ""
log_info "============================================================"
log_info "TEST 1: Create calendar"
log_info "============================================================"
response=$(http_post "$BASE_URL/v1/calendars" "{\"title\":\"My Personal Calendar\",\"description\":\"Test description\"}" "$OWNER_TOKEN")
CALENDAR_ID=$(extract_json "$response" "id")
if [ -n "$CALENDAR_ID" ]; then
log_success "Calendar created: $CALENDAR_ID"
else
log_error "Calendar creation failed: $response"
exit 1
fi
echo ""
log_info "============================================================"
log_info "TEST 2: Create commercial calendar"
log_info "============================================================"
response=$(http_post "$BASE_URL/v1/calendars" "{\"title\":\"Commercial Calendar\",\"type\":\"commercial\"}" "$OWNER_TOKEN")
COMMERCIAL_ID=$(extract_json "$response" "id")
log_success "Commercial calendar created: $COMMERCIAL_ID"
echo ""
log_info "============================================================"
log_info "TEST 3: List calendars (owner)"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/calendars" "$OWNER_TOKEN")
COUNT=$(echo "$response" | grep -o "\"id\"" | wc -l)
log_success "Owner sees $COUNT calendars"
echo ""
log_info "============================================================"
log_info "TEST 4: List calendars (other user - empty)"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/calendars" "$OTHER_TOKEN")
COUNT=$(echo "$response" | grep -o "\"id\"" | wc -l)
log_success "Other user sees $COUNT calendars"
echo ""
log_info "============================================================"
log_info "TEST 5: Get calendar by ID (owner)"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/calendars/$CALENDAR_ID" "$OWNER_TOKEN")
if echo "$response" | grep -q "My Personal Calendar"; then
log_success "Owner can access personal calendar"
else
log_error "Owner cannot access calendar: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 6: Get personal calendar (other user - denied)"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/calendars/$CALENDAR_ID" "$OTHER_TOKEN")
if echo "$response" | grep -q "Access denied"; then
log_success "Other user correctly denied access to personal calendar"
else
log_error "Access control failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 7: Get commercial calendar (other user - allowed)"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/calendars/$COMMERCIAL_ID" "$OTHER_TOKEN")
if echo "$response" | grep -q "Commercial Calendar"; then
log_success "Other user can access commercial calendar"
else
log_error "Other user cannot access commercial calendar: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 8: Update calendar (owner)"
log_info "============================================================"
response=$(http_put "$BASE_URL/v1/calendars/$CALENDAR_ID" "{\"title\":\"Updated Calendar\"}" "$OWNER_TOKEN")
if echo "$response" | grep -q "Updated Calendar"; then
log_success "Calendar updated successfully"
else
log_error "Calendar update failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 9: Update calendar (other user - denied)"
log_info "============================================================"
response=$(http_put "$BASE_URL/v1/calendars/$CALENDAR_ID" "{\"title\":\"Hacked\"}" "$OTHER_TOKEN")
if echo "$response" | grep -q "Access denied"; then
log_success "Other user correctly denied update"
else
log_error "Access control failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 10: Delete calendar (owner)"
log_info "============================================================"
response=$(http_delete "$BASE_URL/v1/calendars/$CALENDAR_ID" "$OWNER_TOKEN")
if echo "$response" | grep -q "deleted"; then
log_success "Calendar deleted"
else
log_error "Calendar deletion failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 11: Get deleted calendar (should be denied)"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/calendars/$CALENDAR_ID" "$OWNER_TOKEN")
if echo "$response" | grep -q "Access denied"; then
log_success "Deleted calendar not accessible"
else
log_error "Deleted calendar still accessible: $response"
fi
echo ""
echo "============================================================"
log_success "CALENDAR API TESTS COMPLETED!"
echo "============================================================"

View File

@@ -0,0 +1,212 @@
#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
BASE_URL="http://localhost:8080"
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
extract_json() {
echo "$1" | grep -o "\"$2\":\"[^\"]*\"" | head -1 | sed "s/\"$2\":\"//;s/\"$//"
}
http_post() {
local url=$1
local data=$2
local token=$3
if [ -n "$token" ]; then
curl -s -X POST "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "$data"
else
curl -s -X POST "$url" \
-H "Content-Type: application/json" \
-d "$data"
fi
}
http_get() {
local url=$1
local token=$2
if [ -n "$token" ]; then
curl -s -X GET "$url" \
-H "Authorization: Bearer $token"
else
curl -s -X GET "$url"
fi
}
http_put() {
local url=$1
local data=$2
local token=$3
curl -s -X PUT "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "$data"
}
http_delete() {
local url=$1; local token=$2
curl -s -X DELETE "$url" -H "Authorization: Bearer $token"
}
echo "============================================================"
echo " EVENTHUB EVENT API TEST SCRIPT"
echo "============================================================"
echo ""
log_info "Setting up test users and calendar..."
OWNER_EMAIL="event_owner_$(date +%s)@example.com"
OWNER_PASS="owner123"
response=$(http_post "$BASE_URL/v1/register" "{\"email\":\"$OWNER_EMAIL\",\"password\":\"$OWNER_PASS\"}" "")
OWNER_TOKEN=$(extract_json "$response" "token")
OWNER_ID=$(extract_json "$response" "id")
log_success "Owner created"
response=$(http_post "$BASE_URL/v1/calendars" "{\"title\":\"Test Calendar\"}" "$OWNER_TOKEN")
CALENDAR_ID=$(extract_json "$response" "id")
log_success "Calendar created: $CALENDAR_ID"
echo ""
log_info "============================================================"
log_info "TEST 1: Create single event"
log_info "============================================================"
EVENT_START="2026-06-01T10:00:00Z"
response=$(http_post "$BASE_URL/v1/calendars/$CALENDAR_ID/events" \
"{\"title\":\"Single Event\",\"start_time\":\"$EVENT_START\",\"duration\":60}" "$OWNER_TOKEN")
EVENT_ID=$(extract_json "$response" "id")
if [ -n "$EVENT_ID" ]; then
log_success "Single event created: $EVENT_ID"
else
log_error "Event creation failed: $response"
exit 1
fi
echo ""
log_info "============================================================"
log_info "TEST 2: Create event with capacity"
log_info "============================================================"
response=$(http_post "$BASE_URL/v1/calendars/$CALENDAR_ID/events" \
"{\"title\":\"Capacity Event\",\"start_time\":\"$EVENT_START\",\"duration\":60,\"capacity\":10}" "$OWNER_TOKEN")
CAPACITY_EVENT_ID=$(extract_json "$response" "id")
log_success "Event with capacity created: $CAPACITY_EVENT_ID"
echo ""
log_info "============================================================"
log_info "TEST 3: Create event in past (should fail)"
log_info "============================================================"
PAST_START="2020-01-01T10:00:00Z"
response=$(http_post "$BASE_URL/v1/calendars/$CALENDAR_ID/events" \
"{\"title\":\"Past Event\",\"start_time\":\"$PAST_START\",\"duration\":60}" "$OWNER_TOKEN")
if echo "$response" | grep -q "past"; then
log_success "Past event correctly rejected"
else
log_error "Past event not rejected: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 4: List events"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/calendars/$CALENDAR_ID/events" "$OWNER_TOKEN")
COUNT=$(echo "$response" | grep -o "\"id\"" | wc -l)
log_success "Found $COUNT events"
echo ""
log_info "============================================================"
log_info "TEST 5: Get event by ID"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/events/$EVENT_ID" "$OWNER_TOKEN")
if echo "$response" | grep -q "Single Event"; then
log_success "Event retrieved successfully"
else
log_error "Event retrieval failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 6: Update event"
log_info "============================================================"
response=$(http_put "$BASE_URL/v1/events/$EVENT_ID" "{\"title\":\"Updated Event\"}" "$OWNER_TOKEN")
if echo "$response" | grep -q "Updated Event"; then
log_success "Event updated"
else
log_error "Event update failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 7: Delete event"
log_info "============================================================"
response=$(http_delete "$BASE_URL/v1/events/$EVENT_ID" "$OWNER_TOKEN")
if echo "$response" | grep -q "deleted"; then
log_success "Event deleted"
else
log_error "Event deletion failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 8: Get deleted event (should fail)"
log_info "============================================================"
response=$(http_get "$BASE_URL/v1/events/$EVENT_ID" "$OWNER_TOKEN")
if echo "$response" | grep -q "not found"; then
log_success "Deleted event not found"
else
log_error "Deleted event still accessible: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 9: Create recurring event"
log_info "============================================================"
response=$(http_post "$BASE_URL/v1/calendars/$CALENDAR_ID/events" \
"{\"title\":\"Weekly Meeting\",\"start_time\":\"$EVENT_START\",\"duration\":60,\"recurrence\":{\"freq\":\"WEEKLY\",\"interval\":1}}" "$OWNER_TOKEN")
RECURRING_ID=$(extract_json "$response" "id")
if [ -n "$RECURRING_ID" ]; then
log_success "Recurring event created: $RECURRING_ID"
else
log_error "Recurring event creation failed: $response"
fi
echo ""
log_info "============================================================"
log_info "TEST 10: Get occurrences"
log_info "============================================================"
FROM="2026-06-01T00:00:00Z"
TO="2026-06-30T00:00:00Z"
response=$(http_get "$BASE_URL/v1/events/$RECURRING_ID/occurrences?from=$FROM&to=$TO" "$OWNER_TOKEN")
if [ -n "$response" ] && [ "$response" != "[]" ]; then
log_success "Occurrences retrieved"
else
log_error "Occurrences retrieval failed: $response"
fi
echo ""
echo "============================================================"
log_success "EVENT API TESTS COMPLETED!"
echo "============================================================"