Merge "ASuite: update prebuilt acloud by uploader.(6637661)."
diff --git a/atest/linux-x86/atest-py3 b/atest/linux-x86/atest-py3
index 182e616..e0bb5d4 100755
--- a/atest/linux-x86/atest-py3
+++ b/atest/linux-x86/atest-py3
Binary files differ
diff --git a/atest/smoke_test_data/iterations.py b/atest/smoke_test_data/iterations.py
new file mode 100644
index 0000000..8b63e92
--- /dev/null
+++ b/atest/smoke_test_data/iterations.py
@@ -0,0 +1,100 @@
+# Copyright 2020, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import inspect
+import os
+import subprocess
+import sys
+
+import utils
+
+# Must assign TITLE so that smoke_tests is able to print it.
+TITLE = "Iteration Runs"
+ATEST = "atest"
+ARGS = "-c {}={} {}"
+ITERS = "--iterations"
+RERUN = "--rerun-until-failure"
+RETRY = "--retry-any-failure"
+RUNS = 5
+PASS_TEST_NAME = "atest_will_pass_tests"
+FAIL_TEST_NAME = "atest_will_fail_tests"
+
+
+class Iterations():
+ """Class of testing --iterations, --rerun-until-failure,
+ --retry-any-failure arguments."""
+
+ def run_test(self, test_arg, expected_pass):
+ """Define pass_tests/fail_tests from expect_pass.
+
+ The test result will be like running:
+ $ atest -c --retry-any-failure=5 atest_will_fail_tests
+
+ Args:
+ test_arg: A string of "--iterations", etc.
+ expected_pass: A boolean of expected test result.
+ """
+ if expected_pass:
+ args = ARGS.format(test_arg, RUNS, PASS_TEST_NAME)
+ pass_tests = 3
+ fail_tests = 0
+ else:
+ args = ARGS.format(test_arg, RUNS, FAIL_TEST_NAME)
+ pass_tests = 1
+ fail_tests = 2
+ # Define expected_threads from the argument.
+ if test_arg == ITERS:
+ expected_threads = (pass_tests+fail_tests) * RUNS
+ elif test_arg == RERUN:
+ expected_threads = (pass_tests+fail_tests) * 1
+ elif test_arg == RETRY:
+ expected_threads = pass_tests + (fail_tests*RUNS)
+
+ print('test{}'.format(test_arg).replace('-', '_'))
+ cmd = '{} {}'.format(ATEST, args)
+ print('Running: {}'.format(cmd))
+ # 1. Check return code
+ if expected_pass:
+ if subprocess.call(cmd, shell=True) != 0:
+ print('Failed testing:\n {}'.format(cmd))
+ sys.exit(1)
+ else:
+ if subprocess.call(cmd, shell=True) == 0:
+ print('Testing:\n{}\nis expected failure,'
+ ' but it passed.'.format(cmd))
+ sys.exit(1)
+
+ # 2. Should observe same threads in host_log.
+ if not utils.is_identical(expected_threads,
+ utils.get_test_threads(),
+ "Test threads"):
+ sys.exit(1)
+
+ # 3. Should observe same amount of passed/failed test in end_host_log.
+ if not utils.has_correct_passed_failed_counts(pass_tests, fail_tests):
+ sys.exit(1)
+
+
+def main():
+ utils.print_banner(TITLE)
+ iters = Iterations()
+ # There are 3 test arguments:
+ # "--iterations": runs atest_will_pass_test and expect pass.
+ # "--rerun-until-failure": runs atest_will_fail_test and expect fail.
+ # "--retry-any-failure": runs atest_will_fail_test and expect fail.
+ test_args = [(ITERS, True), (RERUN, False), (RETRY, False)]
+ for i, _ in enumerate(test_args):
+ print('\n[{}/{}] '.format(i+1, len(test_args)), end='')
+ utils.func_wrapper(iters.run_test, test_args[i])
+ utils.print_banner(TITLE, True)
diff --git a/atest/smoke_test_data/utils.py b/atest/smoke_test_data/utils.py
index 722a4a6..8690d75 100644
--- a/atest/smoke_test_data/utils.py
+++ b/atest/smoke_test_data/utils.py
@@ -129,3 +129,59 @@
args: A list of argument.
"""
func(*args)
+
+
+def get_test_threads():
+ """Get the number of running threads.
+
+ If 3 tests within the testable module, and the iteration number is 5,
+ the ModuleListener will appear 15 times.
+
+ Returns:
+ An integer that ModuleListener appears in host_log.
+ """
+ cmd = ('zcat /tmp/atest_result/LATEST/log/in*/host_log*.zip'
+ '| grep "ModuleListener" | wc -l')
+ return subprocess.check_output(cmd, shell=True).decode().strip()
+
+
+def get_passed_counts():
+ """Get the number of PASSED in end_host_log.
+
+ Returns:
+ An integer that shows PASSED in end_host_log.
+ """
+ cmd = ('zcat /tmp/atest_result/LATEST/log/in*/end_host_log*.zip'
+ '| grep PASSED | awk -F": " \'{{print $2}}\'')
+ return subprocess.check_output(cmd, shell=True).decode().strip()
+
+
+def get_failed_counts():
+ """Get the number of FAILED in end_host_log.
+
+ Returns:
+ An integer that shows PASSED in end_host_log.
+ """
+ cmd = ('zcat /tmp/atest_result/LATEST/log/in*/end_host_log*.zip'
+ '| grep FAILED | awk -F": " \'{{print $2}}\'')
+ return subprocess.check_output(cmd, shell=True).decode().strip()
+
+
+def has_correct_passed_failed_counts(passes, failures):
+ """Given desired passed and failed numbers, and return if they are the same
+ as expectation.
+
+ Args:
+ passes: An integer of desired passed number.
+ failures: An integer of desired failed number.
+
+ Returns:
+ A boolean: True if both passed/failed numbers match the result,
+ otherwise False.
+ """
+ if not is_identical(passes, get_passed_counts(), "PASSED number"):
+ return False
+ if not is_identical(failures, get_failed_counts(), "FAILED number"):
+ return False
+ return True
+
diff --git a/atest/smoke_tests b/atest/smoke_tests
index b894cbd..77b39f6 100755
--- a/atest/smoke_tests
+++ b/atest/smoke_tests
@@ -30,7 +30,7 @@
# Append more tests in the ordered list below, and provide a main() so that
# smoke_tests can invoke them directly.
# TODO: b/153411501 support --enable-file-patterns in the future.
-TESTS = ['lookup_tests', 'test_mappings', 'include_subdirs']
+TESTS = ['lookup_tests', 'test_mappings', 'include_subdirs', 'iterations']
if __name__ == '__main__':