xref: /aosp_15_r20/external/perfetto/python/test/resolver_unittest.py (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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