1*6dbdd20aSAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker# 3*6dbdd20aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker# 7*6dbdd20aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker# 9*6dbdd20aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker# limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workerimport unittest 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.util import parse_trace_uri 18*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.util import to_list 19*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.util import _cs_list 20*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.util import and_list 21*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.util import or_list 22*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.resolver import _args_dict_from_uri 23*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.resolver import Constraint 24*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.resolver import ConstraintClass 25*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.resolver import TraceUriResolver 26*6dbdd20aSAndroid Build Coastguard Workerfrom perfetto.trace_uri_resolver.registry import ResolverRegistry 27*6dbdd20aSAndroid Build Coastguard Worker 28*6dbdd20aSAndroid Build Coastguard Worker 29*6dbdd20aSAndroid Build Coastguard Workerclass SimpleResolver(TraceUriResolver): 30*6dbdd20aSAndroid Build Coastguard Worker PREFIX = 'simple' 31*6dbdd20aSAndroid Build Coastguard Worker 32*6dbdd20aSAndroid Build Coastguard Worker def __init__(self, foo=None, bar=None): 33*6dbdd20aSAndroid Build Coastguard Worker self.foo = foo 34*6dbdd20aSAndroid Build Coastguard Worker self.bar = bar 35*6dbdd20aSAndroid Build Coastguard Worker 36*6dbdd20aSAndroid Build Coastguard Worker def foo_gen(self): 37*6dbdd20aSAndroid Build Coastguard Worker yield self.foo.encode() if self.foo else b'' 38*6dbdd20aSAndroid Build Coastguard Worker 39*6dbdd20aSAndroid Build Coastguard Worker def bar_gen(self): 40*6dbdd20aSAndroid Build Coastguard Worker yield self.bar.encode() if self.bar else b'' 41*6dbdd20aSAndroid Build Coastguard Worker 42*6dbdd20aSAndroid Build Coastguard Worker def resolve(self): 43*6dbdd20aSAndroid Build Coastguard Worker return [ 44*6dbdd20aSAndroid Build Coastguard Worker TraceUriResolver.Result(self.foo_gen()), 45*6dbdd20aSAndroid Build Coastguard Worker TraceUriResolver.Result( 46*6dbdd20aSAndroid Build Coastguard Worker self.bar_gen(), metadata={ 47*6dbdd20aSAndroid Build Coastguard Worker 'foo': self.foo, 48*6dbdd20aSAndroid Build Coastguard Worker 'bar': self.bar 49*6dbdd20aSAndroid Build Coastguard Worker }) 50*6dbdd20aSAndroid Build Coastguard Worker ] 51*6dbdd20aSAndroid Build Coastguard Worker 52*6dbdd20aSAndroid Build Coastguard Worker 53*6dbdd20aSAndroid Build Coastguard Workerclass RecursiveResolver(SimpleResolver): 54*6dbdd20aSAndroid Build Coastguard Worker PREFIX = 'recursive' 55*6dbdd20aSAndroid Build Coastguard Worker 56*6dbdd20aSAndroid Build Coastguard Worker def __init__(self, foo=None, bar=None): 57*6dbdd20aSAndroid Build Coastguard Worker super().__init__(foo=foo, bar=bar) 58*6dbdd20aSAndroid Build Coastguard Worker 59*6dbdd20aSAndroid Build Coastguard Worker def resolve(self): 60*6dbdd20aSAndroid Build Coastguard Worker return [ 61*6dbdd20aSAndroid Build Coastguard Worker TraceUriResolver.Result(self.foo_gen()), 62*6dbdd20aSAndroid Build Coastguard Worker TraceUriResolver.Result( 63*6dbdd20aSAndroid Build Coastguard Worker self.bar_gen(), metadata={ 64*6dbdd20aSAndroid Build Coastguard Worker 'foo': 'foo', 65*6dbdd20aSAndroid Build Coastguard Worker 'bar': 'bar' 66*6dbdd20aSAndroid Build Coastguard Worker }), 67*6dbdd20aSAndroid Build Coastguard Worker TraceUriResolver.Result(f'simple:foo={self.foo};bar={self.bar}'), 68*6dbdd20aSAndroid Build Coastguard Worker TraceUriResolver.Result(SimpleResolver(foo=self.foo, bar=self.bar)), 69*6dbdd20aSAndroid Build Coastguard Worker ] 70*6dbdd20aSAndroid Build Coastguard Worker 71*6dbdd20aSAndroid Build Coastguard Worker 72*6dbdd20aSAndroid Build Coastguard Workerclass TestResolver(unittest.TestCase): 73*6dbdd20aSAndroid Build Coastguard Worker 74*6dbdd20aSAndroid Build Coastguard Worker def test_simple_resolve(self): 75*6dbdd20aSAndroid Build Coastguard Worker registry = ResolverRegistry([SimpleResolver]) 76*6dbdd20aSAndroid Build Coastguard Worker 77*6dbdd20aSAndroid Build Coastguard Worker res = registry.resolve('simple:foo=x;bar=y') 78*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(len(res), 2) 79*6dbdd20aSAndroid Build Coastguard Worker 80*6dbdd20aSAndroid Build Coastguard Worker (foo_res, bar_res) = res 81*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_res, bar_res) 82*6dbdd20aSAndroid Build Coastguard Worker 83*6dbdd20aSAndroid Build Coastguard Worker (foo_res, bar_res) = registry.resolve(['simple:foo=x;bar=y']) 84*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_res, bar_res) 85*6dbdd20aSAndroid Build Coastguard Worker 86*6dbdd20aSAndroid Build Coastguard Worker resolver = SimpleResolver(foo='x', bar='y') 87*6dbdd20aSAndroid Build Coastguard Worker 88*6dbdd20aSAndroid Build Coastguard Worker (foo_res, bar_res) = registry.resolve(resolver) 89*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_res, bar_res) 90*6dbdd20aSAndroid Build Coastguard Worker 91*6dbdd20aSAndroid Build Coastguard Worker (foo_res, bar_res) = registry.resolve([resolver]) 92*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_res, bar_res) 93*6dbdd20aSAndroid Build Coastguard Worker 94*6dbdd20aSAndroid Build Coastguard Worker (foo_a, bar_b, foo_x, 95*6dbdd20aSAndroid Build Coastguard Worker bar_y) = registry.resolve(['simple:foo=a;bar=b', resolver]) 96*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_a, bar_b, foo='a', bar='b') 97*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_x, bar_y) 98*6dbdd20aSAndroid Build Coastguard Worker 99*6dbdd20aSAndroid Build Coastguard Worker def test_simple_resolve_missing_arg(self): 100*6dbdd20aSAndroid Build Coastguard Worker registry = ResolverRegistry([SimpleResolver]) 101*6dbdd20aSAndroid Build Coastguard Worker 102*6dbdd20aSAndroid Build Coastguard Worker (foo_res, bar_res) = registry.resolve('simple:foo=x') 103*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_res, bar_res, bar=None) 104*6dbdd20aSAndroid Build Coastguard Worker 105*6dbdd20aSAndroid Build Coastguard Worker (foo_res, bar_res) = registry.resolve('simple:bar=y') 106*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_res, bar_res, foo=None) 107*6dbdd20aSAndroid Build Coastguard Worker 108*6dbdd20aSAndroid Build Coastguard Worker (foo_res, bar_res) = registry.resolve('simple:') 109*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(foo_res, bar_res, foo=None, bar=None) 110*6dbdd20aSAndroid Build Coastguard Worker 111*6dbdd20aSAndroid Build Coastguard Worker def test_recursive_resolve(self): 112*6dbdd20aSAndroid Build Coastguard Worker registry = ResolverRegistry([SimpleResolver]) 113*6dbdd20aSAndroid Build Coastguard Worker registry.register(RecursiveResolver) 114*6dbdd20aSAndroid Build Coastguard Worker 115*6dbdd20aSAndroid Build Coastguard Worker res = registry.resolve('recursive:foo=x;bar=y') 116*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(len(res), 6) 117*6dbdd20aSAndroid Build Coastguard Worker 118*6dbdd20aSAndroid Build Coastguard Worker (non_rec_foo, non_rec_bar, rec_foo_str, rec_bar_str, rec_foo_obj, 119*6dbdd20aSAndroid Build Coastguard Worker rec_bar_obj) = res 120*6dbdd20aSAndroid Build Coastguard Worker 121*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result( 122*6dbdd20aSAndroid Build Coastguard Worker non_rec_foo, non_rec_bar, foo_metadata='foo', bar_metadata='bar') 123*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(rec_foo_str, rec_bar_str) 124*6dbdd20aSAndroid Build Coastguard Worker self._check_resolver_result(rec_foo_obj, rec_bar_obj) 125*6dbdd20aSAndroid Build Coastguard Worker 126*6dbdd20aSAndroid Build Coastguard Worker def test_parse_trace_uri(self): 127*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(parse_trace_uri('/foo/bar'), (None, '/foo/bar')) 128*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(parse_trace_uri('foo/bar'), (None, 'foo/bar')) 129*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(parse_trace_uri('/foo/b:ar'), (None, '/foo/b:ar')) 130*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(parse_trace_uri('./foo/b:ar'), (None, './foo/b:ar')) 131*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(parse_trace_uri('foo/b:ar'), ('foo/b', 'ar')) 132*6dbdd20aSAndroid Build Coastguard Worker 133*6dbdd20aSAndroid Build Coastguard Worker def test_to_list(self): 134*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(to_list(None), None) 135*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(to_list(1), [1]) 136*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(to_list('1'), ['1']) 137*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(to_list([]), []) 138*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(to_list([1]), [1]) 139*6dbdd20aSAndroid Build Coastguard Worker 140*6dbdd20aSAndroid Build Coastguard Worker def test_cs_list(self): 141*6dbdd20aSAndroid Build Coastguard Worker fn = 'col = {}'.format 142*6dbdd20aSAndroid Build Coastguard Worker sep = ' || ' 143*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(_cs_list(None, fn, 'FALSE', sep), 'TRUE') 144*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(_cs_list(None, fn, 'TRUE', sep), 'TRUE') 145*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(_cs_list([], fn, 'FALSE', sep), 'FALSE') 146*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(_cs_list([], fn, 'TRUE', sep), 'TRUE') 147*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(_cs_list([1], fn, 'FALSE', sep), '(col = 1)') 148*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(_cs_list([1, 2], fn, 'FALSE', sep), '(col = 1 || col = 2)') 149*6dbdd20aSAndroid Build Coastguard Worker 150*6dbdd20aSAndroid Build Coastguard Worker def test_and_list(self): 151*6dbdd20aSAndroid Build Coastguard Worker fn = 'col != {}'.format 152*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(and_list([1, 2], fn, 'FALSE'), '(col != 1 AND col != 2)') 153*6dbdd20aSAndroid Build Coastguard Worker 154*6dbdd20aSAndroid Build Coastguard Worker def test_or_list(self): 155*6dbdd20aSAndroid Build Coastguard Worker fn = 'col = {}'.format 156*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(or_list([1, 2], fn, 'FALSE'), '(col = 1 OR col = 2)') 157*6dbdd20aSAndroid Build Coastguard Worker 158*6dbdd20aSAndroid Build Coastguard Worker def test_args_dict_from_uri(self): 159*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(_args_dict_from_uri('foo:', {}), {}) 160*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual(_args_dict_from_uri('foo:bar=baz', {}), { 161*6dbdd20aSAndroid Build Coastguard Worker 'bar': 'baz', 162*6dbdd20aSAndroid Build Coastguard Worker }) 163*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 164*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key=v1,v2', {}), {'key': ['v1', 'v2']}) 165*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 166*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:bar=baz;key=v1,v2', {}), { 167*6dbdd20aSAndroid Build Coastguard Worker 'bar': 'baz', 168*6dbdd20aSAndroid Build Coastguard Worker 'key': ['v1', 'v2'] 169*6dbdd20aSAndroid Build Coastguard Worker }) 170*6dbdd20aSAndroid Build Coastguard Worker with self.assertRaises(ValueError): 171*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:=v1', {}) 172*6dbdd20aSAndroid Build Coastguard Worker with self.assertRaises(ValueError): 173*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key', {}) 174*6dbdd20aSAndroid Build Coastguard Worker with self.assertRaises(ValueError): 175*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key<', {}) 176*6dbdd20aSAndroid Build Coastguard Worker with self.assertRaises(ValueError): 177*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key<v1', {}) 178*6dbdd20aSAndroid Build Coastguard Worker with self.assertRaises(ValueError): 179*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key<v1', {'key': str}) 180*6dbdd20aSAndroid Build Coastguard Worker 181*6dbdd20aSAndroid Build Coastguard Worker type_hints = {'key': Constraint[str]} 182*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 183*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key=v1', type_hints), 184*6dbdd20aSAndroid Build Coastguard Worker {'key': ConstraintClass('v1', ConstraintClass.Op.EQ)}) 185*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 186*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key!=v1', type_hints), 187*6dbdd20aSAndroid Build Coastguard Worker {'key': ConstraintClass('v1', ConstraintClass.Op.NE)}) 188*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 189*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key<=v1', type_hints), 190*6dbdd20aSAndroid Build Coastguard Worker {'key': ConstraintClass('v1', ConstraintClass.Op.LE)}) 191*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 192*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key>=v1', type_hints), 193*6dbdd20aSAndroid Build Coastguard Worker {'key': ConstraintClass('v1', ConstraintClass.Op.GE)}) 194*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 195*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key>v1', type_hints), 196*6dbdd20aSAndroid Build Coastguard Worker {'key': ConstraintClass('v1', ConstraintClass.Op.GT)}) 197*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 198*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key<v1', type_hints), 199*6dbdd20aSAndroid Build Coastguard Worker {'key': ConstraintClass('v1', ConstraintClass.Op.LT)}) 200*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 201*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key>v1;key<=v2', type_hints), { 202*6dbdd20aSAndroid Build Coastguard Worker 'key': [ 203*6dbdd20aSAndroid Build Coastguard Worker ConstraintClass('v1', ConstraintClass.Op.GT), 204*6dbdd20aSAndroid Build Coastguard Worker ConstraintClass('v2', ConstraintClass.Op.LE) 205*6dbdd20aSAndroid Build Coastguard Worker ] 206*6dbdd20aSAndroid Build Coastguard Worker }) 207*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 208*6dbdd20aSAndroid Build Coastguard Worker _args_dict_from_uri('foo:key>=v1;key<v4;key!=v2;key!=v3', type_hints), { 209*6dbdd20aSAndroid Build Coastguard Worker 'key': [ 210*6dbdd20aSAndroid Build Coastguard Worker ConstraintClass('v1', ConstraintClass.Op.GE), 211*6dbdd20aSAndroid Build Coastguard Worker ConstraintClass('v4', ConstraintClass.Op.LT), 212*6dbdd20aSAndroid Build Coastguard Worker ConstraintClass('v2', ConstraintClass.Op.NE), 213*6dbdd20aSAndroid Build Coastguard Worker ConstraintClass('v3', ConstraintClass.Op.NE), 214*6dbdd20aSAndroid Build Coastguard Worker ] 215*6dbdd20aSAndroid Build Coastguard Worker }) 216*6dbdd20aSAndroid Build Coastguard Worker 217*6dbdd20aSAndroid Build Coastguard Worker def _check_resolver_result(self, 218*6dbdd20aSAndroid Build Coastguard Worker foo_res, 219*6dbdd20aSAndroid Build Coastguard Worker bar_res, 220*6dbdd20aSAndroid Build Coastguard Worker foo='x', 221*6dbdd20aSAndroid Build Coastguard Worker bar='y', 222*6dbdd20aSAndroid Build Coastguard Worker foo_metadata=None, 223*6dbdd20aSAndroid Build Coastguard Worker bar_metadata=None): 224*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 225*6dbdd20aSAndroid Build Coastguard Worker tuple(foo_res.generator), (foo.encode() if foo else ''.encode(),)) 226*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 227*6dbdd20aSAndroid Build Coastguard Worker tuple(bar_res.generator), (bar.encode() if bar else ''.encode(),)) 228*6dbdd20aSAndroid Build Coastguard Worker self.assertEqual( 229*6dbdd20aSAndroid Build Coastguard Worker bar_res.metadata, { 230*6dbdd20aSAndroid Build Coastguard Worker 'foo': foo_metadata if foo_metadata else foo, 231*6dbdd20aSAndroid Build Coastguard Worker 'bar': bar_metadata if bar_metadata else bar 232*6dbdd20aSAndroid Build Coastguard Worker }) 233