@@ -17,19 +17,6 @@ local access_control_event = Notification.event.access_control
1717
1818test .disable_startup_messages ()
1919
20-
21- if table_utils .find_all_entries_by == nil then
22- function table_utils .find_all_entries_by (device , table_name , key , value )
23- local entries = table_utils .get_state (device , table_name ) or {}
24- local matches = {}
25- for _ , entry in ipairs (entries ) do
26- if entry [key ] == value then table.insert (matches , entry ) end
27- end
28- return matches
29- end
30- end
31-
32-
3320local zwave_lock_endpoints = {
3421 {
3522 command_classes = {
5239
5340local function install_state_mocks ()
5441 mock_latest_state = {}
42+ -- tables.lua calls device.log.* unconditionally and get_state guards on
43+ -- supports_capability; stub both for the pre-init seeding phase.
44+ rawset (mock_device , " log" , {
45+ debug = function () end , info = function () end , warn = function () end , error = function () end ,
46+ })
47+ rawset (mock_device , " supports_capability" , function (_ , capability )
48+ local id = type (capability ) == " table" and capability .ID or capability
49+ return id == capabilities .lockUsers .ID or id == capabilities .lockCredentials .ID
50+ end )
5551 mock_device .get_latest_state = function (_ , component_id , capability_id , attribute_name , default_value )
5652 local value = mock_latest_state [mock_state_key (component_id , capability_id , attribute_name )]
5753 if value == nil then
8379-- ── helpers ────────────────────────────────────────────────────────────────
8480
8581local function test_init ()
86- mock_device .persistent_store = mock_device . persistent_store or {}
87- mock_device .transient_store = mock_device . transient_store or {}
82+ mock_device .persistent_store = {}
83+ mock_device .transient_store = {}
8884 install_state_mocks ()
8985 mock_device :set_field (constants .DRIVER_STATE .SLGA_MIGRATED , true , { persist = true })
9086 test .mock_device .add_test_device (mock_device )
@@ -101,6 +97,15 @@ local function expect_set_pin_code(user_identifier, user_code)
10197 )
10298end
10399
100+ local function expect_clear_pin_code (user_identifier )
101+ test .socket .zwave :__expect_send (
102+ UserCode :Set ({
103+ user_identifier = user_identifier ,
104+ user_id_status = UserCode .user_id_status .AVAILABLE ,
105+ }):build_test_tx (mock_device .id )
106+ )
107+ end
108+
104109local function queue_user_code_added (user_identifier )
105110 test .socket .zwave :__queue_receive ({ mock_device .id , Notification :Report ({
106111 notification_type = Notification .notification_type .ACCESS_CONTROL ,
@@ -109,32 +114,27 @@ local function queue_user_code_added(user_identifier)
109114 }) })
110115end
111116
112- local function seed_users (entries )
113- for _ , entry in ipairs (entries ) do
117+ -- Seed through table_utils.add_entry: it calls set_field(..., {persist = true}),
118+ -- which is copied to the real driver device when it is lazily created. Writing
119+ -- only to mock_latest_state / persistent_store never reaches the driver.
120+ local function seed_entries (table_name , capability_attr , key_name , entries )
121+ for i , entry in ipairs (entries ) do
114122 local so_far = {}
115- for _ , e in ipairs (entries ) do
116- table.insert (so_far , e )
117- if e == entry then break end
118- end
119- local event = capabilities .lockUsers .users (so_far , { visibility = { displayed = false } })
120- mock_latest_state [mock_state_key (" main" , event .capability .ID , event .attribute .NAME )] = event .value .value
123+ for j = 1 , i do table.insert (so_far , entries [j ]) end
124+ test .socket .capability :__expect_send (
125+ mock_device :generate_test_message (" main" , capability_attr (so_far , { visibility = { displayed = false } })))
126+ assert (table_utils .add_entry (mock_device , table_name , entry ) == constants .COMMAND_RESULT .SUCCESS ,
127+ " seed " .. table_name .. " : add_entry failed for " .. key_name .. " =" .. tostring (entry [key_name ]))
121128 end
122- mock_device .persistent_store .persistedUsers = entries
123129 test .wait_for_events ()
124130end
125131
132+ local function seed_users (entries )
133+ seed_entries (" users" , capabilities .lockUsers .users , " userIndex" , entries )
134+ end
135+
126136local function seed_credentials (entries )
127- for _ , entry in ipairs (entries ) do
128- local so_far = {}
129- for _ , e in ipairs (entries ) do
130- table.insert (so_far , e )
131- if e == entry then break end
132- end
133- local event = capabilities .lockCredentials .credentials (so_far , { visibility = { displayed = false } })
134- mock_latest_state [mock_state_key (" main" , event .capability .ID , event .attribute .NAME )] = event .value .value
135- end
136- mock_device .persistent_store .persistedCredentials = entries
137- test .wait_for_events ()
137+ seed_entries (" credentials" , capabilities .lockCredentials .credentials , " credentialIndex" , entries )
138138end
139139
140140-- ============================================================================
@@ -437,10 +437,14 @@ test.register_coroutine_test(
437437 { capability = capabilities .lockCredentials .ID , command = " deleteAllCredentials" , args = {} },
438438 })
439439
440- test .timer .__create_and_queue_test_time_advance_timer (4 , " oneshot" )
440+ -- Per-credential clears fire at 2 * (i - 1) s; final cleanup at 2 * #credentials + 4 s.
441+ test .timer .__create_and_queue_test_time_advance_timer (0 , " oneshot" )
442+ test .timer .__create_and_queue_test_time_advance_timer (6 , " oneshot" )
443+ expect_clear_pin_code (1 )
444+ test .mock_time .advance_time (0 )
441445 test .wait_for_events ()
442446
443- test .mock_time .advance_time (4 )
447+ test .mock_time .advance_time (6 )
444448 test .socket .capability :__expect_send (
445449 mock_device :generate_test_message (" main" ,
446450 capabilities .lockCredentials .credentials ({}, { visibility = { displayed = false } }))
@@ -487,8 +491,6 @@ test.register_coroutine_test(
487491test .register_coroutine_test (
488492 " deleteAllCredentials: returns busy when another operation is already in progress" ,
489493 function ()
490- seed_credentials ({ { userIndex = 1 , credentialIndex = 1 , credentialType = " pin" } })
491-
492494 -- First deleteAllCredentials starts the z-wave flow (device is now busy)
493495 test .socket .capability :__queue_receive ({
494496 mock_device .id ,
0 commit comments