From bb2b0c206eb1b4e5ec58e457bee81335183ed85d Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Sat, 29 Nov 2025 01:35:20 +0000 Subject: [PATCH] Implement VM object retrieval and enhance game visuals - Added `vm_object` method in `mission.rb` to fetch VM details from context or return a fallback. - Introduced new images for VM launchers and flag stations in the assets directory. - Updated `game.js` to preload new VM launcher and flag station images. - Refactored `vm-launcher-minigame.js` to streamline VM handling and improve UI messaging. - Adjusted scenario JSON to utilize the new `vm_object` method for VM data retrieval. --- app/models/break_escape/mission.rb | 11 + .../assets/objects/flag-station.png | Bin 0 -> 427 bytes .../assets/objects/vm-launcher-desktop.png | Bin 0 -> 672 bytes .../assets/objects/vm-launcher-kali.png | Bin 0 -> 708 bytes .../assets/objects/vm-launcher.png | Bin 0 -> 585 bytes public/break_escape/js/core/game.js | 6 + .../vm-launcher/vm-launcher-minigame.js | 131 +- .../break_escape/js/systems/interactions.js | 8 +- scenarios/secgen_vm_lab/scenario.json.erb | 4 +- test/dummy/log/test.log | 1071 +++++++++++++++++ test/dummy/storage/test.sqlite3 | Bin 94208 -> 94208 bytes 11 files changed, 1136 insertions(+), 95 deletions(-) create mode 100644 public/break_escape/assets/objects/flag-station.png create mode 100644 public/break_escape/assets/objects/vm-launcher-desktop.png create mode 100644 public/break_escape/assets/objects/vm-launcher-kali.png create mode 100644 public/break_escape/assets/objects/vm-launcher.png diff --git a/app/models/break_escape/mission.rb b/app/models/break_escape/mission.rb index 55502c1..e3ce696 100644 --- a/app/models/break_escape/mission.rb +++ b/app/models/break_escape/mission.rb @@ -114,6 +114,17 @@ module BreakEscape attr_reader :random_password, :random_pin, :random_code, :vm_context + # Get a VM from the context by title, or return a fallback VM object + # Usage in ERB: + # "vm": <%= vm_object('kali', {"id":1,"title":"kali","ip":"192.168.1.10","enable_console":true}) %> + def vm_object(title, fallback = {}) + if vm_context && vm_context['hacktivity_mode'] && vm_context['vms'] + vm = vm_context['vms'].find { |v| v['title'] == title } + return vm.to_json if vm + end + fallback.to_json + end + def get_binding binding end diff --git a/public/break_escape/assets/objects/flag-station.png b/public/break_escape/assets/objects/flag-station.png new file mode 100644 index 0000000000000000000000000000000000000000..282163c5f24bd38741d2e76906978b1eea7d644b GIT binary patch literal 427 zcmV;c0aX5pP)Px$Wl2OqR5*>TRXs|?Kp1`5B)hO~6+#LbSc^TtfUq~P^dMGVK(??Dw2B~DW*aS5 zu(9+8fxsRhMFNt-3n*rWvCxUT*)PBAgD^9XnR(w&cw>M7^SGk;ws?DA8;zTo$JOV@ zml8tu{-{7LO3boN9339_$|lJok{{F^iqo){SZATxblzD^uN)D~^}S1DAkc~zDom#}QJ zD0fxaNl&6I^j(u}| zrG$`bvA9q|$YSmL{uZxC&FfJItMA(ke!x7gk}Se%^^D=@=NEMx7XUCEjq&*K1ONz@ z0UXDL$R!-dMX(HTFqr^AF=~-G4Pn_Pk}UeG6!Z9AZx8hjmG5L8SH^$!hU(EK_YKE3 VKc}|Ao96%k002ovPDHLkV1je5!4d!f literal 0 HcmV?d00001 diff --git a/public/break_escape/assets/objects/vm-launcher-desktop.png b/public/break_escape/assets/objects/vm-launcher-desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..2d3c6d2480e19ef37fdc78b1710d95f71b7a59e4 GIT binary patch literal 672 zcmV;R0$=@!P)Px%T1iAfR7i=XR!wLVK^T3z$!?%t#Y3Wk*n%avm{W7>!BBFOKrna_#9l075dsoC zc_rP>gQ7Lp)XlanWNFv*&Xha}_v%xrekcbUwaFW;N@ z<=ZbSzyh+dN~|0JbW0yuG!s4q;Lki2SZ5}(bN4b?P+O2h$#rtQuhV$FuLA(yT|bKR z>Ms-;uWX`zR+8g$Cv99jtJ%1GG6p3Qru*_<1>d*pju&JKvV@u|%cjKiEUTfpvP`)E z`jZRBhslf>B~~I~G$UaIZ$F@%8;Hh@d~VJ$_{--C;#rNB(TmUsT!%^|3=GRjOZd`U zzDXdmNNXb)IipxSt0A9^c@pG0Ebmniw20@EF;lmC72^t8OC}u&;!|;RVv(_eFmz$} z#X8E$jHjf&XcSQ2xED12UdjwD<6+%#1#^#HoA!@Grv@Lk>ySi=jxaWueaIJl|IF;7 zS1LIs@I|9QyKUon^Vl|A=R*nRzXgV4Yw2$fsys!9HqR|nn;scDnn|i3^6%$a^ePpEP-@&2(pBw;#a(F;y&&4 zt?5hTcdJFuRCx;i#U1B&5HFBK$@IYA`O^mc|M!K1HQ^tiy#d0Es}~~x0000t1fQ< literal 0 HcmV?d00001 diff --git a/public/break_escape/assets/objects/vm-launcher-kali.png b/public/break_escape/assets/objects/vm-launcher-kali.png new file mode 100644 index 0000000000000000000000000000000000000000..44b9ede2e14ee113e00c5b1cccce6c1d7b5e4132 GIT binary patch literal 708 zcmV;#0z3VQP)Px%en~_@R7i=fmQP3&Q5?rVGrO}3)*&c5C><6JQc3cn)5$~PHTIH45JVnIA_!Ju z!Ar5w!9x&hNOh1dftNA@Ax#n_YuIQBG+}mG$ktN_X%D%syRXCMIDg*EuGshTc)$01 zzwht+oA-Y66kHHw$Fz&G#u@uG@ zj2wIEO9l|7c5uQ^rzcQ%%a*#M)e?Q?I7TdG1-26zu@rrHlWa&BIoA&?pqpb-h4vA^ z*aBkpiWsq!v@%U8+*4_XZjNEZQjU_^lWB&`m$0X|n;xdYbvTSIJY?{n6v_@pEgba? zbSQ;xGVMq!UzX?5sh4$+SO`GC`Mmd=ABfOSRwv&tqfE(K>rJ{gr>uEM*CG8@8dq&h z))-xzQ)Jp7H03K*IQ!&{?*>iPtQKa+@s+C-z)yoe;fLpgj(Ihk4Ga*{b=cmPCMJWY zxem0&rGE?lwXMxDRS-l)+P% zd@B)zhFO~Ngm2(mnI8ZwY|J#R)>0^5KNe;@A;jFI$PFj0vExoB0G{#QStdG9GXHb{ z`#!gFGoBE+;iSk7Cxt^{kdkJgL^Q-s1tp>}y1d4_;;gdwT**)WMC?=;G4geVjg(03 zuCe{@8I*|gDr6shhjNwciy2lwuGbSY;|bw*JPd9uuUjX5vEz#PT`E~?=|~IV5hM5w qau8^$=D6_p|7=5ef4;Oaqx=O+EE#;Zme8I60000Px%14%?dR7i=nmOY3QK@`V-yUA?eY{kM;8?W#XMXO79g~zqBjlo6`ukjE;2uMmR z3kyMV7HVOAjmGBSzAz9Jj}wD%dXNOcGo6(wOtNOj;>?=eyq(+J$G@4KH*enm{paKD zSVW+g7If4G(5-%u%py``NEe=4(pbpYd3Zz57F#G=B@XWSUf}Qf9sp~1j&r5>lXCOb z5NTQpa%$>~82sYp^TGG$Pg|nx+xvzwK|7(4L}UONd}AC@VH}Y}*6$}ph|sw-1*{s$ zBvtz+9E52J_e0c&xQ9nYhDo96U>pRZ!YG+KcJffjVhM>X;m69#NI_HC>}Z6CwOD4P`_8L8Uv)VS!lP##3T$A*XeOr{9Ev^Y|a1aQFO+F zq8+DJD%?m4;~W8I$FFJt+wV|rmSX)(NL;)J;oBKzPG5^%2^03rvgYPv1K-~K4#4Wp zVq&#{LjC%QuDN-wmlkwAR|wjPyORJ6wf8UZXz~Or&!!oi7gb(!^SYiZ=z6Z8Lkdkw zlE88ly6a&%iuuYHmYXH3|6FOj{DJOz%xyGw74D@(v`5;r_s(HC;j2)6{1rMqZmw^# z^=^ANv6`FLQOASeR%JUl>FX2M^{-Yd7%Mtsq~|uwZ;(--Y!$lj4}P~H{l8z{S+xEF X724x?V=!EA00000NkvXXu0mjfl))40 literal 0 HcmV?d00001 diff --git a/public/break_escape/js/core/game.js b/public/break_escape/js/core/game.js index 4a27a2e..53d7357 100644 --- a/public/break_escape/js/core/game.js +++ b/public/break_escape/js/core/game.js @@ -364,6 +364,12 @@ export function preload() { this.load.image('pc11', 'objects/pc11.png'); this.load.image('pc12', 'objects/pc12.png'); + // VMs Launchers and Flag Stations + this.load.image('vm-launcher', 'objects/vm-launcher.png'); + this.load.image('vm-launcher-kali', 'objects/vm-launcher-kali.png'); + this.load.image('vm-launcher-desktop', 'objects/vm-launcher-desktop.png'); + this.load.image('flag-station', 'objects/flag-station.png'); + // Laptops this.load.image('laptop7', 'objects/laptop7.png'); diff --git a/public/break_escape/js/minigames/vm-launcher/vm-launcher-minigame.js b/public/break_escape/js/minigames/vm-launcher/vm-launcher-minigame.js index c083d16..526aa5e 100644 --- a/public/break_escape/js/minigames/vm-launcher/vm-launcher-minigame.js +++ b/public/break_escape/js/minigames/vm-launcher/vm-launcher-minigame.js @@ -12,9 +12,8 @@ import { MinigameScene } from '../framework/base-minigame.js'; export class VmLauncherMinigame extends MinigameScene { constructor(container, params) { super(container, params); - this.vms = params.vms || []; + this.vm = params.vm || null; this.hacktivityMode = params.hacktivityMode || false; - this.selectedVm = null; this.isLaunching = false; } @@ -243,22 +242,22 @@ export class VmLauncherMinigame extends MinigameScene { const launcher = document.createElement('div'); launcher.className = 'vm-launcher'; - if (this.vms.length === 0) { - launcher.innerHTML = this.buildNoVmsMessage(); + if (!this.vm) { + launcher.innerHTML = this.buildNoVmMessage(); } else { - launcher.innerHTML = this.buildVmList(); + launcher.innerHTML = this.buildVmDisplay(); } this.gameContainer.appendChild(launcher); this.attachEventHandlers(); } - buildNoVmsMessage() { + buildNoVmMessage() { if (this.hacktivityMode) { return `
-

No VMs Available

-

No virtual machines are configured for this mission.

+

No VM Available

+

No virtual machine is configured for this terminal.

Please provision VMs through Hacktivity first.

`; @@ -266,85 +265,59 @@ export class VmLauncherMinigame extends MinigameScene { return `

VM Terminal

-

You've discovered a computer terminal in the game. To interact with it, you need to launch the virtual machines on your local system.

- ${this.buildStandaloneInstructions()} +

You've discovered a computer terminal in the game. To interact with it, you need to launch the virtual machine on your local system.

+
`; } } - buildVmList() { - const description = this.hacktivityMode - ? 'Select a VM to open its console. A SPICE viewer file will be downloaded.' - : 'These VMs are available for this mission.'; - - let html = ` -

${description}

-
- `; - - for (const vm of this.vms) { - const hasConsole = vm.enable_console !== false; - const statusClass = hasConsole ? 'console' : 'online'; - const statusText = hasConsole ? 'Console' : 'Active'; - + buildVmDisplay() { + const hasConsole = this.vm.enable_console !== false; + const statusClass = hasConsole ? 'console' : 'online'; + const statusText = hasConsole ? 'Console' : 'Active'; + let html = `

You've discovered a computer terminal in the game. To interact with it, ` + + if (this.hacktivityMode) { html += ` -

-
- ${this.escapeHtml(vm.title)} - ${statusText} -
-
- ${vm.ip ? `IP: ${this.escapeHtml(vm.ip)}` : ''} -
-
+ click the console button, and follow the instructions.

+ `; + } else { + html += ` + you need to launch the virtual machine on your local system.

`; } - html += '
'; + html += ` + +
+
+ ${this.escapeHtml(this.vm.title)} + ${statusText} +
+
+ ${this.vm.ip ? `IP: ${this.escapeHtml(this.vm.ip)}` : ''} +
+
+ `; if (this.hacktivityMode) { html += `
-
`; - } else { - html += this.buildStandaloneInstructions(); } return html; } - buildStandaloneInstructions() { - return ` -
-

Load These VMs in VirtualBox:

-
-
kali
-
desktop
-
-
    -
  1. Open VirtualBox on your local machine
  2. -
  3. Import the kali and desktop VMs (.ova files)
  4. -
  5. Start both VMs and wait for them to boot
  6. -
  7. Note their IP addresses
  8. -
  9. Return to this game to complete the mission
  10. -
-
- `; - } + attachEventHandlers() { - // VM card selection - const vmCards = this.gameContainer.querySelectorAll('.vm-card'); - vmCards.forEach(card => { - this.addEventListener(card, 'click', () => this.selectVm(card)); - }); - // Launch button (Hacktivity mode only) const launchBtn = this.gameContainer.querySelector('#launch-console-btn'); if (launchBtn) { @@ -352,33 +325,13 @@ export class VmLauncherMinigame extends MinigameScene { } } - selectVm(card) { - if (this.isLaunching) return; - - // Clear previous selection - this.gameContainer.querySelectorAll('.vm-card').forEach(c => { - c.classList.remove('selected'); - }); - - // Select new card - card.classList.add('selected'); - this.selectedVm = this.vms.find(vm => vm.id == card.dataset.vmId); - - // Update launch button - const launchBtn = this.gameContainer.querySelector('#launch-console-btn'); - if (launchBtn && this.selectedVm) { - launchBtn.disabled = false; - launchBtn.textContent = `Open Console: ${this.selectedVm.title}`; - } - } - async launchConsole() { - if (!this.selectedVm || this.isLaunching) return; + if (!this.vm || this.isLaunching) return; this.isLaunching = true; const launchBtn = this.gameContainer.querySelector('#launch-console-btn'); const statusEl = this.gameContainer.querySelector('#launch-status'); - const vmCard = this.gameContainer.querySelector(`[data-vm-id="${this.selectedVm.id}"]`); + const vmCard = this.gameContainer.querySelector('.vm-card'); launchBtn.disabled = true; launchBtn.classList.add('launching'); @@ -391,8 +344,8 @@ export class VmLauncherMinigame extends MinigameScene { if (window.hacktivityCable) { // Use ActionCable integration const result = await window.hacktivityCable.requestConsoleFile( - this.selectedVm.id, - this.selectedVm.event_id + this.vm.id, + this.vm.event_id ); if (result.success) { @@ -416,7 +369,7 @@ export class VmLauncherMinigame extends MinigameScene { this.isLaunching = false; launchBtn.disabled = false; launchBtn.classList.remove('launching'); - launchBtn.textContent = `Open Console: ${this.selectedVm.title}`; + launchBtn.textContent = `Open Console: ${this.vm.title}`; vmCard.classList.remove('launching'); } } @@ -429,7 +382,7 @@ export class VmLauncherMinigame extends MinigameScene { start() { super.start(); - console.log('[VmLauncher] Started with', this.vms.length, 'VMs'); + console.log('[VmLauncher] Started with VM:', this.vm?.title || 'None'); } } diff --git a/public/break_escape/js/systems/interactions.js b/public/break_escape/js/systems/interactions.js index 2ba78fc..467b855 100644 --- a/public/break_escape/js/systems/interactions.js +++ b/public/break_escape/js/systems/interactions.js @@ -633,13 +633,13 @@ export function handleObjectInteraction(sprite) { if (sprite.scenarioData.type === "vm-launcher" || sprite.scenarioData.type === "vm_launcher") { console.log('VM Launcher interaction:', sprite.scenarioData); if (window.MinigameFramework) { - // Get VM data from scenario or gameConfig - const vms = sprite.scenarioData.vms || window.gameConfig?.vms || []; - const hacktivityMode = sprite.scenarioData.hacktivityMode || window.gameConfig?.hacktivityMode || false; + // Get VM data from scenario + const vm = sprite.scenarioData.vm || null; + const hacktivityMode = sprite.scenarioData.hacktivityMode || window.breakEscapeConfig?.hacktivityMode || false; window.MinigameFramework.startMinigame('vm-launcher', null, { title: sprite.scenarioData.name || 'VM Console Access', - vms: vms, + vm: vm, hacktivityMode: hacktivityMode, stationId: sprite.scenarioData.id || sprite.objectId }); diff --git a/scenarios/secgen_vm_lab/scenario.json.erb b/scenarios/secgen_vm_lab/scenario.json.erb index d3f1614..524a008 100644 --- a/scenarios/secgen_vm_lab/scenario.json.erb +++ b/scenarios/secgen_vm_lab/scenario.json.erb @@ -44,7 +44,7 @@ "takeable": false, "observations": "A terminal interface for accessing the Kali Linux VM. Ready to launch.", "hacktivityMode": <%= vm_context && vm_context['hacktivity_mode'] ? 'true' : 'false' %>, - "vms": <%= vm_context && vm_context['vms'] ? vm_context['vms'].to_json : '[{"id":1,"title":"kali","ip":"192.168.1.10","enable_console":true}]' %> + "vm": <%= vm_object('kali', {"id":1,"title":"kali","ip":"192.168.1.10","enable_console":true}) %> }, { "type": "vm-launcher", @@ -53,7 +53,7 @@ "takeable": false, "observations": "A terminal interface for accessing the Desktop Linux VM. Ready to launch.", "hacktivityMode": <%= vm_context && vm_context['hacktivity_mode'] ? 'true' : 'false' %>, - "vms": <%= vm_context && vm_context['vms'] ? vm_context['vms'].to_json : '[{"id":2,"title":"desktop","ip":"192.168.1.20","enable_console":true}]' %> + "vm": <%= vm_object('desktop', {"id":2,"title":"desktop","ip":"192.168.1.20","enable_console":true}) %> }, { "type": "notes", diff --git a/test/dummy/log/test.log b/test/dummy/log/test.log index b88e53f..a38670b 100644 --- a/test/dummy/log/test.log +++ b/test/dummy/log/test.log @@ -53353,3 +53353,1074 @@ Processing by BreakEscape::MissionsController#index as HTML Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.4ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.4ms | ActiveRecord: 0.2ms (5 queries, 1 cached) | GC: 0.1ms) TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] + ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) DELETE FROM "break_escape_demo_users"; +DELETE FROM "break_escape_missions"; +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-28 23:58:19', '2025-11-28 23:58:19'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 23:58:19', '2025-11-28 23:58:19'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-28 23:58:19', '2025-11-28 23:58:19'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-28 23:58:19', '2025-11-28 23:58:19'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 23:58:19', '2025-11-28 23:58:19', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (0.9ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.2ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.030957"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.030772"], ["updated_at", "2025-11-28 23:58:19.030772"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 1.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) +Completed 200 OK in 8ms (Views: 2.9ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.047591"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.047518"], ["updated_at", "2025-11-28 23:58:19.047518"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.051825"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.051784"], ["updated_at", "2025-11-28 23:58:19.051784"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.054172"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.054130"], ["updated_at", "2025-11-28 23:58:19.054130"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.056788"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.056750"], ["updated_at", "2025-11-28 23:58:19.056750"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office, attempt=1234, method=pin +[BreakEscape] Room data: locked=true, lockType=pin, requires=1234 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 23:58:19.058450"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.059813"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.059775"], ["updated_at", "2025-11-28 23:58:19.059775"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.1ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_game_setup_has_correct_scenario_data +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.062856"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.062814"], ["updated_at", "2025-11-28 23:58:19.062814"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.064036"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.063997"], ["updated_at", "2025-11-28 23:58:19.063997"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.066343"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.066303"], ["updated_at", "2025-11-28 23:58:19.066303"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 23:58:19.066844"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}, "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"note", "name"=>"Test Note", "id"=>"note_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=note, id=note_1, name=Test Note +[BreakEscape] Item collection valid: note +[BreakEscape] Adding item to inventory: note / Test Note + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"note\",\"name\":\"Test Note\",\"id\":\"note_1\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 23:58:19.068472"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Item added successfully. Current inventory: [{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.069749"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.069711"], ["updated_at", "2025-11-28 23:58:19.069711"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.071979"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.071935"], ["updated_at", "2025-11-28 23:58:19.071935"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.074601"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.074560"], ["updated_at", "2025-11-28 23:58:19.074560"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 0ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.2ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.081920"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.078539"], ["updated_at", "2025-11-28 23:58:19.078539"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 5ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 2.7ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 6.2ms | GC: 0.3ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.2ms | GC: 0.3ms) +Completed 200 OK in 7ms (Views: 6.1ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 0.3ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.096018"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.095324"], ["updated_at", "2025-11-28 23:58:19.095324"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 1.0ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.1ms | GC: 0.1ms) +Completed 200 OK in 2ms (Views: 1.1ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.8ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] + ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) DELETE FROM "break_escape_demo_users"; +DELETE FROM "break_escape_missions"; +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-29 00:05:46', '2025-11-29 00:05:46'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 00:05:46', '2025-11-29 00:05:46'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-29 00:05:46', '2025-11-29 00:05:46'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-29 00:05:46', '2025-11-29 00:05:46'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 00:05:46', '2025-11-29 00:05:46', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (0.7ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.2ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.078939"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.078851"], ["updated_at", "2025-11-29 00:05:46.078851"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:05:46.079681"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}, "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"note", "name"=>"Test Note", "id"=>"note_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=note, id=note_1, name=Test Note +[BreakEscape] Item collection valid: note +[BreakEscape] Adding item to inventory: note / Test Note + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"note\",\"name\":\"Test Note\",\"id\":\"note_1\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:05:46.091416"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Item added successfully. Current inventory: [{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}] +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.093673"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.093609"], ["updated_at", "2025-11-29 00:05:46.093609"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.096315"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.096268"], ["updated_at", "2025-11-29 00:05:46.096268"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.098650"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.098608"], ["updated_at", "2025-11-29 00:05:46.098608"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.100833"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.100794"], ["updated_at", "2025-11-29 00:05:46.100794"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 1.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) +Completed 200 OK in 5ms (Views: 2.9ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_game_setup_has_correct_scenario_data +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.107886"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.107849"], ["updated_at", "2025-11-29 00:05:46.107849"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.108950"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.108914"], ["updated_at", "2025-11-29 00:05:46.108914"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office, attempt=1234, method=pin +[BreakEscape] Room data: locked=true, lockType=pin, requires=1234 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:05:46.110537"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.111807"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.111769"], ["updated_at", "2025-11-29 00:05:46.111769"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.114443"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.114385"], ["updated_at", "2025-11-29 00:05:46.114385"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.117189"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.117146"], ["updated_at", "2025-11-29 00:05:46.117146"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.119374"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.119334"], ["updated_at", "2025-11-29 00:05:46.119334"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.121588"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.121549"], ["updated_at", "2025-11-29 00:05:46.121549"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.2ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.129973"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.129238"], ["updated_at", "2025-11-29 00:05:46.129238"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.2ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 6ms (ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 2.7ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 6.1ms | GC: 0.2ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.3ms | GC: 0.4ms) +Completed 200 OK in 7ms (Views: 6.1ms | ActiveRecord: 0.4ms (5 queries, 1 cached) | GC: 0.4ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.8ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.8ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.143510"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.142826"], ["updated_at", "2025-11-29 00:05:46.142826"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 00:05:46 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.9ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.1ms) +Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.1ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] + ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) DELETE FROM "break_escape_demo_users"; +DELETE FROM "break_escape_missions"; +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-29 00:39:42', '2025-11-29 00:39:42'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 00:39:42', '2025-11-29 00:39:42'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-29 00:39:42', '2025-11-29 00:39:42'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-29 00:39:42', '2025-11-29 00:39:42'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 00:39:42', '2025-11-29 00:39:42', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (0.8ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.2ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.002409"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.002321"], ["updated_at", "2025-11-29 00:39:43.002321"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.015875"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.015819"], ["updated_at", "2025-11-29 00:39:43.015819"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.019223"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.019179"], ["updated_at", "2025-11-29 00:39:43.019179"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office, attempt=1234, method=pin +[BreakEscape] Room data: locked=true, lockType=pin, requires=1234 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:39:43.020984"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.022384"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.022347"], ["updated_at", "2025-11-29 00:39:43.022347"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.024516"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.024479"], ["updated_at", "2025-11-29 00:39:43.024479"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 1.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) +Completed 200 OK in 5ms (Views: 3.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.032069"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.032019"], ["updated_at", "2025-11-29 00:39:43.032019"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.1ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.035027"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.034967"], ["updated_at", "2025-11-29 00:39:43.034967"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.037309"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.037269"], ["updated_at", "2025-11-29 00:39:43.037269"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:39:43.037849"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}, "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"note", "name"=>"Test Note", "id"=>"note_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=note, id=note_1, name=Test Note +[BreakEscape] Item collection valid: note +[BreakEscape] Adding item to inventory: note / Test Note + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"note\",\"name\":\"Test Note\",\"id\":\"note_1\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:39:43.039435"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Item added successfully. Current inventory: [{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.040707"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.040668"], ["updated_at", "2025-11-29 00:39:43.040668"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.042814"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.042775"], ["updated_at", "2025-11-29 00:39:43.042775"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.1ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.045920"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.045873"], ["updated_at", "2025-11-29 00:39:43.045873"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_game_setup_has_correct_scenario_data +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.048198"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.048155"], ["updated_at", "2025-11-29 00:39:43.048155"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.2ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.051893"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.051180"], ["updated_at", "2025-11-29 00:39:43.051180"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 5ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 2.5ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.2ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.058193"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.057394"], ["updated_at", "2025-11-29 00:39:43.057394"], ["objectives_completed", 0], ["tasks_completed", 0]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 3ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.3ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 6.1ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.2ms | GC: 0.2ms) +Completed 200 OK in 7ms (Views: 6.1ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.8ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.8ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.0ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction diff --git a/test/dummy/storage/test.sqlite3 b/test/dummy/storage/test.sqlite3 index 3b32bcf728658fa5f853a9bd174b4f85ee79abb3..2999b9be4017126726d20a37e8f61b64ee4827e4 100644 GIT binary patch delta 208 zcmZp8z}oPDb;Hv9XiEhH11n=oD-$Cl10z#iLqlC7gplR&)jv7d801BbjZ0FCOX5q5 nQ;R?ti&88?n+l%f$s!EHqGB@R{W1b7rrh_yuVVAh`|J|{#2q#_ delta 208 zcmZp8z}oPDb;Hv9XbS~Hb1NfLD-&}g10z#iLqlC7gplR&)jv7d801BbjZ0FCOX5q5 nQ;R?ti&88?n+l%f$s!EHqGB@R{W1b7rrh_yuVVAh`|J|{-D);{