local c_tasks = require('mc.orm.tasks')
if not c_tasks._pd_ut_sleep_patch then
c_tasks._pd_ut_sleep_patch = true
local raw_get_instance = c_tasks.get_instance
local fallback_tasks = { sleep_ms = function() end }
c_tasks.get_instance = function()
local inst = raw_get_instance()
return inst or fallback_tasks
end
end
local pd_service = require('pd.pd_identify_service')
local pd_object = require('pd.pd_object')
local c_storageconfig = require('storageconfig.storageconfig_object')
local drive_collection = require('drive.drive_collection')
local lu = require('luaunit')
local skynet = require('skynet')
local sml = require('sml')
local PD_MAX_TRY <const> = 60
Test_Pd_Identify_Debug = {}
function Test_Pd_Identify_Debug:setupClass()
pd_service.new(nil)
end
function Test_Pd_Identify_Debug:setUp()
if
type(pd_service.drive_list) ~= 'table'
or type(pd_service.pd_list) ~= 'table'
or type(pd_service.identified_list) ~= 'table'
then
pd_service.new(nil)
end
end
local function clone_list(t)
local r = {}
if not t then
return r
end
for i, v in ipairs(t) do
r[i] = v
end
return r
end
local function snapshot_pd_lists()
return {
drive_list = clone_list(pd_service.drive_list),
pd_list = clone_list(pd_service.pd_list),
identified_list = clone_list(pd_service.identified_list),
}
end
local function restore_pd_lists(s)
pd_service.drive_list = clone_list(s.drive_list)
pd_service.pd_list = clone_list(s.pd_list)
pd_service.identified_list = clone_list(s.identified_list)
end
function Test_Pd_Identify_Debug:test_get_locating_led_snapshot_only_pending_locating()
local snap = snapshot_pd_lists()
local d_on = {
Name = 'Disk_on',
is_presence = function()
return true
end,
is_being_located = function()
return true
end,
}
local d_off = {
Name = 'Disk_off',
is_presence = function()
return true
end,
is_being_located = function()
return false
end,
}
pd_service.drive_list = { d_on, d_off }
local cnt, names = pd_service:get_locating_led_snapshot()
lu.assertEquals(cnt, 1)
lu.assertEquals(names[1], 'Disk_on')
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_del_pd_calls_identified_nil_before_re_add()
local snap = snapshot_pd_lists()
local nil_identified_count = 0
local drive = {
Name = 'Disk_sym',
identified = function(_, arg)
if arg == nil then
nil_identified_count = nil_identified_count + 1
end
end,
}
local pd = {
key = 'pd_sym:1:1:1',
is_valid = function()
return true
end,
}
pd_service.identified_list = { { pd = pd, drive = drive } }
pd_service.pd_list = {}
local old_add = pd_service.add_drive
local readded_name
pd_service.add_drive = function(_, d)
readded_name = d.Name
end
pd_service:del_pd(pd)
pd_service.add_drive = old_add
lu.assertEquals(nil_identified_count, 1)
lu.assertEquals(readded_name, 'Disk_sym')
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_returns_false_when_no_pending_drives()
local snap = snapshot_pd_lists()
pd_service.drive_list = {}
pd_service.pd_list = {
{
key = 'p',
is_valid = function()
return true
end,
},
}
lu.assertIsFalse(pd_service:identify_task(0))
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_returns_true_when_no_pending_pds()
local snap = snapshot_pd_lists()
pd_service.drive_list = { { Name = 'D' } }
pd_service.pd_list = {}
lu.assertIsTrue(pd_service:identify_task(0))
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_locate_start_fail_smoke()
local snap = snapshot_pd_lists()
local old_sk_sleep = skynet.sleep
local old_idpd = pd_service.identify_pd_by_persistence_data
skynet.sleep = function() end
pd_service.identify_pd_by_persistence_data = function()
return false
end
local pd = {
key = 'pd_loc_fail',
is_valid = function()
return true
end,
locate = function()
return {
start = function()
return false
end,
__close = function() end,
}
end,
}
pd_service.drive_list = {
{
Name = 'Disk_loc',
is_presence = function()
return true
end,
is_being_located = function()
return true
end,
},
}
pd_service.pd_list = { pd }
local r59 = pd_service:identify_task(59)
local r60 = pd_service:identify_task(60)
skynet.sleep = old_sk_sleep
pd_service.identify_pd_by_persistence_data = old_idpd
restore_pd_lists(snap)
lu.assertIsTrue(r59)
lu.assertIsTrue(r60)
end
function Test_Pd_Identify_Debug:test_identify_task_verbose_pd_invalid_after_locate_settle()
local snap = snapshot_pd_lists()
local old_sk = skynet.sleep
local old_idpd = pd_service.identify_pd_by_persistence_data
pd_service.identify_pd_by_persistence_data = function()
return false
end
local valid = true
local pd = {
key = 'pd_inv_settle',
is_valid = function()
return valid
end,
locate = function()
return {
start = function()
return true
end,
__close = function() end,
}
end,
}
skynet.sleep = function()
valid = false
end
pd_service.drive_list = {
{
Name = 'D_settle',
is_presence = function()
return true
end,
is_being_located = function()
return true
end,
},
}
pd_service.pd_list = { pd }
lu.assertIsTrue(pd_service:identify_task(PD_MAX_TRY))
skynet.sleep = old_sk
pd_service.identify_pd_by_persistence_data = old_idpd
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_verbose_pd_removed_from_pd_list_after_sleep()
local snap = snapshot_pd_lists()
local old_sk = skynet.sleep
local old_idpd = pd_service.identify_pd_by_persistence_data
pd_service.identify_pd_by_persistence_data = function()
return false
end
local pd = {
key = 'pd_rm_list',
is_valid = function()
return true
end,
locate = function()
return {
start = function()
return true
end,
__close = function() end,
}
end,
}
local other = {
key = 'pd_other_only',
is_valid = function()
return true
end,
}
skynet.sleep = function()
pd_service.pd_list = { other }
end
pd_service.drive_list = {
{
Name = 'D_rm_list',
is_presence = function()
return true
end,
is_being_located = function()
return true
end,
},
}
pd_service.pd_list = { pd }
lu.assertIsTrue(pd_service:identify_task(PD_MAX_TRY))
skynet.sleep = old_sk
pd_service.identify_pd_by_persistence_data = old_idpd
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_verbose_pd_queue_head_changed_after_sleep()
local snap = snapshot_pd_lists()
local old_sk = skynet.sleep
local old_idpd = pd_service.identify_pd_by_persistence_data
pd_service.identify_pd_by_persistence_data = function()
return false
end
local pd_a = {
key = 'pd_q_a',
is_valid = function()
return true
end,
locate = function()
return {
start = function()
return true
end,
__close = function() end,
}
end,
}
local pd_b = {
key = 'pd_q_b',
is_valid = function()
return true
end,
}
skynet.sleep = function()
pd_service.pd_list = { pd_b, pd_a }
end
pd_service.drive_list = {
{
Name = 'D_q',
is_presence = function()
return true
end,
is_being_located = function()
return true
end,
},
}
pd_service.pd_list = { pd_a, pd_b }
lu.assertIsTrue(pd_service:identify_task(PD_MAX_TRY))
skynet.sleep = old_sk
pd_service.identify_pd_by_persistence_data = old_idpd
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_verbose_pd_invalid_during_drive_scan()
local snap = snapshot_pd_lists()
local old_sk = skynet.sleep
local old_idpd = pd_service.identify_pd_by_persistence_data
local old_lp = pd_service.locate_pd
pd_service.identify_pd_by_persistence_data = function()
return false
end
skynet.sleep = function() end
local pd = {
key = 'pd_scan_brk',
valid = true,
is_valid = function(self)
return self.valid
end,
locate = function()
return {
start = function()
return true
end,
__close = function() end,
}
end,
}
local n = 0
pd_service.locate_pd = function(s, p, d)
local m1, m2 = old_lp(s, p, d)
n = n + 1
if n == 1 then
p.valid = false
end
return m1, m2
end
local d_bad = {
Name = 'D_scan_1',
is_presence = function()
return false
end,
is_being_located = function()
return false
end,
}
local d_ok = {
Name = 'D_scan_2',
is_presence = function()
return true
end,
is_being_located = function()
return true
end,
}
pd_service.drive_list = { d_bad, d_ok }
pd_service.pd_list = { pd }
lu.assertIsTrue(pd_service:identify_task(PD_MAX_TRY))
pd_service.locate_pd = old_lp
skynet.sleep = old_sk
pd_service.identify_pd_by_persistence_data = old_idpd
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_verbose_locate_pd_reject_logged()
local snap = snapshot_pd_lists()
local old_sk = skynet.sleep
local old_idpd = pd_service.identify_pd_by_persistence_data
pd_service.identify_pd_by_persistence_data = function()
return false
end
skynet.sleep = function() end
local pd = {
key = 'pd_reject',
is_valid = function()
return true
end,
locate = function()
return {
start = function()
return true
end,
__close = function() end,
}
end,
}
pd_service.drive_list = {
{
Name = 'D_reject',
is_presence = function()
return false
end,
is_being_located = function()
return false
end,
},
}
pd_service.pd_list = { pd }
lu.assertIsTrue(pd_service:identify_task(PD_MAX_TRY))
skynet.sleep = old_sk
pd_service.identify_pd_by_persistence_data = old_idpd
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_verbose_rotate_pd_queue_on_fail()
local snap = snapshot_pd_lists()
local old_sk = skynet.sleep
local old_idpd = pd_service.identify_pd_by_persistence_data
pd_service.identify_pd_by_persistence_data = function()
return false
end
skynet.sleep = function() end
local mk_pd = function(key)
return {
key = key,
is_valid = function()
return true
end,
locate = function()
return {
start = function()
return true
end,
__close = function() end,
}
end,
}
end
local pda = mk_pd('pd_rot_a')
local pdb = mk_pd('pd_rot_b')
pd_service.drive_list = {
{
Name = 'D_rot',
is_presence = function()
return false
end,
is_being_located = function()
return false
end,
},
}
pd_service.pd_list = { pda, pdb }
lu.assertIsTrue(pd_service:identify_task(PD_MAX_TRY))
lu.assertEquals(pd_service.pd_list[1].key, 'pd_rot_b')
lu.assertEquals(pd_service.pd_list[2].key, 'pd_rot_a')
skynet.sleep = old_sk
pd_service.identify_pd_by_persistence_data = old_idpd
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_identify_task_verbose_cycle_failed_snapshot()
local snap = snapshot_pd_lists()
local old_sk = skynet.sleep
local old_idpd = pd_service.identify_pd_by_persistence_data
pd_service.identify_pd_by_persistence_data = function()
return false
end
skynet.sleep = function() end
local pd = {
key = 'pd_cycle',
is_valid = function()
return true
end,
locate = function()
return {
start = function()
return true
end,
__close = function() end,
}
end,
}
pd_service.drive_list = {
{
Name = 'D_cycle',
is_presence = function()
return false
end,
is_being_located = function()
return false
end,
},
}
pd_service.pd_list = { pd }
lu.assertIsTrue(pd_service:identify_task(PD_MAX_TRY))
skynet.sleep = old_sk
pd_service.identify_pd_by_persistence_data = old_idpd
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_start_identify_task_stops_loop_when_identify_returns_false()
local snap = snapshot_pd_lists()
local old_get_sc = c_storageconfig.get_instance
local sc = { all_ctrl_loaded = true }
c_storageconfig.get_instance = function()
return sc
end
local raw_tasks = c_tasks.get_instance
local loop_body
c_tasks.get_instance = function()
return {
new_task = function()
return {
loop = function(_, fn)
loop_body = fn
return { set_timeout_ms = function() end }
end,
}
end,
}
end
local old_identify = pd_service.identify_task
pd_service.identify_task = function()
return false
end
pd_service.task = nil
pd_service.add_pd_complete = true
pd_service.skip = false
local drive = { Name = 'D_stop', Id = 1, PassThrough = 0, check_link_abnormal = function() end }
pd_service.drive_list = { drive }
pd_service.pd_list = {
{
key = 'pd_stop',
is_valid = function()
return true
end,
},
}
pd_service:start_identify_task(drive)
local stopped = false
loop_body({
stop = function()
stopped = true
end,
})
lu.assertIsTrue(stopped)
lu.assertNil(pd_service.task)
pd_service.identify_task = old_identify
c_tasks.get_instance = raw_tasks
c_storageconfig.get_instance = old_get_sc
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_start_identify_task_long_retry_resets_pd_try_count()
local snap = snapshot_pd_lists()
local old_get_sc = c_storageconfig.get_instance
local sc = { all_ctrl_loaded = true }
c_storageconfig.get_instance = function()
return sc
end
local raw_tasks = c_tasks.get_instance
local loop_body
c_tasks.get_instance = function()
return {
new_task = function()
return {
loop = function(_, fn)
loop_body = fn
return { set_timeout_ms = function() end }
end,
}
end,
}
end
local identify_n = 0
local old_identify = pd_service.identify_task
pd_service.identify_task = function()
identify_n = identify_n + 1
return true
end
pd_service.task = nil
pd_service.add_pd_complete = true
pd_service.skip = false
local drive = { Name = 'D_long', Id = 1, PassThrough = 1, check_link_abnormal = function() end }
pd_service.drive_list = { drive }
pd_service.pd_list = {
{
key = 'pd_long_a',
is_valid = function()
return true
end,
},
{
key = 'pd_long_b',
is_valid = function()
return true
end,
},
}
pd_service:start_identify_task(drive)
local fake_task = { stop = function() end }
for _ = 1, PD_MAX_TRY + 1 do
loop_body(fake_task)
end
lu.assertEquals(identify_n, PD_MAX_TRY + 1)
pd_service.identify_task = old_identify
c_tasks.get_instance = raw_tasks
c_storageconfig.get_instance = old_get_sc
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_start_identify_task_loop_returns_when_skip()
local snap = snapshot_pd_lists()
local old_get_sc = c_storageconfig.get_instance
local sc = { all_ctrl_loaded = true }
c_storageconfig.get_instance = function()
return sc
end
local raw_tasks = c_tasks.get_instance
local loop_body
c_tasks.get_instance = function()
return {
new_task = function()
return {
loop = function(_, fn)
loop_body = fn
return { set_timeout_ms = function() end }
end,
}
end,
}
end
pd_service.task = nil
pd_service.add_pd_complete = true
pd_service.skip = true
local drive = { Name = 'D_skip', Id = 1, PassThrough = 0, check_link_abnormal = function() end }
pd_service.drive_list = { drive }
pd_service.pd_list = {
{
key = 'pd_skip',
is_valid = function()
return true
end,
},
}
pd_service:start_identify_task(drive)
local task_stopped = false
loop_body({
stop = function()
task_stopped = true
end,
})
lu.assertFalse(task_stopped)
pd_service.task = nil
pd_service.skip = false
c_tasks.get_instance = raw_tasks
c_storageconfig.get_instance = old_get_sc
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_start_identify_task_check_link_abnormal()
local snap = snapshot_pd_lists()
local old_get_sc = c_storageconfig.get_instance
local sc = { all_ctrl_loaded = true }
c_storageconfig.get_instance = function()
return sc
end
local raw_tasks = c_tasks.get_instance
local loop_body
c_tasks.get_instance = function()
return {
new_task = function()
return {
loop = function(_, fn)
loop_body = fn
return { set_timeout_ms = function() end }
end,
}
end,
}
end
local check_called = false
local old_identify = pd_service.identify_task
pd_service.identify_task = function()
return true
end
pd_service.task = nil
pd_service.add_pd_complete = true
pd_service.skip = false
local drive = {
Name = 'D_link',
Id = 1,
PassThrough = 0,
check_link_abnormal = function()
check_called = true
end,
}
pd_service.drive_list = { drive }
pd_service.pd_list = {
{
key = 'pd_link_a',
is_valid = function()
return true
end,
},
}
pd_service:start_identify_task(drive)
local fake_task = { stop = function() end }
loop_body(fake_task)
lu.assertFalse(check_called)
loop_body(fake_task)
lu.assertTrue(check_called)
pd_service.identify_task = old_identify
pd_service.task = nil
c_tasks.get_instance = raw_tasks
c_storageconfig.get_instance = old_get_sc
restore_pd_lists(snap)
end
function Test_Pd_Identify_Debug:test_start_identify_task_assigns_task()
local snap = snapshot_pd_lists()
local old_get_sc = c_storageconfig.get_instance
local sc = { all_ctrl_loaded = true }
c_storageconfig.get_instance = function()
return sc
end
local raw_tasks = c_tasks.get_instance
c_tasks.get_instance = function()
return {
new_task = function()
return {
loop = function(_, fn)
return {
set_timeout_ms = function(self)
return self
end,
}
end,
}
end,
}
end
pd_service.task = nil
pd_service.add_pd_complete = true
pd_service.skip = false
local drive = { Name = 'D_assign', Id = 1, PassThrough = 0, check_link_abnormal = function() end }
pd_service.drive_list = { drive }
pd_service.pd_list = {
{
key = 'pd_assign',
is_valid = function()
return true
end,
},
}
pd_service:start_identify_task(drive)
lu.assertNotNil(pd_service.task)
pd_service.task = nil
c_tasks.get_instance = raw_tasks
c_storageconfig.get_instance = old_get_sc
restore_pd_lists(snap)
end
Test_Pd_Object_AutoLocate = {}
function Test_Pd_Object_AutoLocate:test_locate_start_false_when_sml_returns_non_ok()
local old_op = sml.pd_operation
local inst = c_tasks.get_instance()
local old_sleep = inst.sleep_ms
sml.pd_operation = function()
return 1
end
inst.sleep_ms = function() end
local pd = { device_id = 9, slot_num = 2, enclosure_id = 3 }
local obj = pd_object.new(1, pd, 0)
local loc = obj:locate()
lu.assertIsFalse(loc:start())
lu.assertIsFalse(loc.is_locate)
inst.sleep_ms = old_sleep
sml.pd_operation = old_op
end
function Test_Pd_Object_AutoLocate:test_stop_locate_notice_when_sml_stop_returns_non_ok()
local old_op = sml.pd_operation
local inst = c_tasks.get_instance()
local old_sleep = inst.sleep_ms
local old_get_controller = pd_object.get_controller
inst.sleep_ms = function() end
pd_object.get_controller = function() end
local LOCATE_OP = 1
local STOP_OP = 0
sml.pd_operation = function(_, _, op, _)
if op == LOCATE_OP then
return 0
end
if op == STOP_OP then
return 9
end
return 0
end
local pd = {
device_id = 9,
slot_num = 2,
enclosure_id = 3,
controller_id = 4,
is_valid = function()
return true
end,
}
local obj = pd_object.new(1, pd, 0)
local loc = obj:locate()
lu.assertIsTrue(loc:start())
loc:__close()
inst.sleep_ms = old_sleep
sml.pd_operation = old_op
pd_object.get_controller = old_get_controller
end
function Test_Pd_Object_AutoLocate:test_pd_object_operation_logs_error_on_non_ok()
local old_op = sml.pd_operation
sml.pd_operation = function()
return 1
end
local pd = { device_id = 9, slot_num = 2, enclosure_id = 3, controller_id = 4 }
local obj = pd_object.new(1, pd, 0)
local retval = obj:pd_object_operation(7, string.pack('B', 1))
lu.assertEquals(retval, 1)
sml.pd_operation = old_op
end
function Test_Pd_Object_AutoLocate:test_pd_object_operation_invalid_returns_invalid()
local pd = { device_id = 9, slot_num = 2, enclosure_id = 3, controller_id = 4 }
local obj = pd_object.new(1, pd, 0)
obj:invalid()
local retval = obj:pd_object_operation(7, '')
lu.assertEquals(retval, 1)
end
function Test_Pd_Object_AutoLocate:test_set_short_dst_success()
local old_op = sml.pd_operation
sml.pd_operation = function()
return 0
end
local pd = { device_id = 9, slot_num = 2, enclosure_id = 3, controller_id = 4 }
local obj = pd_object.new(1, pd, 0)
local retval = obj:set_short_dst(1)
lu.assertEquals(retval, 0)
sml.pd_operation = old_op
end
function Test_Pd_Object_AutoLocate:test_locate_start_set_led_when_directly_manage()
local old_op = sml.pd_operation
local inst = c_tasks.get_instance()
local old_sleep = inst.sleep_ms
local old_get_controller = pd_object.get_controller
local old_drive = drive_collection.get_instance
inst.sleep_ms = function() end
local led_calls = {}
drive_collection.get_instance = function()
return {
get_drive_by_drive_id = function(_, id)
return {
set_locate_led = function(_, val)
table.insert(led_calls, { drive_id = id, led = val })
end,
}
end,
}
end
pd_object.get_controller = function()
return {
is_directly_manage_physical_drive = function()
return true
end,
}
end
sml.pd_operation = function()
return 0
end
local pd = {
device_id = 9,
slot_num = 2,
enclosure_id = 3,
controller_id = 4,
is_valid = function()
return true
end,
}
local obj = pd_object.new(1, pd, 0)
local loc = obj:locate()
lu.assertIsTrue(loc:start())
lu.assertEquals(#led_calls, 1)
lu.assertEquals(led_calls[1].drive_id, 209)
lu.assertEquals(led_calls[1].led, 1)
loc:__close()
inst.sleep_ms = old_sleep
sml.pd_operation = old_op
pd_object.get_controller = old_get_controller
drive_collection.get_instance = old_drive
end
function Test_Pd_Object_AutoLocate:test_get_controller_returns_controller_by_id()
local old_cc = package.loaded['controller.controller_collection']
package.loaded['controller.controller_collection'] = nil
local controller_collection = require('controller.controller_collection')
local old_get_instance = controller_collection.get_instance
local expected_ctrl = { Id = 1, TypeId = 200 }
controller_collection.get_instance = function()
return {
get_by_controller_id = function(_, ctrl_id)
lu.assertEquals(ctrl_id, 1)
return expected_ctrl
end,
}
end
local pd = { device_id = 9, slot_num = 2, enclosure_id = 3 }
local obj = pd_object.new(1, pd, 0)
local ctrl = obj:get_controller()
lu.assertEquals(ctrl, expected_ctrl)
controller_collection.get_instance = old_get_instance
package.loaded['controller.controller_collection'] = old_cc
end
function Test_Pd_Object_AutoLocate:test_locate_stop_set_led_when_directly_manage()
local old_op = sml.pd_operation
local inst = c_tasks.get_instance()
local old_sleep = inst.sleep_ms
local old_get_controller = pd_object.get_controller
local old_drive = drive_collection.get_instance
inst.sleep_ms = function() end
local led_calls = {}
drive_collection.get_instance = function()
return {
get_drive_by_drive_id = function(_, id)
return {
set_locate_led = function(_, val)
table.insert(led_calls, { drive_id = id, led = val })
end,
}
end,
}
end
pd_object.get_controller = function()
return {
is_directly_manage_physical_drive = function()
return true
end,
}
end
local LOCATE_OP = 1
local STOP_OP = 0
sml.pd_operation = function(_, _, op, _)
if op == LOCATE_OP then
return 0
end
if op == STOP_OP then
return 0
end
return 0
end
local pd = {
device_id = 9,
slot_num = 2,
enclosure_id = 3,
controller_id = 4,
is_valid = function()
return true
end,
}
local obj = pd_object.new(1, pd, 0)
local loc = obj:locate()
lu.assertIsTrue(loc:start())
loc:__close()
lu.assertEquals(#led_calls, 2)
lu.assertEquals(led_calls[1].led, 1)
lu.assertEquals(led_calls[2].led, 0)
inst.sleep_ms = old_sleep
sml.pd_operation = old_op
pd_object.get_controller = old_get_controller
drive_collection.get_instance = old_drive
end