[moblab] add moblab_StorageQual test
Create a test that will flex the moblab provisioning and scheduling
functionality required to run hardware_storagequal suite. Storage qual
requires that tests run in the correct priority order on the correct
DUTs as determined by their labels. This is a new moblab suite, which
runs a new non-destructive storage qual suite 'hardware_storagequal_cq'
on the DUTs. This test is intended to be added to CQ. Before adding
to CQ, we will need to label 2 DUTs on each moblab as 'storage_qual_cq_1'
and 'storage_qual_cq_2'.
BUG=chromium:878009
TEST=run_suite.py --pool='' --board=caroline --build=caroline-release/R69-10755.0.0 --suite_name=hardware_storagequal_cq --retry=True --max_retries=42
test_that -b guado_moblab 100.90.25.159 moblab_StorageQual --args="image_storage_server=gs://chromeos-moblab-peng-staging/ clear_devserver_cache=False"
Change-Id: I2846200d2ac90664c2d9d87ba825698ed9a06386
Reviewed-on: https://chromium-review.googlesource.com/1225892
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Matt Mallett <mattmallett@chromium.org>
Reviewed-by: Keith Haddow <haddowk@chromium.org>
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_1_after b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_1_after
new file mode 100644
index 0000000..f84a35f
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_1_after
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageQualBase_storage_qual_cq_1_after"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageQualBase_storage_qual_cq_1_after"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 70
+DEPENDENCIES = "storage_qual_cq_1"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageQualBase_storage_qual_cq_1_after"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageQualBase", host=hosts.create_host(machine),
+ client_ip=machine, client_tag='after', tag='after', cq=True)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_1_before b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_1_before
new file mode 100644
index 0000000..a8bb211
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_1_before
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageQualBase_storage_qual_cq_1_before"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageQualBase_storage_qual_cq_1_before"
+TIME = "lengthy"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 100
+DEPENDENCIES = "storage_qual_cq_1"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageQualBase_storage_qual_cq_1_before"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageQualBase", host=hosts.create_host(machine),
+ client_ip=machine, client_tag='before', tag='before', cq=True)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_2_after b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_2_after
new file mode 100644
index 0000000..c2b8134
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_2_after
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageQualBase_storage_qual_cq_2_after"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageQualBase_storage_qual_cq_2_after"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 70
+DEPENDENCIES = "storage_qual_cq_2"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageQualBase_storage_qual_cq_2_after"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageQualBase", host=hosts.create_host(machine),
+ client_ip=machine, client_tag='after', tag='after', cq=True)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_2_before b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_2_before
new file mode 100644
index 0000000..43fb1ed
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualBase_storage_qual_cq_2_before
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageQualBase_storage_qual_cq_2_before"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageQualBase_storage_qual_cq_2_before"
+TIME = "lengthy"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 100
+DEPENDENCIES = "storage_qual_cq_2"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageQualBase_storage_qual_cq_2_before"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageQualBase", host=hosts.create_host(machine),
+ client_ip=machine, client_tag='before', tag='before', cq=True)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualTrimStress_storage_qual_cq_2_0 b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualTrimStress_storage_qual_cq_2_0
new file mode 100644
index 0000000..666c9fd
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualTrimStress_storage_qual_cq_2_0
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageQualTrimStress_storage_qual_cq_2_0"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageQualTrimStress_storage_qual_cq_2_0"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 80
+DEPENDENCIES = "storage_qual_cq_2"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageQualTrimStress_storage_qual_cq_2_0"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageQualTrimStress", host=hosts.create_host(machine),
+ client_ip=machine, duration=1800, cq=True)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualTrimStress_storage_qual_cq_2_1 b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualTrimStress_storage_qual_cq_2_1
new file mode 100644
index 0000000..566a2b3
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageQualTrimStress_storage_qual_cq_2_1
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageQualTrimStress_storage_qual_cq_2_1"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageQualTrimStress_storage_qual_cq_2_1"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 80
+DEPENDENCIES = "storage_qual_cq_2"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageQualTrimStress_storage_qual_cq_2_1"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageQualTrimStress", host=hosts.create_host(machine),
+ client_ip=machine, duration=1800, cq=True)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_soak_0 b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_soak_0
new file mode 100644
index 0000000..fadf017
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_soak_0
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageStress_storage_qual_cq_1_soak_0"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageStress_storage_qual_cq_1_soak_0"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 90
+DEPENDENCIES = "storage_qual_cq_1"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageStress_storage_qual_cq_1_soak_0"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageStress", host=hosts.create_host(machine),
+ client_ip=machine, storage_test_command='full_write', suspend_duration=300, tag='soak', duration=14400, cq=True, power_command='wait')
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_soak_1 b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_soak_1
new file mode 100644
index 0000000..6754193
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_soak_1
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageStress_storage_qual_cq_1_soak_1"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageStress_storage_qual_cq_1_soak_1"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 90
+DEPENDENCIES = "storage_qual_cq_1"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageStress_storage_qual_cq_1_soak_1"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageStress", host=hosts.create_host(machine),
+ client_ip=machine, storage_test_command='full_write', suspend_duration=300, tag='soak', duration=14400, cq=True, power_command='wait')
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_suspend b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_suspend
new file mode 100644
index 0000000..950ff1b
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_1_suspend
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageStress_storage_qual_cq_1_suspend"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageStress_storage_qual_cq_1_suspend"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 80
+DEPENDENCIES = "storage_qual_cq_1"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageStress_storage_qual_cq_1_suspend"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageStress", host=hosts.create_host(machine),
+ client_ip=machine, storage_test_command='full_write', suspend_duration=120, tag='suspend', duration=1800, cq=True, power_command='suspend')
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_2_soak_0 b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_2_soak_0
new file mode 100644
index 0000000..deacfce
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_2_soak_0
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageStress_storage_qual_cq_2_soak_0"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageStress_storage_qual_cq_2_soak_0"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 90
+DEPENDENCIES = "storage_qual_cq_2"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageStress_storage_qual_cq_2_soak_0"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageStress", host=hosts.create_host(machine),
+ client_ip=machine, storage_test_command='full_write', suspend_duration=300, tag='soak', duration=14400, cq=True, power_command='wait')
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_2_soak_1 b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_2_soak_1
new file mode 100644
index 0000000..4a89bd2
--- /dev/null
+++ b/server/site_tests/hardware_StorageQual/control.storage_qual_cq_hardware_StorageStress_storage_qual_cq_2_soak_1
@@ -0,0 +1,36 @@
+
+# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This control file was auto-generated by generate_storage_qual_control_files.py
+# Do not edit this file!
+
+from autotest_lib.client.common_lib import utils
+
+AUTHOR = "Chrome OS Team"
+NAME = "hardware_StorageStress_storage_qual_cq_2_soak_1"
+ATTRIBUTES = "suite:storage_qual_cq"
+PURPOSE = "hardware_StorageStress_storage_qual_cq_2_soak_1"
+TIME = "long"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "Hardware"
+TEST_TYPE = "server"
+REQUIRE_SSP = False
+PRIORITY = 90
+DEPENDENCIES = "storage_qual_cq_2"
+JOB_RETRIES = 0
+
+DOC = "hardware_StorageStress_storage_qual_cq_2_soak_1"
+
+keyval = dict()
+keyval['storage_qual_version'] = 1
+keyval['bug_id'] = bug_id
+keyval['part_id'] = part_id
+utils.write_keyval(job.resultdir, keyval)
+
+def run(machine):
+ job.run_test("hardware_StorageStress", host=hosts.create_host(machine),
+ client_ip=machine, storage_test_command='full_write', suspend_duration=300, tag='soak', duration=14400, cq=True, power_command='wait')
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/hardware_StorageQual/generate_storage_qual_control_files.py b/server/site_tests/hardware_StorageQual/generate_storage_qual_control_files.py
index 2d38836..73e2c14 100644
--- a/server/site_tests/hardware_StorageQual/generate_storage_qual_control_files.py
+++ b/server/site_tests/hardware_StorageQual/generate_storage_qual_control_files.py
@@ -61,10 +61,6 @@
'length': 'long'
}
-SOAK_QUICK = copy.deepcopy(SOAK)
-SOAK_QUICK['iterations'] = 2
-SOAK_QUICK['args']['duration'] = HOUR_IN_SECS
-
BASE_AFTER = {
'test': 'hardware_StorageQualBase',
'args': {'tag': 'after', 'client_tag': 'after'},
@@ -72,6 +68,18 @@
'length': 'long'
}
+SOAK_QUICK = copy.deepcopy(SOAK)
+SOAK_QUICK['iterations'] = 2
+SOAK_QUICK['args']['duration'] = HOUR_IN_SECS
+
+BASE_BEFORE_CQ = copy.deepcopy(BASE_BEFORE)
+BASE_BEFORE_CQ['args']['cq'] = True
+SOAK_CQ = copy.deepcopy(SOAK)
+SOAK_CQ['args']['cq'] = True
+SOAK_CQ['iterations'] = 2
+BASE_AFTER_CQ = copy.deepcopy(BASE_AFTER)
+BASE_AFTER_CQ['args']['cq'] = True
+
SUITES = {
'storage_qual': [
{
@@ -179,12 +187,50 @@
BASE_AFTER
]
}
+ ],
+ 'storage_qual_cq': [
+ {
+ 'label': 'storage_qual_cq_1',
+ 'tests': [
+ BASE_BEFORE_CQ,
+ SOAK_CQ,
+ {
+ 'test': 'hardware_StorageStress',
+ 'args': {'tag': 'suspend', 'power_command': 'suspend',
+ 'storage_test_command': 'full_write',
+ 'suspend_duration': 120,
+ 'duration': HOUR_IN_SECS / 2,
+ 'cq': True
+ },
+ 'priority': 80,
+ 'length': 'long'
+ },
+ BASE_AFTER_CQ
+ ]
+ },
+
+ {
+ 'label': 'storage_qual_cq_2',
+ 'tests': [
+ BASE_BEFORE_CQ,
+ SOAK_CQ,
+ {
+ 'test': 'hardware_StorageQualTrimStress',
+ 'args': {'duration': HOUR_IN_SECS / 2, 'cq': True},
+ 'iterations': 2,
+ 'priority': 80,
+ 'length': 'long'
+ },
+ BASE_AFTER_CQ
+ ]
+ }
]
}
SUITE_ATTRIBUTES = {
'storage_qual': 'suite:storage_qual',
- 'storage_qual_quick': 'suite:storage_qual_quick'
+ 'storage_qual_quick': 'suite:storage_qual_quick',
+ 'storage_qual_cq': 'suite:storage_qual_cq'
}
TEMPLATE = """
diff --git a/server/site_tests/hardware_StorageQualBase/hardware_StorageQualBase.py b/server/site_tests/hardware_StorageQualBase/hardware_StorageQualBase.py
index 9fe90ec..b3d015d 100644
--- a/server/site_tests/hardware_StorageQualBase/hardware_StorageQualBase.py
+++ b/server/site_tests/hardware_StorageQualBase/hardware_StorageQualBase.py
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import time
from autotest_lib.server import autotest
from autotest_lib.server import hosts
from autotest_lib.server import test
@@ -47,7 +48,17 @@
]
- def run_once(self, client_ip, client_tag='', crypto_runtime=CRYPTO_RUNTIME):
+ def run_once(self, client_ip, client_tag='', crypto_runtime=CRYPTO_RUNTIME,
+ cq=False):
+
+ # in a cq run, do not execute the test, just output
+ # the order that the test would have run in
+ if cq:
+ self.write_test_keyval(
+ {'storage_qual_cq': ('%f hardware_StorageQualBase_%s'
+ % (time.time(), client_tag))})
+ return
+
client = hosts.create_host(client_ip)
client_at = autotest.Autotest(client)
for test_name, argv in self.CLIENT_FUNCTIONAL_TESTS:
diff --git a/server/site_tests/hardware_StorageQualTrimStress/hardware_StorageQualTrimStress.py b/server/site_tests/hardware_StorageQualTrimStress/hardware_StorageQualTrimStress.py
index ba711de..3b76450 100644
--- a/server/site_tests/hardware_StorageQualTrimStress/hardware_StorageQualTrimStress.py
+++ b/server/site_tests/hardware_StorageQualTrimStress/hardware_StorageQualTrimStress.py
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import time
from autotest_lib.server import autotest
from autotest_lib.server import hosts
from autotest_lib.server import test
@@ -10,7 +11,15 @@
"""Do traffic and trim while suspending aggressively."""
version = 1
- def run_once(self, client_ip, duration):
+ def run_once(self, client_ip, duration, cq=False):
+
+ # in a cq run, do not execute the test, just output
+ # the order that the test would have run in
+ if cq:
+ self.write_test_keyval({'storage_qual_cq':
+ '%f hardware_StorageQualTrimStress' % time.time()})
+ return
+
client = hosts.create_host(client_ip)
client_at = autotest.Autotest(client)
control = """job.parallel(
diff --git a/server/site_tests/hardware_StorageStress/hardware_StorageStress.py b/server/site_tests/hardware_StorageStress/hardware_StorageStress.py
index f8e612b..6d699a5 100644
--- a/server/site_tests/hardware_StorageStress/hardware_StorageStress.py
+++ b/server/site_tests/hardware_StorageStress/hardware_StorageStress.py
@@ -25,7 +25,8 @@
def run_once(self, client_ip, gap=_TEST_GAP, duration=_TEST_DURATION,
power_command='reboot', storage_test_command='integrity',
- suspend_duration=_SUSPEND_DURATION, storage_test_argument=''):
+ suspend_duration=_SUSPEND_DURATION, storage_test_argument='',
+ cq=False):
"""
Run the Storage stress test
Use hardwareStorageFio to run some test_command repeatedly for a long
@@ -44,8 +45,20 @@
to determine which disk to write
@param suspend_duration: if power_command is suspend, how long the DUT
is suspended.
+ @param cq: Indicates that this test is being run as part of
+ the cq. This is not used to test a component for
+ qualification, but to test the storage qual suite
"""
+ # in a cq run, do not execute the test, just output
+ # the order that the test would have run in
+ if cq:
+ label = 'suspend' if power_command is 'suspend' else 'soak'
+ self.write_test_keyval(
+ {'storage_qual_cq': ('%f hardware_StorageStress_%s'
+ % (time.time(), label))})
+ return
+
# init test
if not client_ip:
error.TestError("Must provide client's IP address to test")
diff --git a/server/site_tests/moblab_StorageQual/control b/server/site_tests/moblab_StorageQual/control
new file mode 100644
index 0000000..15949bb
--- /dev/null
+++ b/server/site_tests/moblab_StorageQual/control
@@ -0,0 +1,71 @@
+# Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = "chromeos-moblab@google.com"
+NAME = "moblab_StorageQual"
+PURPOSE = "Test that Moblab can run the Storage Qual suite."
+ATTRIBUTES = "suite:moblab_storage_qual"
+TIME = "MEDIUM"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = "moblab"
+TEST_TYPE = "server"
+
+DOC = """
+Kicks off the storage qual suite on a Moblab host against the DUTs on its
+subnet and ensures the suite completes successfully. The suite tests that
+moblab correctly provisions and runs the storage qual suite, but does not
+perform any disk operations.
+
+To invole this test locally:
+ test_that -b stumpy_moblab <remote> moblab_StorageQual
+ --args="<ARGLIST>"
+
+where ARGLIST is a whitespace separated list of the following key=value pairs.
+Values pertaining to the test case include:
+
+ boto_path=<boto_path> path to the boto file to be installed on
+ the Moblab DUT. If not specified, the
+ boto file in the current home directory
+ will be installed if it exists.
+ image_storage_server=<server_name> Google Storage Bucket from which to
+ fetch test images from. If not
+ specified, the value will be fetched
+ from global_config.
+ service_init_timeout_m=<int> Timeout (in minutes) to wait for upstart
+ services to start on the moblab host.
+ This can take ~5 minutes on a physical
+ devices and ~10 minutes on a VM.
+ test_timeout_hint_m=<int> The overall timeout to expect for the
+ test run. For this test, it is very
+ important to collect post failure data
+ from the moblab device. If the overall
+ timeout is provided, the test will try to
+ fail early to save some time for log
+ collection from the DUT.
+ clear_devserver_cache=<boolean> If True, image cache of the devserver
+ running on moblab is cleared before
+ running the test to validate devserver
+ imaging staging flow.
+"""
+from autotest_lib.client.bin import sysinfo
+from autotest_lib.client.common_lib import utils
+
+MOBLAB_AUTOTEST_FOLDERS = ['/usr/local/autotest/results',
+ '/usr/local/autotest/logs']
+
+
+def run(machine):
+ host = hosts.create_host(machine)
+ args_dict = utils.args_to_dict(args)
+
+ logging.info('Logs from moblab\'s instance of autotest will be collected '
+ 'under the sysinfo/ folder in results.')
+ for folder in MOBLAB_AUTOTEST_FOLDERS:
+ logging.info(' Will collect %s', folder)
+ job.sysinfo.add_logdir(sysinfo.logdir(folder, excludes=()))
+
+ job.run_test('moblab_StorageQual', host=host,
+ moblab_suite_max_retries=1, **args_dict)
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/moblab_StorageQual/moblab_StorageQual.py b/server/site_tests/moblab_StorageQual/moblab_StorageQual.py
new file mode 100644
index 0000000..8aac8d3
--- /dev/null
+++ b/server/site_tests/moblab_StorageQual/moblab_StorageQual.py
@@ -0,0 +1,272 @@
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import re
+
+from autotest_lib.client.common_lib import error
+from autotest_lib.server.cros import moblab_test
+from autotest_lib.server.hosts import moblab_host
+from autotest_lib.utils import labellib
+
+
+_CLEANUP_TIME_M = 5
+_MOBLAB_IMAGE_STORAGE = '/mnt/moblab/static'
+
+class moblab_StorageQual(moblab_test.MoblabTest):
+ """
+ Moblab storage qual suite test. Ensures that moblab can run the storage
+ qual tests on the correct DUTs in the correct order. This test does not
+ perform any destructive disk operations.
+
+ The test requires 2 duts, labeled 'storage_qual_cq_1', 'storage_qual_cq_2'.
+ Each DUT will run a sequence of tests, and the test will then verify
+ that the correct tests ran on the correctly labeled DUT, in the correct
+ order.
+ """
+ version = 1
+
+ # Moblab expects to have 1 dut with each of these labels
+ REQUIRED_LABELS = {'storage_qual_cq_1', 'storage_qual_cq_2'}
+
+ EXPECTED_RESULTS = {
+ 'storage_qual_cq_1': [
+ 'hardware_StorageQualBase_before',
+ 'hardware_StorageStress_soak',
+ 'hardware_StorageStress_soak',
+ 'hardware_StorageStress_suspend',
+ 'hardware_StorageQualBase_after'
+ ],
+ 'storage_qual_cq_2': [
+ 'hardware_StorageQualBase_before',
+ 'hardware_StorageStress_soak',
+ 'hardware_StorageStress_soak',
+ 'hardware_StorageQualTrimStress',
+ 'hardware_StorageQualTrimStress',
+ 'hardware_StorageQualBase_after'
+ ]
+ }
+
+ def run_once(self, host, moblab_suite_max_retries,
+ target_build='', clear_devserver_cache=True,
+ test_timeout_hint_m=None):
+ """Runs a suite on a Moblab Host against its test DUTS.
+
+ @param host: Moblab Host that will run the suite.
+ @param moblab_suite_max_retries: The maximum number of test retries
+ allowed within the suite launched on moblab.
+ @param target_build: Optional build to be use in the run_suite
+ call on moblab. This argument is passed as is to run_suite. It
+ must be a sensible build target for the board of the sub-DUTs
+ attached to the moblab.
+ @param clear_devserver_cache: If True, image cache of the devserver
+ running on moblab is cleared before running the test to validate
+ devserver imaging staging flow.
+ @param test_timeout_hint_m: (int) Optional overall timeout for the test.
+ For this test, it is very important to collect post failure data
+ from the moblab device. If the overall timeout is provided, the
+ test will try to fail early to save some time for log collection
+ from the DUT.
+
+ @raises AutoservRunError if the suite does not complete successfully.
+ """
+ self._host = host
+ self._maybe_clear_devserver_cache(clear_devserver_cache)
+
+ duts = host.afe.get_hosts()
+ if len(duts) == 0:
+ raise error.TestFail('All hosts for this MobLab are down. Please '
+ 'request the lab admins to take a look.')
+
+ board = None
+ dut_to_label = {}
+ for dut in duts:
+ # Fetch the board of the DUT's assigned to this Moblab. There should
+ # only be one type.
+ board = labellib.LabelsMapping(dut.labels)['board']
+ for label in dut.labels:
+ if label in self.REQUIRED_LABELS:
+ dut_to_label[dut.hostname] = label
+
+ if not set(dut_to_label.values()) == self.REQUIRED_LABELS:
+ raise error.TestFail(
+ 'Missing required labels on hosts %s, are some hosts down?'
+ % self.REQUIRED_LABELS - set(dut_to_label.values()))
+
+ if not board:
+ raise error.TestFail('Could not determine board from hosts.')
+
+ if not target_build:
+ stable_version_map = host.afe.get_stable_version_map(
+ host.afe.CROS_IMAGE_TYPE)
+ target_build = stable_version_map.get_image_name(board)
+
+ logging.info('Running suite: hardware_storagequal_cq')
+ cmd = ("%s/site_utils/run_suite.py --pool='' --board=%s --build=%s "
+ "--suite_name=hardware_storagequal_cq --retry=True "
+ "--max_retries=%d" %
+ (moblab_host.AUTOTEST_INSTALL_DIR, board, target_build,
+ moblab_suite_max_retries))
+ cmd, run_suite_timeout_s = self._append_run_suite_timeout(
+ cmd,
+ test_timeout_hint_m,
+ )
+
+ logging.debug('Run suite command: %s', cmd)
+ try:
+ result = host.run_as_moblab(cmd, timeout=run_suite_timeout_s)
+ except error.AutoservRunError as e:
+ if _is_run_suite_error_critical(e.result_obj.exit_status):
+ raise
+
+ logging.debug('Suite Run Output:\n%s', result.stderr)
+
+ job_ids = self._get_job_ids_from_suite_output(result.stderr)
+
+ logging.debug('Suite job ids %s', job_ids)
+
+ keyvals_per_host = self._get_keyval_files_per_host(host, job_ids)
+
+ logging.debug('Keyvals grouped by host %s', keyvals_per_host)
+
+ failed_test = False
+ for hostname in keyvals_per_host:
+ label = dut_to_label[hostname]
+ expected = self.EXPECTED_RESULTS[label]
+ actual = self._get_test_execution_order(
+ host, keyvals_per_host[hostname])
+
+ logging.info('Comparing test order for %s from host %s',
+ label, hostname)
+ logging.info('%-37s %s', 'Expected', 'Actual')
+ for i in range(max(len(expected), len(actual))):
+ expected_i = expected[i] if i < len(expected) else None
+ actual_i = actual[i] if i < len(actual) else None
+ check_fail = expected_i != actual_i
+ check_text = 'X' if check_fail else ' '
+ logging.info('%s %-35s %s', check_text, expected_i, actual_i)
+ failed_test = failed_test or check_fail
+
+ # Cache directory can contain large binaries like CTS/CTS zip files
+ # no need to offload those in the results.
+ # The cache is owned by root user
+ host.run('rm -fR /mnt/moblab/results/shared/cache',
+ timeout=600)
+
+ if failed_test:
+ raise error.TestFail(
+ 'Actual test execution order did not match expected')
+
+ def _append_run_suite_timeout(self, cmd, test_timeout_hint_m):
+ """Modify given run_suite command with timeout.
+
+ @param cmd: run_suite command str.
+ @param test_timeout_hint_m: (int) timeout for the test, or None.
+ @return cmd, run_suite_timeout_s: cmd is the updated command str,
+ run_suite_timeout_s is the timeout to use for the run_suite
+ call, in seconds.
+ """
+ if test_timeout_hint_m is None:
+ return cmd, 10800
+
+ # Arguments passed in via test_args may be all str, depending on how
+ # they're passed in.
+ test_timeout_hint_m = int(test_timeout_hint_m)
+ elasped_m = self.elapsed.total_seconds() / 60
+ run_suite_timeout_m = (
+ test_timeout_hint_m - elasped_m - _CLEANUP_TIME_M)
+ logging.info('Overall test timeout hint provided (%d minutes)',
+ test_timeout_hint_m)
+ logging.info('%d minutes have already elasped', elasped_m)
+ logging.info(
+ 'Keeping %d minutes for cleanup, will allow %d minutes for '
+ 'the suite to run.', _CLEANUP_TIME_M, run_suite_timeout_m)
+ cmd += ' --timeout_mins %d' % run_suite_timeout_m
+ return cmd, run_suite_timeout_m * 60
+
+ def _maybe_clear_devserver_cache(self, clear_devserver_cache):
+ # When passed in via test_args, all arguments are str
+ if not isinstance(clear_devserver_cache, bool):
+ clear_devserver_cache = (clear_devserver_cache.lower() == 'true')
+ if clear_devserver_cache:
+ self._host.run('rm -rf %s/*' % _MOBLAB_IMAGE_STORAGE)
+
+ def _get_job_ids_from_suite_output(self, suite_output):
+ """Parse the set of job ids from run_suite output
+
+ @param suite_output (str) output from run_suite command
+ @return (set<int>) job ids contained in the suite
+ """
+ job_ids = set()
+ job_id_pattern = re.compile('(\d+)-moblab')
+ for line in suite_output.splitlines():
+ match = job_id_pattern.search(line)
+ logging.debug('suite line %s match %s', line, match)
+ if match is None:
+ continue
+ job_ids.add(int(match.groups()[0]))
+ return job_ids
+
+ def _get_keyval_files_per_host(self, host, job_ids):
+ """Find the result keyval files for the given job ids and
+ group them by host
+
+ @param host (moblab_host)
+ @param job_ids (set<int>) set of job ids to find keyvals for
+ @return (dict<str, list<str>>) map of hosts and the keyval
+ file locations
+ @throws AutoservRunError if the command fails to run on moblab
+ """
+ keyvals_per_host = {}
+ keyvals = host.run_as_moblab(
+ 'find /mnt/moblab/results '
+ '-wholename *-moblab/192.168*/hardware_Storage*/keyval')
+ pattern = re.compile('(\d+)-moblab/(192.168.\d+.\d+)')
+ for line in keyvals.stdout.splitlines():
+ match = pattern.search(line)
+ if match is None:
+ continue
+ job_id, dut = match.groups()
+ if int(job_id) not in job_ids:
+ continue
+ if dut not in keyvals_per_host:
+ keyvals_per_host[dut] = []
+ keyvals_per_host[dut].append(line)
+
+ return keyvals_per_host
+
+ def _get_test_execution_order(self, host, keyvals):
+ """Determines the test execution order for the given list
+ of storage qual test result keyvals
+
+ @param host (moblab_host)
+ @param keyvals (list<str>) location of keyval files to order
+ @return (list<str>) test names in the order they executed
+ @throws AutoservRunError if the command fails to run on moblab
+ """
+ tests = host.run_as_moblab(
+ 'FILES=(%s); for FILE in ${FILES[@]}; do cat $FILE '
+ '| grep storage_qual_cq; done '
+ '| sort | cut -d " " -f 2'
+ % ' '.join(keyvals)
+ )
+ test_execution_order = []
+ pattern = re.compile('hardware_\w+')
+ logging.debug(tests.stdout)
+ for line in tests.stdout.splitlines():
+ match = pattern.search(line)
+ if match:
+ test_execution_order.append(match.group(0))
+ return test_execution_order
+
+def _is_run_suite_error_critical(return_code):
+ # We can't actually import run_suite here because importing run_suite pulls
+ # in certain MySQLdb dependencies that fail to load in the context of a
+ # test.
+ # OTOH, these return codes are unlikely to change because external users /
+ # builders depend on them.
+ return return_code not in (
+ 0, # run_suite.RETURN_CODES.OK
+ 2, # run_suite.RETURN_CODES.WARNING
+ )
diff --git a/site_utils/attribute_whitelist.txt b/site_utils/attribute_whitelist.txt
index 04bbbec..a682c8a 100644
--- a/site_utils/attribute_whitelist.txt
+++ b/site_utils/attribute_whitelist.txt
@@ -151,6 +151,7 @@
suite:mmc_qual
suite:moblab
suite:moblab_quick
+suite:moblab_storage_qual
suite:network_nightly
suite:network_ui
suite:partners
@@ -181,6 +182,7 @@
suite:something_else
suite:ssdqual
suite:storage_qual
+suite:storage_qual_cq
suite:storage_qual_quick
suite:storage_qual_temp
suite:storagequal
diff --git a/test_suites/control.hardware_storagequal_cq b/test_suites/control.hardware_storagequal_cq
new file mode 100644
index 0000000..406456a
--- /dev/null
+++ b/test_suites/control.hardware_storagequal_cq
@@ -0,0 +1,38 @@
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = 'mattmallett'
+NAME = 'storage_qual_cq'
+TIME = 'SHORT'
+TEST_CATEGORY = 'General'
+TEST_CLASS = 'suite'
+TEST_TYPE = 'Server'
+
+DOC = """
+Test the moblab mechanisms that run the storage qual suite in the cq
+
+@param build: The name of the image to test.
+ Ex: x86-mario-release/R17-1412.33.0-a1-b29
+@param board: The board to test on. Ex: x86-mario
+@param pool: The pool of machines to utilize for scheduling. If pool=None
+ board is used.
+@param check_hosts: require appropriate live hosts to exist in the lab.
+@param SKIP_IMAGE: (optional) If present and True, don't re-image devices.
+@param file_bugs: If True your suite will file bugs on failures.
+"""
+
+import common
+from autotest_lib.server.cros.dynamic_suite import dynamic_suite
+
+args_dict['add_experimental'] = True
+args_dict['timeout_mins'] = 30
+args_dict['max_runtime_mins'] = 30
+args_dict['name'] = NAME
+args_dict['job'] = job
+args_dict['test_args'] = {
+ 'bug_id': '',
+ 'part_id': ''
+}
+
+dynamic_suite.reimage_and_run(**args_dict)
diff --git a/test_suites/control.moblab_storage_qual b/test_suites/control.moblab_storage_qual
new file mode 100644
index 0000000..9413818
--- /dev/null
+++ b/test_suites/control.moblab_storage_qual
@@ -0,0 +1,33 @@
+# Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = "Chrome OS Team"
+NAME = "moblab_storage_qual"
+PURPOSE = "Quickly test basic moblab functionality."
+
+TIME = "MEDIUM"
+TEST_CATEGORY = "General"
+TEST_CLASS = "suite"
+TEST_TYPE = "Server"
+
+DOC = """
+Moblab Functionality Tests
+
+@param build: The name of the image to test.
+ Ex: x86-mario-release/R17-1412.33.0-a1-b29
+@param board: The board to test on. Ex: x86-mario
+@param pool: The pool of machines to utilize for scheduling. If pool=None
+ board is used.
+@param check_hosts: require appropriate live hosts to exist in the lab.
+@param SKIP_IMAGE: (optional) If present and True, don't re-image devices.
+"""
+
+import common
+from autotest_lib.server.cros.dynamic_suite import dynamic_suite
+
+args_dict['add_experimental'] = True
+args_dict['name'] = 'moblab_quick'
+args_dict['job'] = job
+
+dynamic_suite.reimage_and_run(**args_dict)