#
# Copyright (C) 2017 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 json
import logging
from vts.runners.host import asserts
from vts.runners.host import const
VTS_TESTABILITY_CHECKER_32 = "/data/local/tmp/vts_testability_checker32"
VTS_TESTABILITY_CHECKER_64 = "/data/local/tmp/vts_testability_checker64"
def GetHalServiceName(shell, hal, bitness="64", run_as_compliance_test=False):
"""Determine whether to run a VTS test against a HAL and get the service
names of the given hal if determine to run.
Args:
shell: the ShellMirrorObject to execute command on the device.
hal: string, the FQName of a HAL service, e.g.,
android.hardware.foo@1.0::IFoo
bitness: string, the bitness of the test.
run_as_compliance_test: boolean, whether it is a compliance test.
Returns:
a boolean whether to run the test against the given hal.
a set containing all service names for the given HAL.
"""
binary = VTS_TESTABILITY_CHECKER_64
if bitness == "32":
binary = VTS_TESTABILITY_CHECKER_32
# Give permission to execute the binary.
shell.Execute("chmod 755 %s" % binary)
cmd = binary
if run_as_compliance_test:
cmd += " -c "
cmd += " -b " + bitness + " " + hal
cmd_results = shell.Execute(str(cmd))
asserts.assertFalse(
any(cmd_results[const.EXIT_CODE]),
"Failed to run vts_testability_checker. ErrorCode: %s\n STDOUT: %s\n STDERR: %s\n"
% (cmd_results[const.EXIT_CODE][0], cmd_results[const.STDOUT][0],
cmd_results[const.STDERR][0]))
result = json.loads(cmd_results[const.STDOUT][0])
if str(result['Testable']).lower() == "true":
return True, set(result['instances'])
else:
return False, ()
class CombMode(object):
"""Enum for service name combination mode"""
FULL_PERMUTATION = 0
NAME_MATCH = 1
NO_COMBINATION = 2
def GetServiceInstancesCombinations(services,
service_instances,
mode=CombMode.FULL_PERMUTATION):
"""Create combinations of instances for all services.
Args:
services: list, all services used in the test. e.g. [s1, s2]
service_instances: dictionary, mapping of each service and the
corresponding service name(s).
e.g. {"s1": ["n1"], "s2": ["n2", "n3"]}
mode: CombMode that determines the combination strategy.
Returns:
A list of service instance combinations.
"""
if mode == CombMode.FULL_PERMUTATION:
return GetServiceInstancesFullCombinations(services, service_instances)
elif mode == CombMode.NAME_MATCH:
return GetServiceInstancesNameMatchCombinations(
services, service_instances)
else:
logging.warning("Unknown comb mode, use default comb mode instead.")
return GetServiceInstancesFullCombinations(services, service_instances)
def GetServiceInstancesFullCombinations(services, service_instances):
"""Create all combinations of instances for all services.
Create full permutation for registered service instances, e.g.
s1 have instances (n1, n2) and s2 have instances (n3, n4), return all
permutations of s1 and s2, i.e. (s1/n1, s2/n3), (s1/n1, s2/n4),
(s1/n2, s2/n3) and (s1/n2, s2/n4)
Args:
services: list, all services used in the test. e.g. [s1, s2]
service_instances: dictionary, mapping of each service and the
corresponding service name(s).
e.g. {"s1": ["n1"], "s2": ["n2", "n3"]}
Returns:
A list of all service instance combinations.
e.g. [[s1/n1, s2/n2], [s1/n1, s2/n3]]
"""
service_instance_combinations = []
if not services or (service_instances and type(service_instances) != dict):
return service_instance_combinations
service = services.pop()
pre_instance_combs = GetServiceInstancesCombinations(
services, service_instances)
if service not in service_instances or not service_instances[service]:
return pre_instance_combs
for name in service_instances[service]:
if not pre_instance_combs:
new_instance_comb = [service + '/' + name]
service_instance_combinations.append(new_instance_comb)
else:
for instance_comb in pre_instance_combs:
new_instance_comb = [service + '/' + name]
new_instance_comb.extend(instance_comb)
service_instance_combinations.append(new_instance_comb)
return service_instance_combinations
def GetServiceInstancesNameMatchCombinations(services, service_instances):
"""Create service instance combinations with same name for services.
Create combinations for services with the same instance name, e.g.
both s1 and s2 have two instances with name n1, and n2, return
the service instance combination of s1 and s2 with same instance name,
i.e. (s1/n1, s2/n1) and (s1/n2, s2/n2)
Args:
services: list, all services used in the test. e.g. [s1, s2]
service_instances: dictionary, mapping of each service and the
corresponding service name(s).
e.g. {"s1": ["n1", "n2"], "s2": ["n1", "n2"]}
Returns:
A list of service instance combinations.
e.g. [[s1/n1, s2/n1], [s1/n2, s2/n2]]
"""
service_instance_combinations = []
instance_names = set()
for service in services:
if service not in service_instances or not service_instances[service]:
logging.error("Does not found instance for service: %s", service)
return []
if not instance_names:
instance_names = set(service_instances[service])
else:
instance_names.intersection_update(set(service_instances[service]))
for name in instance_names:
instance_comb = []
for service in services:
new_instance = [service + '/' + name]
instance_comb.extend(new_instance)
service_instance_combinations.append(instance_comb)
return service_instance_combinations