From 3484135f427ab1c2dbd860defe840a92b59b2256 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Tue, 27 Oct 2026 10:33:54 -0500 Subject: [PATCH 1/2] zwave test: properly seed credentials test file data --- .../test/test_lock_credentials_commands.lua | 61 +++++++++++-------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/drivers/SmartThings/zwave-lock/src/test/test_lock_credentials_commands.lua b/drivers/SmartThings/zwave-lock/src/test/test_lock_credentials_commands.lua index 5daee2191a..36a5616a35 100644 --- a/drivers/SmartThings/zwave-lock/src/test/test_lock_credentials_commands.lua +++ b/drivers/SmartThings/zwave-lock/src/test/test_lock_credentials_commands.lua @@ -52,6 +52,12 @@ end local function install_state_mocks() mock_latest_state = {} + -- tables.lua calls device.log.* unconditionally and get_state guards on + -- supports_capability; stub both for the pre-init seeding phase. + rawset(mock_device, "log", { + debug = function() end, info = function() end, warn = function() end, error = function() end, + }) + rawset(mock_device, "supports_capability", function() return true end) mock_device.get_latest_state = function(_, component_id, capability_id, attribute_name, default_value) local value = mock_latest_state[mock_state_key(component_id, capability_id, attribute_name)] if value == nil then @@ -83,8 +89,8 @@ end -- ── helpers ──────────────────────────────────────────────────────────────── local function test_init() - mock_device.persistent_store = mock_device.persistent_store or {} - mock_device.transient_store = mock_device.transient_store or {} + mock_device.persistent_store = {} + mock_device.transient_store = {} install_state_mocks() mock_device:set_field(constants.DRIVER_STATE.SLGA_MIGRATED, true, { persist = true }) test.mock_device.add_test_device(mock_device) @@ -101,6 +107,15 @@ local function expect_set_pin_code(user_identifier, user_code) ) end +local function expect_clear_pin_code(user_identifier) + test.socket.zwave:__expect_send( + UserCode:Set({ + user_identifier = user_identifier, + user_id_status = UserCode.user_id_status.AVAILABLE, + }):build_test_tx(mock_device.id) + ) +end + local function queue_user_code_added(user_identifier) test.socket.zwave:__queue_receive({ mock_device.id, Notification:Report({ notification_type = Notification.notification_type.ACCESS_CONTROL, @@ -109,32 +124,27 @@ local function queue_user_code_added(user_identifier) }) }) end -local function seed_users(entries) - for _, entry in ipairs(entries) do +-- Seed through table_utils.add_entry: it calls set_field(..., {persist = true}), +-- which is copied to the real driver device when it is lazily created. Writing +-- only to mock_latest_state / persistent_store never reaches the driver. +local function seed_entries(table_name, capability_attr, key_name, entries) + for i, entry in ipairs(entries) do local so_far = {} - for _, e in ipairs(entries) do - table.insert(so_far, e) - if e == entry then break end - end - local event = capabilities.lockUsers.users(so_far, { visibility = { displayed = false } }) - mock_latest_state[mock_state_key("main", event.capability.ID, event.attribute.NAME)] = event.value.value + for j = 1, i do table.insert(so_far, entries[j]) end + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capability_attr(so_far, { visibility = { displayed = false } }))) + assert(table_utils.add_entry(mock_device, table_name, entry) == constants.COMMAND_RESULT.SUCCESS, + "seed " .. table_name .. ": add_entry failed for " .. key_name .. "=" .. tostring(entry[key_name])) end - mock_device.persistent_store.persistedUsers = entries test.wait_for_events() end +local function seed_users(entries) + seed_entries("users", capabilities.lockUsers.users, "userIndex", entries) +end + local function seed_credentials(entries) - for _, entry in ipairs(entries) do - local so_far = {} - for _, e in ipairs(entries) do - table.insert(so_far, e) - if e == entry then break end - end - local event = capabilities.lockCredentials.credentials(so_far, { visibility = { displayed = false } }) - mock_latest_state[mock_state_key("main", event.capability.ID, event.attribute.NAME)] = event.value.value - end - mock_device.persistent_store.persistedCredentials = entries - test.wait_for_events() + seed_entries("credentials", capabilities.lockCredentials.credentials, "credentialIndex", entries) end -- ============================================================================ @@ -437,10 +447,13 @@ test.register_coroutine_test( { capability = capabilities.lockCredentials.ID, command = "deleteAllCredentials", args = {} }, }) - test.timer.__create_and_queue_test_time_advance_timer(4, "oneshot") + test.timer.__create_and_queue_test_time_advance_timer(0, "oneshot") + test.timer.__create_and_queue_test_time_advance_timer(6, "oneshot") + test.mock_time.advance_time(0) + expect_clear_pin_code(1) test.wait_for_events() - test.mock_time.advance_time(4) + test.mock_time.advance_time(6) test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockCredentials.credentials({}, { visibility = { displayed = false } })) From 02b07c5dc90c1054610ba6e1ddb8ae3d71bde1cc Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Wed, 28 Oct 2026 12:30:09 -0500 Subject: [PATCH 2/2] cleanup in response to comments --- .../test/test_lock_credentials_commands.lua | 23 +++++-------------- .../src/test/test_lock_pre_configured.lua | 18 ++++----------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/SmartThings/zwave-lock/src/test/test_lock_credentials_commands.lua b/drivers/SmartThings/zwave-lock/src/test/test_lock_credentials_commands.lua index 36a5616a35..864162b29d 100644 --- a/drivers/SmartThings/zwave-lock/src/test/test_lock_credentials_commands.lua +++ b/drivers/SmartThings/zwave-lock/src/test/test_lock_credentials_commands.lua @@ -17,19 +17,6 @@ local access_control_event = Notification.event.access_control test.disable_startup_messages() - -if table_utils.find_all_entries_by == nil then - function table_utils.find_all_entries_by(device, table_name, key, value) - local entries = table_utils.get_state(device, table_name) or {} - local matches = {} - for _, entry in ipairs(entries) do - if entry[key] == value then table.insert(matches, entry) end - end - return matches - end -end - - local zwave_lock_endpoints = { { command_classes = { @@ -57,7 +44,10 @@ local function install_state_mocks() rawset(mock_device, "log", { debug = function() end, info = function() end, warn = function() end, error = function() end, }) - rawset(mock_device, "supports_capability", function() return true end) + rawset(mock_device, "supports_capability", function(_, capability) + local id = type(capability) == "table" and capability.ID or capability + return id == capabilities.lockUsers.ID or id == capabilities.lockCredentials.ID + end) mock_device.get_latest_state = function(_, component_id, capability_id, attribute_name, default_value) local value = mock_latest_state[mock_state_key(component_id, capability_id, attribute_name)] if value == nil then @@ -447,10 +437,11 @@ test.register_coroutine_test( { capability = capabilities.lockCredentials.ID, command = "deleteAllCredentials", args = {} }, }) + -- Per-credential clears fire at 2 * (i - 1) s; final cleanup at 2 * #credentials + 4 s. test.timer.__create_and_queue_test_time_advance_timer(0, "oneshot") test.timer.__create_and_queue_test_time_advance_timer(6, "oneshot") - test.mock_time.advance_time(0) expect_clear_pin_code(1) + test.mock_time.advance_time(0) test.wait_for_events() test.mock_time.advance_time(6) @@ -500,8 +491,6 @@ test.register_coroutine_test( test.register_coroutine_test( "deleteAllCredentials: returns busy when another operation is already in progress", function() - seed_credentials({ { userIndex = 1, credentialIndex = 1, credentialType = "pin" } }) - -- First deleteAllCredentials starts the z-wave flow (device is now busy) test.socket.capability:__queue_receive({ mock_device.id, diff --git a/drivers/SmartThings/zwave-lock/src/test/test_lock_pre_configured.lua b/drivers/SmartThings/zwave-lock/src/test/test_lock_pre_configured.lua index ef264e0c88..c5f89b6672 100644 --- a/drivers/SmartThings/zwave-lock/src/test/test_lock_pre_configured.lua +++ b/drivers/SmartThings/zwave-lock/src/test/test_lock_pre_configured.lua @@ -19,17 +19,6 @@ local json = require "st.json" test.disable_startup_messages() -if table_utils.find_all_entries_by == nil then - function table_utils.find_all_entries_by(device, table_name, key, value) - local entries = table_utils.get_state(device, table_name) or {} - local matches = {} - for _, entry in ipairs(entries) do - if entry[key] == value then table.insert(matches, entry) end - end - return matches - end -end - -- ── Shared device ────────────────────────────────────────────────────────── @@ -70,8 +59,11 @@ local function install_state_mocks() error = function() end, }) - -- get_state guards with device:supports_capability; always return true here. - rawset(mock_device, "supports_capability", function() return true end) + -- get_state guards with device:supports_capability; only the seeded capabilities are supported. + rawset(mock_device, "supports_capability", function(_, capability) + local id = type(capability) == "table" and capability.ID or capability + return id == capabilities.lockUsers.ID or id == capabilities.lockCredentials.ID + end) -- get_state / get_max_entries use device:get_latest_state to read -- capability attribute values from the state cache.