Summary| Tags| Feature: api/event-availability-visibility/event-availability-visibility.feature| Ticketing MVP - Event Availability Visibility As a buyer I want to view event availability and tier status So that I can see which tiers are available for purchase
Scenario: [1:12] Scenario 1 - Event visible with valid availability by tier
ms: 100
>>
Background:
7
* def baseUrlEvents = karate.properties['baseUrlEvents'] || 'http://localhost:8081'
1
22:50:36.707 karate.env system property was: null
8
* def baseUrlTicketing = karate.properties['baseUrlTicketing'] || 'http://localhost:8082'
1
9
* def UUID = Java.type('java.util.UUID')
0
10
* def futureDate = '2026-12-15T20:00:00'
0
14
* def tag = UUID.randomUUID() + ''
1
15
* def eventTitle = 'Avail S1 ' + tag
0
17
Given url baseUrlEvents + '/api/v1/rooms'
0
18
And header X-Role = 'ADMIN'
0
19
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
20
And request { name: 'Availability Room S1', maxCapacity: 200 }
0
21
When method post
16
22:50:36.714 request: 1 > POST http://localhost:8081/api/v1/rooms 1 > X-Role: ADMIN 1 > X-User-Id: 00000000-0000-0000-0000-000000000001 1 > Content-Type: application/json; charset=UTF-8 1 > Content-Length: 49 1 > Host: localhost:8081 1 > Connection: Keep-Alive 1 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 1 > Accept-Encoding: gzip,deflate {"name":"Availability Room S1","maxCapacity":200} 22:50:36.728 response time in milliseconds: 14 1 < 201 1 < Content-Type: application/json 1 < Transfer-Encoding: chunked 1 < Date: Wed, 08 Apr 2026 03:50:36 GMT 1 < Keep-Alive: timeout=60 1 < Connection: keep-alive {"id":"6ebd1bc5-7f63-4ae3-abe2-b16d1a46a286","name":"Availability Room S1","maxCapacity":200,"created_at":"2026-04-08T03:50:36.717334123","updated_at":"2026-04-08T03:50:36.717351566"}
22
Then status 201
0
23
* def roomId = response.id
1
25
Given url baseUrlEvents + '/api/v1/events'
0
26
And header X-Role = 'ADMIN'
0
27
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
28
And request
1
{ "roomId": "#(roomId)", "title": "#(eventTitle)", "description": "Test event for availability", "date": "#(futureDate)", "capacity": 100, "enableSeats": false }
39
When method post
19
22:50:36.731 request: 2 > POST http://localhost:8081/api/v1/events 2 > X-Role: ADMIN 2 > X-User-Id: 00000000-0000-0000-0000-000000000001 2 > Content-Type: application/json; charset=UTF-8 2 > Content-Length: 213 2 > Host: localhost:8081 2 > Connection: Keep-Alive 2 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 2 > Accept-Encoding: gzip,deflate {"roomId":"6ebd1bc5-7f63-4ae3-abe2-b16d1a46a286","title":"Avail S1 ec1d6ac6-17ab-4fb2-a33c-44b80005a763","description":"Test event for availability","date":"2026-12-15T20:00:00","capacity":100,"enableSeats":false} 22:50:36.749 response time in milliseconds: 17 2 < 201 2 < Content-Type: application/json 2 < Transfer-Encoding: chunked 2 < Date: Wed, 08 Apr 2026 03:50:36 GMT 2 < Keep-Alive: timeout=60 2 < Connection: keep-alive {"id":"f8ba3e5f-7e05-4457-b9b0-39702f084b38","roomId":"6ebd1bc5-7f63-4ae3-abe2-b16d1a46a286","title":"Avail S1 ec1d6ac6-17ab-4fb2-a33c-44b80005a763","description":"Test event for availability","date":"2026-12-15T20:00:00","capacity":100,"status":"DRAFT","createdAt":"2026-04-08T03:50:36.738559018","updatedAt":"2026-04-08T03:50:36.738569769","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
40
Then status 201
0
41
* def eventId = response.id
1
43
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/tiers'
0
44
And header X-Role = 'ADMIN'
0
45
And request
0
[{ "tierType": "GENERAL", "price": 50, "quota": 100 }]
49
When method post
19
22:50:36.752 request: 3 > POST http://localhost:8081/api/v1/events/f8ba3e5f-7e05-4457-b9b0-39702f084b38/tiers 3 > X-Role: ADMIN 3 > Content-Type: application/json; charset=UTF-8 3 > Content-Length: 47 3 > Host: localhost:8081 3 > Connection: Keep-Alive 3 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 3 > Accept-Encoding: gzip,deflate [{"tierType":"GENERAL","price":50,"quota":100}] 22:50:36.769 response time in milliseconds: 16 3 < 201 3 < Content-Type: application/json 3 < Transfer-Encoding: chunked 3 < Date: Wed, 08 Apr 2026 03:50:36 GMT 3 < Keep-Alive: timeout=60 3 < Connection: keep-alive {"eventId":"f8ba3e5f-7e05-4457-b9b0-39702f084b38","tiers":[{"id":"2f5d0ddc-ea47-4e29-a64b-9e74b03c3d7c","tierType":"GENERAL","price":50,"quota":100,"validFrom":null,"validUntil":null,"createdAt":"2026-04-08T03:50:36.75999407","updatedAt":"2026-04-08T03:50:36.760006291"}]}
50
Then status 201
0
51
* def tierId = response.tiers[0].id
1
53
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/publish'
0
54
And header X-Role = 'ADMIN'
0
55
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
56
When method patch
22
22:50:36.771 request: 4 > PATCH http://localhost:8081/api/v1/events/f8ba3e5f-7e05-4457-b9b0-39702f084b38/publish 4 > X-Role: ADMIN 4 > X-User-Id: 00000000-0000-0000-0000-000000000001 4 > Host: localhost:8081 4 > Connection: Keep-Alive 4 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 4 > Accept-Encoding: gzip,deflate 22:50:36.793 response time in milliseconds: 20 4 < 200 4 < Content-Type: application/json 4 < Transfer-Encoding: chunked 4 < Date: Wed, 08 Apr 2026 03:50:36 GMT 4 < Keep-Alive: timeout=60 4 < Connection: keep-alive {"id":"f8ba3e5f-7e05-4457-b9b0-39702f084b38","roomId":"6ebd1bc5-7f63-4ae3-abe2-b16d1a46a286","title":"Avail S1 ec1d6ac6-17ab-4fb2-a33c-44b80005a763","description":"Test event for availability","date":"2026-12-15T20:00:00","capacity":100,"status":"PUBLISHED","createdAt":"2026-04-08T03:50:36.738559","updatedAt":"2026-04-08T03:50:36.780636855","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
57
Then status 200
0
59
Given url baseUrlEvents + '/api/v1/events/' + eventId
0
60
When method get
14
22:50:36.794 request: 5 > GET http://localhost:8081/api/v1/events/f8ba3e5f-7e05-4457-b9b0-39702f084b38 5 > Host: localhost:8081 5 > Connection: Keep-Alive 5 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 5 > Accept-Encoding: gzip,deflate 22:50:36.807 response time in milliseconds: 13 5 < 200 5 < Content-Type: application/json 5 < Transfer-Encoding: chunked 5 < Date: Wed, 08 Apr 2026 03:50:36 GMT 5 < Keep-Alive: timeout=60 5 < Connection: keep-alive {"id":"f8ba3e5f-7e05-4457-b9b0-39702f084b38","title":"Avail S1 ec1d6ac6-17ab-4fb2-a33c-44b80005a763","description":"Test event for availability","date":"2026-12-15T20:00:00","capacity":100,"room":{"id":"6ebd1bc5-7f63-4ae3-abe2-b16d1a46a286","name":"Availability Room S1","maxCapacity":200,"created_at":"2026-04-08T03:50:36.717334","updated_at":"2026-04-08T03:50:36.717352"},"availableTiers":[{"id":"2f5d0ddc-ea47-4e29-a64b-9e74b03c3d7c","tierType":"GENERAL","price":50.00,"quota":100,"validFrom":null,"validUntil":null,"isAvailable":true,"reason":null}],"created_at":"2026-04-08T03:50:36.738559","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
61
Then status 200
0
62
* match response.availableTiers != null && response.availableTiers.length > 0
1
63
* def tier = response.availableTiers[0]
0
64
* match tier.tierType == 'GENERAL'
0
65
* match tier.quota == 100
1
66
* match tier.isAvailable == true
0
67
* match tier.price == 50.0
0
68
* print 'Scenario 1 PASS: Event visible with 100 available in GENERAL tier'
0
22:50:36.811 [print] Scenario 1 PASS: Event visible with 100 available in GENERAL tier
Scenario: [2:71] Scenario 2 - Exhausted tier (quota=2 reached via 2 approved payments)
ms: 851
>>
Background:
7
* def baseUrlEvents = karate.properties['baseUrlEvents'] || 'http://localhost:8081'
0
22:50:36.813 karate.env system property was: null
8
* def baseUrlTicketing = karate.properties['baseUrlTicketing'] || 'http://localhost:8082'
0
9
* def UUID = Java.type('java.util.UUID')
0
10
* def futureDate = '2026-12-15T20:00:00'
0
73
* def tag = UUID.randomUUID() + ''
0
74
* def eventTitle = 'Avail S2 ' + tag
0
75
* def buyer1Id = UUID.randomUUID() + ''
0
76
* def buyer2Id = UUID.randomUUID() + ''
0
78
Given url baseUrlEvents + '/api/v1/rooms'
0
79
And header X-Role = 'ADMIN'
0
80
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
81
And request { name: 'Exhausted Tier Room S2', maxCapacity: 50 }
0
82
When method post
12
22:50:36.817 request: 1 > POST http://localhost:8081/api/v1/rooms 1 > X-Role: ADMIN 1 > X-User-Id: 00000000-0000-0000-0000-000000000001 1 > Content-Type: application/json; charset=UTF-8 1 > Content-Length: 50 1 > Host: localhost:8081 1 > Connection: Keep-Alive 1 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 1 > Accept-Encoding: gzip,deflate {"name":"Exhausted Tier Room S2","maxCapacity":50} 22:50:36.827 response time in milliseconds: 10 1 < 201 1 < Content-Type: application/json 1 < Transfer-Encoding: chunked 1 < Date: Wed, 08 Apr 2026 03:50:36 GMT 1 < Keep-Alive: timeout=60 1 < Connection: keep-alive {"id":"10e2c018-89bf-4a37-b8e7-2bc016a4a856","name":"Exhausted Tier Room S2","maxCapacity":50,"created_at":"2026-04-08T03:50:36.820135714","updated_at":"2026-04-08T03:50:36.820148002"}
83
Then status 201
0
84
* def roomId = response.id
0
86
Given url baseUrlEvents + '/api/v1/events'
0
87
And header X-Role = 'ADMIN'
0
88
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
89
And request
0
{ "roomId": "#(roomId)", "title": "#(eventTitle)", "description": "Test event exhausted tier", "date": "#(futureDate)", "capacity": 5, "enableSeats": false }
100
When method post
16
22:50:36.831 request: 2 > POST http://localhost:8081/api/v1/events 2 > X-Role: ADMIN 2 > X-User-Id: 00000000-0000-0000-0000-000000000001 2 > Content-Type: application/json; charset=UTF-8 2 > Content-Length: 209 2 > Host: localhost:8081 2 > Connection: Keep-Alive 2 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 2 > Accept-Encoding: gzip,deflate {"roomId":"10e2c018-89bf-4a37-b8e7-2bc016a4a856","title":"Avail S2 7c87cb95-f667-44df-bd2b-2331f4f4f167","description":"Test event exhausted tier","date":"2026-12-15T20:00:00","capacity":5,"enableSeats":false} 22:50:36.845 response time in milliseconds: 14 2 < 201 2 < Content-Type: application/json 2 < Transfer-Encoding: chunked 2 < Date: Wed, 08 Apr 2026 03:50:36 GMT 2 < Keep-Alive: timeout=60 2 < Connection: keep-alive {"id":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","roomId":"10e2c018-89bf-4a37-b8e7-2bc016a4a856","title":"Avail S2 7c87cb95-f667-44df-bd2b-2331f4f4f167","description":"Test event exhausted tier","date":"2026-12-15T20:00:00","capacity":5,"status":"DRAFT","createdAt":"2026-04-08T03:50:36.838884653","updatedAt":"2026-04-08T03:50:36.838897855","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
101
Then status 201
0
102
* def eventId = response.id
0
104
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/tiers'
0
105
And header X-Role = 'ADMIN'
0
106
And request
0
[{ "tierType": "GENERAL", "price": 40, "quota": 2 }]
110
When method post
16
22:50:36.848 request: 3 > POST http://localhost:8081/api/v1/events/fe5916cf-204e-48d9-8aa9-00269ee2ad53/tiers 3 > X-Role: ADMIN 3 > Content-Type: application/json; charset=UTF-8 3 > Content-Length: 45 3 > Host: localhost:8081 3 > Connection: Keep-Alive 3 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 3 > Accept-Encoding: gzip,deflate [{"tierType":"GENERAL","price":40,"quota":2}] 22:50:36.863 response time in milliseconds: 15 3 < 201 3 < Content-Type: application/json 3 < Transfer-Encoding: chunked 3 < Date: Wed, 08 Apr 2026 03:50:36 GMT 3 < Keep-Alive: timeout=60 3 < Connection: keep-alive {"eventId":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","tiers":[{"id":"2274ff34-294a-4576-9ade-074e47f3c178","tierType":"GENERAL","price":40,"quota":2,"validFrom":null,"validUntil":null,"createdAt":"2026-04-08T03:50:36.85578232","updatedAt":"2026-04-08T03:50:36.85579937"}]}
111
Then status 201
0
112
* def tierId = response.tiers[0].id
0
114
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/publish'
0
115
And header X-Role = 'ADMIN'
0
116
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
117
When method patch
15
22:50:36.865 request: 4 > PATCH http://localhost:8081/api/v1/events/fe5916cf-204e-48d9-8aa9-00269ee2ad53/publish 4 > X-Role: ADMIN 4 > X-User-Id: 00000000-0000-0000-0000-000000000001 4 > Host: localhost:8081 4 > Connection: Keep-Alive 4 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 4 > Accept-Encoding: gzip,deflate 22:50:36.878 response time in milliseconds: 12 4 < 200 4 < Content-Type: application/json 4 < Transfer-Encoding: chunked 4 < Date: Wed, 08 Apr 2026 03:50:36 GMT 4 < Keep-Alive: timeout=60 4 < Connection: keep-alive {"id":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","roomId":"10e2c018-89bf-4a37-b8e7-2bc016a4a856","title":"Avail S2 7c87cb95-f667-44df-bd2b-2331f4f4f167","description":"Test event exhausted tier","date":"2026-12-15T20:00:00","capacity":5,"status":"PUBLISHED","createdAt":"2026-04-08T03:50:36.838885","updatedAt":"2026-04-08T03:50:36.870555216","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
118
Then status 200
0
# Reservation 1 + approved payment
121
* def email1 = 'b1s2-' + tag + '@karate.com'
1
122
Given url baseUrlTicketing + '/api/v1/reservations'
0
123
And header X-User-Id = buyer1Id
0
124
And request
1
{ "eventId": "#(eventId)", "tierId": "#(tierId)", "buyerEmail": "#(email1)" }
128
When method post
600
22:50:36.882 request: 5 > POST http://localhost:8082/api/v1/reservations 5 > X-User-Id: e05b8d9b-036b-42a1-b16a-17b8eb2bb694 5 > Content-Type: application/json; charset=UTF-8 5 > Content-Length: 166 5 > Host: localhost:8082 5 > Connection: Keep-Alive 5 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 5 > Accept-Encoding: gzip,deflate {"eventId":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","tierId":"2274ff34-294a-4576-9ade-074e47f3c178","buyerEmail":"b1s2-7c87cb95-f667-44df-bd2b-2331f4f4f167@karate.com"} 22:50:37.481 response time in milliseconds: 599 5 < 201 5 < Content-Type: application/json 5 < Transfer-Encoding: chunked 5 < Date: Wed, 08 Apr 2026 03:50:37 GMT 5 < Keep-Alive: timeout=60 5 < Connection: keep-alive {"id":"2ebe8b5f-1db9-4f11-9395-0e6693b986ae","eventId":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","tierId":"2274ff34-294a-4576-9ade-074e47f3c178","buyerId":"e05b8d9b-036b-42a1-b16a-17b8eb2bb694","status":"PENDING","createdAt":"2026-04-08T03:50:37.40949172","updatedAt":"2026-04-08T03:50:37.40949172","validUntilAt":"2026-04-08T04:00:37.40949172"}
129
Then status 201
0
130
* def res1 = response.id
0
132
Given url baseUrlTicketing + '/api/v1/reservations/' + res1 + '/payments'
1
133
And header X-User-Id = buyer1Id
0
134
And request { amount: 40, paymentMethod: 'MOCK', status: 'APPROVED' }
0
135
When method post
96
22:50:37.484 request: 6 > POST http://localhost:8082/api/v1/reservations/2ebe8b5f-1db9-4f11-9395-0e6693b986ae/payments 6 > X-User-Id: e05b8d9b-036b-42a1-b16a-17b8eb2bb694 6 > Content-Type: application/json; charset=UTF-8 6 > Content-Length: 56 6 > Host: localhost:8082 6 > Connection: Keep-Alive 6 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 6 > Accept-Encoding: gzip,deflate {"amount":40,"paymentMethod":"MOCK","status":"APPROVED"} 22:50:37.577 response time in milliseconds: 93 6 < 200 6 < Content-Type: application/json 6 < Transfer-Encoding: chunked 6 < Date: Wed, 08 Apr 2026 03:50:37 GMT 6 < Keep-Alive: timeout=60 6 < Connection: keep-alive {"reservationId":"2ebe8b5f-1db9-4f11-9395-0e6693b986ae","status":"CONFIRMED","ticketId":"f6a89f92-5fa5-40d7-98e8-a92e9ffaa97b","message":"Payment approved. Ticket generated.","ticket":{"ticketId":"f6a89f92-5fa5-40d7-98e8-a92e9ffaa97b","eventId":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","eventTitle":"Avail S2 7c87cb95-f667-44df-bd2b-2331f4f4f167","eventDate":"2026-12-15T20:00:00","tier":"GENERAL","pricePaid":40,"status":"VALID","purchasedAt":"2026-04-08T03:50:37.522693432","buyerEmail":"b1s2-7c87cb95-f667-44df-bd2b-2331f4f4f167@karate.com","reservationId":"2ebe8b5f-1db9-4f11-9395-0e6693b986ae"},"timestamp":"2026-04-08T03:50:37.539608404"}
136
Then status 200
0
# Reservation 2 + approved payment
139
* def email2 = 'b2s2-' + tag + '@karate.com'
1
140
Given url baseUrlTicketing + '/api/v1/reservations'
0
141
And header X-User-Id = buyer2Id
0
142
And request
1
{ "eventId": "#(eventId)", "tierId": "#(tierId)", "buyerEmail": "#(email2)" }
146
When method post
38
22:50:37.581 request: 7 > POST http://localhost:8082/api/v1/reservations 7 > X-User-Id: 65b0b890-1174-4552-b842-ee5854ca89dc 7 > Content-Type: application/json; charset=UTF-8 7 > Content-Length: 166 7 > Host: localhost:8082 7 > Connection: Keep-Alive 7 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 7 > Accept-Encoding: gzip,deflate {"eventId":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","tierId":"2274ff34-294a-4576-9ade-074e47f3c178","buyerEmail":"b2s2-7c87cb95-f667-44df-bd2b-2331f4f4f167@karate.com"} 22:50:37.617 response time in milliseconds: 36 7 < 201 7 < Content-Type: application/json 7 < Transfer-Encoding: chunked 7 < Date: Wed, 08 Apr 2026 03:50:37 GMT 7 < Keep-Alive: timeout=60 7 < Connection: keep-alive {"id":"14ed702d-0e67-49b7-8ffd-96dfe9851ada","eventId":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","tierId":"2274ff34-294a-4576-9ade-074e47f3c178","buyerId":"65b0b890-1174-4552-b842-ee5854ca89dc","status":"PENDING","createdAt":"2026-04-08T03:50:37.609754075","updatedAt":"2026-04-08T03:50:37.609754075","validUntilAt":"2026-04-08T04:00:37.609754075"}
147
Then status 201
0
148
* def res2 = response.id
0
151
Given url baseUrlTicketing + '/api/v1/reservations/' + res2 + '/payments'
1
152
And header X-User-Id = buyer2Id
0
153
And request { amount: 40, paymentMethod: 'MOCK', status: 'APPROVED' }
0
154
When method post
36
22:50:37.621 request: 8 > POST http://localhost:8082/api/v1/reservations/14ed702d-0e67-49b7-8ffd-96dfe9851ada/payments 8 > X-User-Id: 65b0b890-1174-4552-b842-ee5854ca89dc 8 > Content-Type: application/json; charset=UTF-8 8 > Content-Length: 56 8 > Host: localhost:8082 8 > Connection: Keep-Alive 8 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 8 > Accept-Encoding: gzip,deflate {"amount":40,"paymentMethod":"MOCK","status":"APPROVED"} 22:50:37.655 response time in milliseconds: 33 8 < 200 8 < Content-Type: application/json 8 < Transfer-Encoding: chunked 8 < Date: Wed, 08 Apr 2026 03:50:37 GMT 8 < Keep-Alive: timeout=60 8 < Connection: keep-alive {"reservationId":"14ed702d-0e67-49b7-8ffd-96dfe9851ada","status":"CONFIRMED","ticketId":"3c66f05b-05ff-4e49-9623-46197f90e395","message":"Payment approved. Ticket generated.","ticket":{"ticketId":"3c66f05b-05ff-4e49-9623-46197f90e395","eventId":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","eventTitle":"Avail S2 7c87cb95-f667-44df-bd2b-2331f4f4f167","eventDate":"2026-12-15T20:00:00","tier":"GENERAL","pricePaid":40,"status":"VALID","purchasedAt":"2026-04-08T03:50:37.636089702","buyerEmail":"b2s2-7c87cb95-f667-44df-bd2b-2331f4f4f167@karate.com","reservationId":"14ed702d-0e67-49b7-8ffd-96dfe9851ada"},"timestamp":"2026-04-08T03:50:37.644781256"}
155
Then status 200
0
# HU-03: Verify tier shows as unavailable (isAvailable = false)
# Note: 'quota' in availableTiers is the REMAINING quota (decremented per approved payment)
# After 2 approved payments on quota=2, remaining quota = 0 and isAvailable = false
160
Given url baseUrlEvents + '/api/v1/events/' + eventId
0
161
When method get
9
22:50:37.656 request: 9 > GET http://localhost:8081/api/v1/events/fe5916cf-204e-48d9-8aa9-00269ee2ad53 9 > Host: localhost:8081 9 > Connection: Keep-Alive 9 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 9 > Accept-Encoding: gzip,deflate 22:50:37.664 response time in milliseconds: 8 9 < 200 9 < Content-Type: application/json 9 < Transfer-Encoding: chunked 9 < Date: Wed, 08 Apr 2026 03:50:37 GMT 9 < Keep-Alive: timeout=60 9 < Connection: keep-alive {"id":"fe5916cf-204e-48d9-8aa9-00269ee2ad53","title":"Avail S2 7c87cb95-f667-44df-bd2b-2331f4f4f167","description":"Test event exhausted tier","date":"2026-12-15T20:00:00","capacity":5,"room":{"id":"10e2c018-89bf-4a37-b8e7-2bc016a4a856","name":"Exhausted Tier Room S2","maxCapacity":50,"created_at":"2026-04-08T03:50:36.820136","updated_at":"2026-04-08T03:50:36.820148"},"availableTiers":[{"id":"2274ff34-294a-4576-9ade-074e47f3c178","tierType":"GENERAL","price":40.00,"quota":0,"validFrom":null,"validUntil":null,"isAvailable":false,"reason":"SOLD_OUT"}],"created_at":"2026-04-08T03:50:36.838885","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
162
Then status 200
0
163
* def exhaustedTier = response.availableTiers[0]
0
164
* print 'Exhausted tier:', exhaustedTier
1
22:50:37.666 [print] Exhausted tier: { "id": "2274ff34-294a-4576-9ade-074e47f3c178", "tierType": "GENERAL", "price": 40.0, "quota": 0, "validFrom": null, "validUntil": null, "isAvailable": false, "reason": "SOLD_OUT" }
165
* match exhaustedTier.quota == 0
0
166
* match exhaustedTier.isAvailable == false
0
167
* print 'Scenario 2 PASS: Tier unavailable after 2 approvals (quota=0, isAvailable=false)'
0
22:50:37.667 [print] Scenario 2 PASS: Tier unavailable after 2 approvals (quota=0, isAvailable=false)
Scenario: [3:170] Scenario 3 - Early Bird tier not yet started (validFrom in future -> isAvailable false)
ms: 72
>>
Background:
7
* def baseUrlEvents = karate.properties['baseUrlEvents'] || 'http://localhost:8081'
0
22:50:37.670 karate.env system property was: null
8
* def baseUrlTicketing = karate.properties['baseUrlTicketing'] || 'http://localhost:8082'
0
9
* def UUID = Java.type('java.util.UUID')
0
10
* def futureDate = '2026-12-15T20:00:00'
0
# Note: Backend validates validFrom/validUntil must be in the FUTURE at creation time.
# A tier with validFrom in the future (not yet started) shows isAvailable=false.
# This scenario verifies the EB tier availability logic without requiring past-dated creation.
176
* def tag = UUID.randomUUID() + ''
0
177
* def eventTitle = 'Avail S3 ' + tag
1
179
Given url baseUrlEvents + '/api/v1/rooms'
0
180
And header X-Role = 'ADMIN'
0
181
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
182
And request { name: 'Early Bird Not-Started Room S3', maxCapacity: 100 }
0
183
When method post
11
22:50:37.674 request: 1 > POST http://localhost:8081/api/v1/rooms 1 > X-Role: ADMIN 1 > X-User-Id: 00000000-0000-0000-0000-000000000001 1 > Content-Type: application/json; charset=UTF-8 1 > Content-Length: 59 1 > Host: localhost:8081 1 > Connection: Keep-Alive 1 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 1 > Accept-Encoding: gzip,deflate {"name":"Early Bird Not-Started Room S3","maxCapacity":100} 22:50:37.685 response time in milliseconds: 10 1 < 201 1 < Content-Type: application/json 1 < Transfer-Encoding: chunked 1 < Date: Wed, 08 Apr 2026 03:50:37 GMT 1 < Keep-Alive: timeout=60 1 < Connection: keep-alive {"id":"83c3543e-106d-4563-97da-4a8b0a4090f9","name":"Early Bird Not-Started Room S3","maxCapacity":100,"created_at":"2026-04-08T03:50:37.677315027","updated_at":"2026-04-08T03:50:37.677331715"}
184
Then status 201
0
185
* def roomId = response.id
0
187
Given url baseUrlEvents + '/api/v1/events'
0
188
And header X-Role = 'ADMIN'
0
189
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
190
And request
0
{ "roomId": "#(roomId)", "title": "#(eventTitle)", "description": "Test event - EB not yet started", "date": "#(futureDate)", "capacity": 100, "enableSeats": false }
201
When method post
18
22:50:37.686 request: 2 > POST http://localhost:8081/api/v1/events 2 > X-Role: ADMIN 2 > X-User-Id: 00000000-0000-0000-0000-000000000001 2 > Content-Type: application/json; charset=UTF-8 2 > Content-Length: 217 2 > Host: localhost:8081 2 > Connection: Keep-Alive 2 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 2 > Accept-Encoding: gzip,deflate {"roomId":"83c3543e-106d-4563-97da-4a8b0a4090f9","title":"Avail S3 7dde01e9-8454-4e82-b035-10ae3f3fcd61","description":"Test event - EB not yet started","date":"2026-12-15T20:00:00","capacity":100,"enableSeats":false} 22:50:37.703 response time in milliseconds: 17 2 < 201 2 < Content-Type: application/json 2 < Transfer-Encoding: chunked 2 < Date: Wed, 08 Apr 2026 03:50:37 GMT 2 < Keep-Alive: timeout=60 2 < Connection: keep-alive {"id":"28f55f3a-fdaf-43e9-b26e-02e4ed2ce8b9","roomId":"83c3543e-106d-4563-97da-4a8b0a4090f9","title":"Avail S3 7dde01e9-8454-4e82-b035-10ae3f3fcd61","description":"Test event - EB not yet started","date":"2026-12-15T20:00:00","capacity":100,"status":"DRAFT","createdAt":"2026-04-08T03:50:37.69486117","updatedAt":"2026-04-08T03:50:37.694877077","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
202
Then status 201
0
203
* def eventId = response.id
0
# Create GENERAL tier first so event can be published (EB tier alone with future validFrom
# causes 422 on publish since no active tiers exist at publish time)
207
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/tiers'
0
208
And header X-Role = 'ADMIN'
0
209
And request
0
[{ "tierType": "GENERAL", "price": 50, "quota": 80 }]
213
When method post
13
22:50:37.705 request: 3 > POST http://localhost:8081/api/v1/events/28f55f3a-fdaf-43e9-b26e-02e4ed2ce8b9/tiers 3 > X-Role: ADMIN 3 > Content-Type: application/json; charset=UTF-8 3 > Content-Length: 46 3 > Host: localhost:8081 3 > Connection: Keep-Alive 3 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 3 > Accept-Encoding: gzip,deflate [{"tierType":"GENERAL","price":50,"quota":80}] 22:50:37.717 response time in milliseconds: 12 3 < 201 3 < Content-Type: application/json 3 < Transfer-Encoding: chunked 3 < Date: Wed, 08 Apr 2026 03:50:37 GMT 3 < Keep-Alive: timeout=60 3 < Connection: keep-alive {"eventId":"28f55f3a-fdaf-43e9-b26e-02e4ed2ce8b9","tiers":[{"id":"e9e10ce3-844c-4852-8263-beddfb37aca4","tierType":"GENERAL","price":50,"quota":80,"validFrom":null,"validUntil":null,"createdAt":"2026-04-08T03:50:37.710536696","updatedAt":"2026-04-08T03:50:37.710550381"}]}
214
Then status 201
0
216
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/publish'
0
217
And header X-Role = 'ADMIN'
0
218
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
219
When method patch
15
22:50:37.719 request: 4 > PATCH http://localhost:8081/api/v1/events/28f55f3a-fdaf-43e9-b26e-02e4ed2ce8b9/publish 4 > X-Role: ADMIN 4 > X-User-Id: 00000000-0000-0000-0000-000000000001 4 > Host: localhost:8081 4 > Connection: Keep-Alive 4 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 4 > Accept-Encoding: gzip,deflate 22:50:37.733 response time in milliseconds: 14 4 < 200 4 < Content-Type: application/json 4 < Transfer-Encoding: chunked 4 < Date: Wed, 08 Apr 2026 03:50:37 GMT 4 < Keep-Alive: timeout=60 4 < Connection: keep-alive {"id":"28f55f3a-fdaf-43e9-b26e-02e4ed2ce8b9","roomId":"83c3543e-106d-4563-97da-4a8b0a4090f9","title":"Avail S3 7dde01e9-8454-4e82-b035-10ae3f3fcd61","description":"Test event - EB not yet started","date":"2026-12-15T20:00:00","capacity":100,"status":"PUBLISHED","createdAt":"2026-04-08T03:50:37.694861","updatedAt":"2026-04-08T03:50:37.725447192","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
220
Then status 200
0
# HU-03: Verify event shows GENERAL tier as available
223
Given url baseUrlEvents + '/api/v1/events/' + eventId
0
224
When method get
9
22:50:37.734 request: 5 > GET http://localhost:8081/api/v1/events/28f55f3a-fdaf-43e9-b26e-02e4ed2ce8b9 5 > Host: localhost:8081 5 > Connection: Keep-Alive 5 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 5 > Accept-Encoding: gzip,deflate 22:50:37.743 response time in milliseconds: 8 5 < 200 5 < Content-Type: application/json 5 < Transfer-Encoding: chunked 5 < Date: Wed, 08 Apr 2026 03:50:37 GMT 5 < Keep-Alive: timeout=60 5 < Connection: keep-alive {"id":"28f55f3a-fdaf-43e9-b26e-02e4ed2ce8b9","title":"Avail S3 7dde01e9-8454-4e82-b035-10ae3f3fcd61","description":"Test event - EB not yet started","date":"2026-12-15T20:00:00","capacity":100,"room":{"id":"83c3543e-106d-4563-97da-4a8b0a4090f9","name":"Early Bird Not-Started Room S3","maxCapacity":100,"created_at":"2026-04-08T03:50:37.677315","updated_at":"2026-04-08T03:50:37.677332"},"availableTiers":[{"id":"e9e10ce3-844c-4852-8263-beddfb37aca4","tierType":"GENERAL","price":50.00,"quota":80,"validFrom":null,"validUntil":null,"isAvailable":true,"reason":null}],"created_at":"2026-04-08T03:50:37.694861","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
225
Then status 200
0
226
* def genTier = response.availableTiers[0]
0
227
* match genTier.tierType == 'GENERAL'
0
228
* match genTier.isAvailable == true
0
229
* print 'Scenario 3 PASS: GENERAL tier is available (isAvailable=true)'
0
22:50:37.744 [print] Scenario 3 PASS: GENERAL tier is available (isAvailable=true)
230
* print 'Note: EB tier with past validUntil cannot be created via API (backend validates future dates).'
0
22:50:37.744 [print] Note: EB tier with past validUntil cannot be created via API (backend validates future dates).
231
* print 'Expiration-based isAvailable=false for EB is validated in expiration-release-flow-with-sql.feature'
0
22:50:37.745 [print] Expiration-based isAvailable=false for EB is validated in expiration-release-flow-with-sql.feature
Scenario: [4:234] Scenario 4 - Event with no active tiers (empty availableTiers)
ms: 40
>>
Background:
7
* def baseUrlEvents = karate.properties['baseUrlEvents'] || 'http://localhost:8081'
0
22:50:37.747 karate.env system property was: null
8
* def baseUrlTicketing = karate.properties['baseUrlTicketing'] || 'http://localhost:8082'
0
9
* def UUID = Java.type('java.util.UUID')
0
10
* def futureDate = '2026-12-15T20:00:00'
0
236
* def tag = UUID.randomUUID() + ''
0
237
* def eventTitle = 'Avail S4 ' + tag
0
239
Given url baseUrlEvents + '/api/v1/rooms'
0
240
And header X-Role = 'ADMIN'
0
241
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
242
And request { name: 'No Tiers Room S4', maxCapacity: 50 }
0
243
When method post
11
22:50:37.750 request: 1 > POST http://localhost:8081/api/v1/rooms 1 > X-Role: ADMIN 1 > X-User-Id: 00000000-0000-0000-0000-000000000001 1 > Content-Type: application/json; charset=UTF-8 1 > Content-Length: 44 1 > Host: localhost:8081 1 > Connection: Keep-Alive 1 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 1 > Accept-Encoding: gzip,deflate {"name":"No Tiers Room S4","maxCapacity":50} 22:50:37.760 response time in milliseconds: 10 1 < 201 1 < Content-Type: application/json 1 < Transfer-Encoding: chunked 1 < Date: Wed, 08 Apr 2026 03:50:37 GMT 1 < Keep-Alive: timeout=60 1 < Connection: keep-alive {"id":"f134d632-df5b-4a3f-9173-fe43d8474764","name":"No Tiers Room S4","maxCapacity":50,"created_at":"2026-04-08T03:50:37.753393997","updated_at":"2026-04-08T03:50:37.753408466"}
244
Then status 201
0
245
* def roomId = response.id
0
247
Given url baseUrlEvents + '/api/v1/events'
0
248
And header X-Role = 'ADMIN'
0
249
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
250
And request
0
{ "roomId": "#(roomId)", "title": "#(eventTitle)", "description": "Test event with no tiers", "date": "#(futureDate)", "capacity": 50, "enableSeats": false }
261
When method post
16
22:50:37.761 request: 2 > POST http://localhost:8081/api/v1/events 2 > X-Role: ADMIN 2 > X-User-Id: 00000000-0000-0000-0000-000000000001 2 > Content-Type: application/json; charset=UTF-8 2 > Content-Length: 209 2 > Host: localhost:8081 2 > Connection: Keep-Alive 2 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 2 > Accept-Encoding: gzip,deflate {"roomId":"f134d632-df5b-4a3f-9173-fe43d8474764","title":"Avail S4 48ecf8af-3062-4a57-b1ba-926fa3e7f5cf","description":"Test event with no tiers","date":"2026-12-15T20:00:00","capacity":50,"enableSeats":false} 22:50:37.776 response time in milliseconds: 15 2 < 201 2 < Content-Type: application/json 2 < Transfer-Encoding: chunked 2 < Date: Wed, 08 Apr 2026 03:50:37 GMT 2 < Keep-Alive: timeout=60 2 < Connection: keep-alive {"id":"6065c5a2-3d92-492f-b0ac-6319c0825a7e","roomId":"f134d632-df5b-4a3f-9173-fe43d8474764","title":"Avail S4 48ecf8af-3062-4a57-b1ba-926fa3e7f5cf","description":"Test event with no tiers","date":"2026-12-15T20:00:00","capacity":50,"status":"DRAFT","createdAt":"2026-04-08T03:50:37.767953796","updatedAt":"2026-04-08T03:50:37.767964186","createdBy":"00000000-0000-0000-0000-000000000001","imageUrl":null,"subtitle":null,"location":null,"director":null,"castMembers":null,"duration":null,"tag":null,"isLimited":false,"isFeatured":false,"enableSeats":false,"author":null}
262
Then status 201
0
263
* def eventId = response.id
0
# HU-03: Backend constraint: Event without tiers CANNOT be published (returns 422 EVENT_HAS_NO_TIERS)
# This validates that the availability system enforces at least 1 tier before publishing
267
Given url baseUrlEvents + '/api/v1/events/' + eventId + '/publish'
0
268
And header X-Role = 'ADMIN'
0
269
And header X-User-Id = '00000000-0000-0000-0000-000000000001'
0
270
When method patch
10
22:50:37.778 request: 3 > PATCH http://localhost:8081/api/v1/events/6065c5a2-3d92-492f-b0ac-6319c0825a7e/publish 3 > X-Role: ADMIN 3 > X-User-Id: 00000000-0000-0000-0000-000000000001 3 > Host: localhost:8081 3 > Connection: Keep-Alive 3 > User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.17) 3 > Accept-Encoding: gzip,deflate 22:50:37.787 response time in milliseconds: 9 3 < 422 3 < Content-Type: application/json 3 < Transfer-Encoding: chunked 3 < Date: Wed, 08 Apr 2026 03:50:37 GMT 3 < Keep-Alive: timeout=60 3 < Connection: keep-alive {"error":"EVENT_HAS_NO_TIERS","message":"Event with id '6065c5a2-3d92-492f-b0ac-6319c0825a7e' cannot be published: no tiers configured"}
271
Then status 422
0
272
* match response.error == 'EVENT_HAS_NO_TIERS'
1
273
* print 'Scenario 4 PASS: Event with no tiers cannot be published (422 EVENT_HAS_NO_TIERS - business constraint enforced)'
1
22:50:37.789 [print] Scenario 4 PASS: Event with no tiers cannot be published (422 EVENT_HAS_NO_TIERS - business constraint enforced)