1#
2# Copyright (C) 2017 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import json
18import logging
19
20from vts.runners.host import asserts
21from vts.runners.host import const
22
23VTS_TESTABILITY_CHECKER_32 = "/data/local/tmp/vts_testability_checker32"
24VTS_TESTABILITY_CHECKER_64 = "/data/local/tmp/vts_testability_checker64"
25
26
27def GetHalServiceName(shell, hal, bitness="64", run_as_compliance_test=False):
28    """Determine whether to run a VTS test against a HAL and get the service
29    names of the given hal if determine to run.
30
31    Args:
32        shell: the ShellMirrorObject to execute command on the device.
33        hal: string, the FQName of a HAL service, e.g.,
34                     android.hardware.foo@1.0::IFoo
35        bitness: string, the bitness of the test.
36        run_as_compliance_test: boolean, whether it is a compliance test.
37
38    Returns:
39        a boolean whether to run the test against the given hal.
40        a set containing all service names for the given HAL.
41    """
42
43    binary = VTS_TESTABILITY_CHECKER_64
44    if bitness == "32":
45        binary = VTS_TESTABILITY_CHECKER_32
46    # Give permission to execute the binary.
47    shell.Execute("chmod 755 %s" % binary)
48    cmd = binary
49    if run_as_compliance_test:
50        cmd += " -c "
51    cmd += " -b " + bitness + " " + hal
52    cmd_results = shell.Execute(str(cmd))
53    asserts.assertFalse(
54        any(cmd_results[const.EXIT_CODE]),
55        "Failed to run vts_testability_checker. ErrorCode: %s\n STDOUT: %s\n STDERR: %s\n"
56        % (cmd_results[const.EXIT_CODE][0], cmd_results[const.STDOUT][0],
57           cmd_results[const.STDERR][0]))
58    result = json.loads(cmd_results[const.STDOUT][0])
59    if str(result['Testable']).lower() == "true":
60        return True, set(result['instances'])
61    else:
62        return False, ()
63
64
65class CombMode(object):
66    """Enum for service name combination mode"""
67    FULL_PERMUTATION = 0
68    NAME_MATCH = 1
69    NO_COMBINATION = 2
70
71
72def GetServiceInstancesCombinations(services,
73                                    service_instances,
74                                    mode=CombMode.FULL_PERMUTATION):
75    """Create combinations of instances for all services.
76
77    Args:
78        services: list, all services used in the test. e.g. [s1, s2]
79        service_instances: dictionary, mapping of each service and the
80                           corresponding service name(s).
81                           e.g. {"s1": ["n1"], "s2": ["n2", "n3"]}
82        mode: CombMode that determines the combination strategy.
83
84    Returns:
85        A list of service instance combinations.
86    """
87    if mode == CombMode.FULL_PERMUTATION:
88        return GetServiceInstancesFullCombinations(services, service_instances)
89    elif mode == CombMode.NAME_MATCH:
90        return GetServiceInstancesNameMatchCombinations(
91            services, service_instances)
92    else:
93        logging.warning("Unknown comb mode, use default comb mode instead.")
94        return GetServiceInstancesFullCombinations(services, service_instances)
95
96
97def GetServiceInstancesFullCombinations(services, service_instances):
98    """Create all combinations of instances for all services.
99
100    Create full permutation for registered service instances, e.g.
101    s1 have instances (n1, n2) and s2 have instances (n3, n4), return all
102    permutations of s1 and s2, i.e. (s1/n1, s2/n3), (s1/n1, s2/n4),
103    (s1/n2, s2/n3) and (s1/n2, s2/n4)
104
105    Args:
106        services: list, all services used in the test. e.g. [s1, s2]
107        service_instances: dictionary, mapping of each service and the
108                           corresponding service name(s).
109                           e.g. {"s1": ["n1"], "s2": ["n2", "n3"]}
110
111    Returns:
112        A list of all service instance combinations.
113        e.g. [[s1/n1, s2/n2], [s1/n1, s2/n3]]
114    """
115    service_instance_combinations = []
116    if not services or (service_instances and type(service_instances) != dict):
117        return service_instance_combinations
118    service = services.pop()
119    pre_instance_combs = GetServiceInstancesCombinations(
120        services, service_instances)
121    if service not in service_instances or not service_instances[service]:
122        return pre_instance_combs
123    for name in service_instances[service]:
124        if not pre_instance_combs:
125            new_instance_comb = [service + '/' + name]
126            service_instance_combinations.append(new_instance_comb)
127        else:
128            for instance_comb in pre_instance_combs:
129                new_instance_comb = [service + '/' + name]
130                new_instance_comb.extend(instance_comb)
131                service_instance_combinations.append(new_instance_comb)
132
133    return service_instance_combinations
134
135
136def GetServiceInstancesNameMatchCombinations(services, service_instances):
137    """Create service instance combinations with same name for services.
138
139    Create combinations for services with the same instance name, e.g.
140    both s1 and s2 have two instances with name n1, and n2, return
141    the service instance combination of s1 and s2 with same instance name,
142    i.e. (s1/n1, s2/n1) and (s1/n2, s2/n2)
143
144    Args:
145        services: list, all services used in the test. e.g. [s1, s2]
146        service_instances: dictionary, mapping of each service and the
147                           corresponding service name(s).
148                           e.g. {"s1": ["n1", "n2"], "s2": ["n1", "n2"]}
149
150    Returns:
151        A list of service instance combinations.
152        e.g. [[s1/n1, s2/n1], [s1/n2, s2/n2]]
153    """
154    service_instance_combinations = []
155    instance_names = set()
156    for service in services:
157        if service not in service_instances or not service_instances[service]:
158            logging.error("Does not found instance for service: %s", service)
159            return []
160        if not instance_names:
161            instance_names = set(service_instances[service])
162        else:
163            instance_names.intersection_update(set(service_instances[service]))
164
165    for name in instance_names:
166        instance_comb = []
167        for service in services:
168            new_instance = [service + '/' + name]
169            instance_comb.extend(new_instance)
170        service_instance_combinations.append(instance_comb)
171
172    return service_instance_combinations
173