Regression test cases — Dead beds¶
Audience: QA. Scope: the dead-bed check in booking-wizard room selection, the same check on the Xtreme availability screens, the block-and-waitlist behaviour, the manager override, and the warning and email that carry the value.
Every case cites the microflow and node it derives from, so expected results can be re-derived
rather than trusted. Mechanism detail:
docs/deep-dives/dead-beds.md.
Priority: P1 blocks release, P2 must pass before sign-off, P3 when time allows.
None of these cases have been executed. They state what the system currently does, derived from its decision logic. A pass means unchanged, not correct.
Two of these cases assert defective behaviour — B4 and F2. They are written as the system behaves today so that a fix is visible as a deliberate change rather than a surprise. Both are marked (defect) and cross-referenced to the deep dive.
What to assert on¶
| Thing | Where it lives | After a clean check | After dead beds found |
|---|---|---|---|
| per-room-type counters | Booking.AvailableRoomConfig.DeadBedsCreated{Begin,End}_{Double,Fam,Hm,Twin} |
all 0 |
the count, per type and end |
| the verdict flag | …DeadBedsCreatedWhenNotAllowed |
false |
true |
| override, configuration level | …DeadbedsOverrridden (three rs) |
false |
true only after an override |
| override, line level | Booking.BookingLine.DeadBedsOverridden + BookingLine_Account_DeadOverride |
false / empty |
true / the approving account |
| the evidence | Logging.DeadBed_log |
no new row | one row per room type checked, with the three dates and amounts |
| the Xtreme warning | Availability.UserBookingAvailConfig.DeadBedWarning |
empty | supplier name + phrases |
A setup note that decides half of these cases: the check reads RoomsAvailableAfterWait, so
fixtures must control waitlisted demand, not just raw availability.
A. The gates — when nothing should happen¶
| ID | Case | Preconditions | Steps | Expected | Pri | Source |
|---|---|---|---|---|---|---|
| A1 | Non-Wish accommodation is never checked | AvailableRoomConfig/BookingMethod ≠ Wish |
Select rooms | No counters change, no DeadBed_log row, booking proceeds |
P1 | CheckForDeadBeds_X [2] |
| A2 | Inside eight weeks, no check | SeqStartDate = today + 7 weeks, camp in a dead-bed month |
Select rooms | No check, no block — even with availability that would fail | P1 | CheckForDeadBeds_X [4] |
| A3 | Just outside eight weeks, checked | SeqStartDate = today + 8 weeks + 1 day |
Select rooms | Check runs | P1 | CheckForDeadBeds_X [4] |
| A4 | No dead-bed month configured, no check | Delete the DeadBedMonths rows for the camp |
Select rooms | Returns without arithmetic; counters untouched | P1 | CheckForDeadBeds_X [15],[18],[21] |
| A5 | Month covers the start only | Range covers SeqStartDate, not SeqEndDate |
Select rooms | Beginning checked, end not; only …Begin_* may be non-zero |
P1 | CheckForDeadBeds_X [15],[66] |
| A6 | Month covers the end only | Range covers SeqEndDate, not SeqStartDate |
Select rooms | End checked, beginning not | P1 | CheckForDeadBeds_X [18],[81] |
| A7 | Availability status Available skips the check |
Status Available |
Select rooms | No check | P2 | CheckForDeadBeds_X [3] |
| A8 | Nothing runs unattended | Camp in a dead-bed month, booking left untouched overnight | Wait | No DeadBed_log row appears; no scheduled event exists |
P2 | entry_points — 11 buttons, no scheduled |
B. The arithmetic¶
Fixture shape: three availability rows for one room type, at start−2, start−1 and start, with
controlled RoomsAvailableAfterWait values. R = rooms required.
| ID | Case | Fixture (2before / 1before / start, R) | Expected return | Pri | Source |
|---|---|---|---|---|---|
| B1 | No local peak, no dead beds | 5 / 5 / 5, R=1 | 0, all counters 0, flag false |
P1 | DeadBedCheck_Begin_X [33],[43] |
| B2 | Booking creates the condition | 0 / 2 / 2, R=2 | 2 — the whole post-booking count, not a difference |
P1 | DeadBedCheck_Begin_X [42] |
| B3 | Dead beds already existed — only the increment | 0 / 3 / 2, R=1 | 1 — PostBook (2) − PreBook (1) |
P1 | DeadBedCheck_Begin_X [35],[36],[39] |
| B4 | Increment not positive returns zero (defect-adjacent) | pre-existing dead beds unchanged by the booking | 0 — pre-existing dead beds are never reported |
P2 | DeadBedCheck_Begin_X [37],[40] |
| B5 | End of stay uses the mirrored window | Rows at end, end+1, end+2 | Counters land in …End_*, not …Begin_* |
P1 | DeadBedCheck_End_X [26],[35] |
| B6 | Room types are independent | Twin fixture fails, double fixture clean | Only …Twin non-zero; verdict still true |
P1 | CheckForDeadBeds_X [61],[64-67] |
| B7 | A log row per room type checked | Any check with four types requested | Four Logging.DeadBed_log rows, each with RoomTypeBegin, RoomsRequired and six date/amount pairs |
P2 | CheckForDeadBeds_X [64],[68],[72],[76] |
| B8 | Logs older than a month are deleted | Insert a DeadBed_log dated 40 days ago, run a check |
The old row is gone | P2 | CheckForDeadBeds_X [6],[60] |
C. Duplicate availability — the 99 sentinel¶
| ID | Case | Preconditions | Expected | Pri | Source |
|---|---|---|---|---|---|
| C1 | More than three rows returns 99 | Four availability rows for one room type in the window | Warning "Duplicate availability records could not check for deadbeds at the beginning of your booking …", a Critical log entry, and the count stored as 99 |
P1 | DeadBedCheck_Begin_X [7],[11],[13] |
| C2 | 99 blocks the booking (defect D2) | As C1 | DeadBedsCreatedWhenNotAllowed = true; CanBook refuses |
P1 | deep dive §2, [61] |
| C3 | 99 reaches the email as a value | As C1, then override | Email quotes the rack value of 99 beds. Assert the current behaviour and flag it | P2 | SendDeadBedsEmail [8],[9] |
| C4 | The end check has its own sentinel | Four rows in the end window | Same message wording with "at the end of your booking", returns 99 | P2 | DeadBedCheck_End_X [40],[42] |
D. Blocking and waitlisting¶
| ID | Case | Preconditions | Steps | Expected | Pri | Source |
|---|---|---|---|---|---|---|
| D1 | Dead beds block the line and waitlist it | DeadBedsCreatedWhenNotAllowed = true, no override |
Book provisionally | Information message "…this can only be booked by a Wilderness Manager. It will however be waitlisted in the meantime."; CanBook returns false; line waitlisted |
P1 | CanBook [14],[16],[19] |
| D2 | An override lets it through | DeadbedsOverrridden = true |
Book provisionally | CanBook passes the dead-bed gate |
P1 | CanBook [15],[20] |
| D3 | A re-check clears the line-level approval | Line has DeadBedsOverridden = true, config not overridden |
Re-run the check, then book | BookingLine.DeadBedsOverridden reset to false, BookingLine_Account_DeadOverride emptied |
P1 | CanBook [17] |
| D4 | Every caller of the gate behaves the same | Repeat D1 from IVK_SelectRooms_040625, Sub_BookProvisionally_AllInventory, Dashboard.IVK_WishStatusToProvOverrideWait_CloseForm and DataManagement.WishBookingLine_Update |
Same refusal each time | P2 | call_graph, dst = Booking.CanBook |
|
| D5 | An expiring held line resets the counters | Held line with counters set, let it expire | Maintenance.ProcessExpiredLine zeroes DeadBedsCreatedWhenNotAllowed |
P2 | writers, Maintenance.ProcessExpiredLine |
|
| D6 | The verdict is set by the caller, not the checker | Dead-bed fixture, reached through Booking.CheckRoomSelection |
Flag true, AvailableRoomConfig.Status = Dead_bed_warning, information "Your room selection will be waitlisted" |
P1 | CheckRoomSelection [148],[149],[151] |
|
| D7 | The other caller downgrades availability instead | Same fixture through Booking.UpdateAvailabilityStatusForAccom_X |
Flag true and BookThis recomputed; on a clean result both DeadBedsCreated and the flag are cleared |
P1 | UpdateAvailabilityStatusForAccom_X [100],[101],[119] |
|
| D8 | A dead bed triggers trip suggestion | Status Dead_bed_warning, SearchSimilarCamps = false |
Booking.TripSuggest runs as the current user via CommunityCommons.executeMicroflowAsUser_1 |
P2 | UpdateAvailabilityStatusForAccom_X [111],[114] |
|
| D9 | Rebuilding the room-config string clears the verdict (defect D9) | Flag true, then trigger Booking.SetRoomConfigString |
Flag reset to false with no dead-bed check re-run; a previously refused selection now reads clean |
P1 | writers, 15 sites in SetRoomConfigString |
E. The override path¶
| ID | Case | Steps | Expected | Pri | Source |
|---|---|---|---|---|---|
| E1 | Override sets both levels | Override on Dashboard.BookingLine_Accomm_Edit |
AvailableRoomConfig.DeadbedsOverrridden = true and OverrideBy = current user; BookingLine.DeadBedsOverridden = true with BookingLine_Account_DeadOverride |
P1 | IVK_OverrideDeadbeds [2],[7] |
| E2 | Override is on the booking's event log | As E1 | A Booking.LogEvent entry "Deadbeds overridden by manager on this booking line", object type BookingLine |
P1 | IVK_OverrideDeadbeds [4] |
| E3 | Override sends the email | As E1 | AdvEmail message, subject "Dead beds created booking: … camp : …" |
P1 | IVK_OverrideDeadbeds [6], SendDeadBedsEmail [15] |
| E4 | Popup and inline buttons behave identically | Override from …_Popup |
Same four effects | P2 | entry_points, actionButton8 |
| E4b | The configuration-level override is never withdrawn (defect D8) | Override, then change the room selection and re-check | AvailableRoomConfig.DeadbedsOverrridden stays true — nothing in the live model writes false — while BookingLine.DeadBedsOverridden is cleared |
P1 | IVK_OverrideDeadbeds [2], CanBook [17] |
| E5 | No role check in the logic (defect D5) | Override as a non-manager, if the page permits it | The microflow does not refuse. Record what page security actually does | P1 | CanBook [16], IVK_OverrideDeadbeds |
| E6 | Clearance email reaches the branch managers | Trigger Dashboard.IVK_DeadBed_ClearanceEmail |
Addressed via BranchDepartment_EmployeeResMgr and _EmployeeOpsMgr |
P2 | IVK_DeadBed_ClearanceEmail [5],[6] |
F. The Xtreme availability screens¶
| ID | Case | Preconditions | Expected | Pri | Source |
|---|---|---|---|---|---|
| F1 | Warning string names supplier and room types | Dead beds on an availability search | UserBookingAvailConfig.DeadBedWarning = supplier name + "Deadbeds created at beginning of stay :" shape |
P1 | XAvailCheckDeadBeds_supplier [47], GetDeadBedPerRoomtype [18],[19] |
| F2 | End check follows the start month (defect D1) | Dead-bed month covers SeqEndDate only |
End-of-stay dead beds are not reported on these screens, while the same fixture in the booking wizard does report them | P1 | XAvailCheckDeadBeds_supplier [33],[37],[41] and GetDeadBedPerRoomtype [10] vs CheckForDeadBeds_X [66] |
| F6 | Doubles are counted as twins (defect D10) | Twin availability clean, double availability would strand beds, RoomCountDouble = 2, RoomCountTwin = 0 |
The check runs against twin availability with 2 rooms required, so the double dead beds are missed - and the same fixture in the wizard reports them | P1 | XAvailCheckDeadBeds_supplier [36],[37] |
| F7 | Beginning-of-stay phrasing says "twin" for every type (defect D11) | Family dead beds at the start of a stay | Warning reads "N twin room(s)"; the end-of-stay phrase for the same fixture uses the real caption | P2 | GetDeadBedPerRoomtype [21] vs [23] |
| F3 | Duplicate rows are not guarded here (defect D6) | Four availability rows | No 99, no warning about duplicates — the count is silently wrong | P2 | XAvail_DeadBedCheck_Begin [7-18] |
| F4 | Clearing suggestions clears the warning | Warning present | XAVail_ClearBookingSuggestions empties DeadBedWarning |
P2 | writers, attr DeadBedWarning |
| F5 | No log row from this path | Dead beds via the availability screen | No Logging.DeadBed_log row is written |
P3 | deep dive §1 table |
G. Configuration and messaging¶
| ID | Case | Steps | Expected | Pri | Source |
|---|---|---|---|---|---|
| G1 | A dead-bed month is per supplier | Configure a range for camp A only | Camp B is not checked for the same dates | P1 | CheckForDeadBeds_X [15] XPath |
| G2 | Boundary dates are inclusive | StartDate = SeqStartDate exactly |
Row matches — the XPath is StartDate <= date and date <= EndDate |
P2 | CheckForDeadBeds_X [15] |
| G3 | Config screen commits without events | Edit a range on BookingMasterData.DeadBedConfig |
Saved via Och_DeadBedMonth_Commit, commit without events |
P3 | Och_DeadBedMonth_Commit [2] |
| G4 | Partner bookings get different wording | Booking/API_System = ITRVL, dead beds created |
The logged warning includes the high-occupancy sentence and the bulleted options; non-ITRVL does not | P2 | CheckDeadBedsForWarning [23] |
| G7 | The warning is stored, not only logged | Dead beds created through the wizard | Booking.AvailableRoomConfig.DeadBedWarning holds the sentence |
P2 | CheckDeadBedsForWarning [21] |
| G8 | The stored warning is never cleared (defect D12) | As G7, then re-check with a clean selection | Counters go to 0 and the flag to false, but DeadBedWarning still holds the old sentence - nothing in the live model writes it empty |
P1 | writers, attr DeadBedWarning |
| G5 | The value is rack, times beds | Known GetRackPrice fixture, 2 dead beds |
Price = round(Gs_Ad_Tw × 2); percentage = beds ÷ (roomsBooked + beds) rounded to 2 dp, ×100 |
P2 | CheckDeadBedsForWarning [15],[17],[18] |
| G6 | No rack price yields zero, not a crash | GetRackPrice returns empty |
Price = 0, message still sent |
P2 | CheckDeadBedsForWarning [15] |
H. Not covered here¶
The availability engine that produces RoomsAvailableAfterWait, waitlist mechanics beyond the
fact that a refused line is waitlisted, Pricing.GetRackPrice internals, the
Pricing.TakingUpPotentialDeadBeds discount, and the five documents listed in
deep dive §10 — four excluded
from deployment, plus DataManagement.jaGetWISHDeadBeds, which nothing calls.