• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2024 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 {assertDefined} from 'common/assert_utils';
18import {
19  TimestampConverterUtils,
20  timestampEqualityTester,
21} from 'common/time/test_utils';
22import {TraceSearchQueryFailed} from 'messaging/user_warnings';
23import {ParserSurfaceFlinger} from 'parsers/surface_flinger/perfetto/parser_surface_flinger';
24import {UserNotifierChecker} from 'test/unit/user_notifier_checker';
25import {UnitTestUtils} from 'test/unit/utils';
26import {CoarseVersion} from 'trace/coarse_version';
27import {TraceType} from 'trace/trace_type';
28import {ParserSearch} from './parser_search';
29
30describe('ParserSearch', () => {
31  let userNotifierChecker: UserNotifierChecker;
32  let parser: ParserSearch;
33
34  beforeAll(() => {
35    userNotifierChecker = new UserNotifierChecker();
36    jasmine.addCustomEqualityTester(timestampEqualityTester);
37  });
38
39  afterEach(() => {
40    userNotifierChecker.reset();
41  });
42
43  describe('valid query with timestamps', () => {
44    beforeAll(async () => {
45      parser = await createParser(
46        'SELECT * FROM surfaceflinger_layers_snapshot',
47      );
48    });
49
50    afterEach(() => {
51      userNotifierChecker.expectNone();
52    });
53
54    it('has expected trace type', () => {
55      expect(parser.getTraceType()).toEqual(TraceType.SEARCH);
56    });
57
58    it('has expected coarse version', () => {
59      expect(parser.getCoarseVersion()).toEqual(CoarseVersion.LATEST);
60    });
61
62    it('has expected descriptors', () => {
63      expect(parser.getDescriptors()).toEqual([
64        'SELECT * FROM surfaceflinger_layers_snapshot',
65      ]);
66    });
67
68    it('has length entries equal to number of rows', () => {
69      expect(parser.getLengthEntries()).toEqual(21);
70    });
71
72    it('provides timestamps', () => {
73      const expected = [
74        TimestampConverterUtils.makeElapsedTimestamp(14500282843n),
75        TimestampConverterUtils.makeElapsedTimestamp(14631249355n),
76        TimestampConverterUtils.makeElapsedTimestamp(15403446377n),
77      ];
78      const actual = assertDefined(parser.getTimestamps()).slice(0, 3);
79      expect(actual).toEqual(expected);
80      userNotifierChecker.expectNone();
81    });
82
83    it('provides query result', async () => {
84      const entry = await parser.getEntry(0);
85      expect(entry.numRows()).toEqual(21);
86      const firstRow = entry.iter({});
87      expect(firstRow.get('id')).toEqual(0n);
88      expect(firstRow.get('ts')).toEqual(14500282843n);
89      expect(firstRow.get('arg_set_id')).toEqual(6193n);
90    });
91  });
92
93  describe('valid query without timestamps', () => {
94    beforeAll(async () => {
95      parser = await createParser('SELECT * FROM surfaceflinger_layer');
96      userNotifierChecker.expectNone();
97    });
98
99    afterEach(() => {
100      userNotifierChecker.expectNone();
101    });
102
103    it('has length entries equal to 1 so query result can be accessed', () => {
104      expect(parser.getLengthEntries()).toEqual(1);
105    });
106
107    it('provides one invalid timestamp so query result can be accessed', () => {
108      expect(parser.getTimestamps()).toEqual([
109        TimestampConverterUtils.makeZeroTimestamp(),
110      ]);
111    });
112
113    it('provides query result', async () => {
114      const entry = await parser.getEntry(0);
115      expect(entry.numRows()).toEqual(1815);
116      const firstRow = entry.iter({});
117      expect(firstRow.get('id')).toEqual(0n);
118      expect(firstRow.get('arg_set_id')).toEqual(0n);
119      expect(firstRow.get('snapshot_id')).toEqual(0n);
120    });
121  });
122
123  describe('valid query without rows', () => {
124    beforeAll(async () => {
125      parser = await createParser('SELECT * FROM surfaceflinger_transactions');
126    });
127
128    afterEach(() => {
129      userNotifierChecker.expectNone();
130    });
131
132    it('has length entries equal to 1 so query result can be accessed', () => {
133      expect(parser.getLengthEntries()).toEqual(1);
134    });
135
136    it('provides one invalid timestamp so query result can be accessed', () => {
137      expect(parser.getTimestamps()).toEqual([
138        TimestampConverterUtils.makeZeroTimestamp(),
139      ]);
140    });
141
142    it('provides query result', async () => {
143      const entry = await parser.getEntry(0);
144      expect(entry.columns()).toEqual([
145        'id',
146        'ts',
147        'arg_set_id',
148        'base64_proto_id',
149      ]);
150      expect(entry.numRows()).toEqual(0);
151    });
152  });
153
154  it('notifies user of parsing error before throwing error', async () => {
155    const createFailingParser = () => createParser('SELECT * FROM fake_table');
156    await expectAsync(createFailingParser()).toBeRejected();
157    userNotifierChecker.reset();
158    try {
159      parser = await createFailingParser();
160    } catch (e) {
161      userNotifierChecker.expectNotified([
162        new TraceSearchQueryFailed((e as Error).message),
163      ]);
164    }
165  });
166
167  async function createParser(query: string): Promise<ParserSearch> {
168    await (
169      (await UnitTestUtils.getPerfettoParser(
170        TraceType.SURFACE_FLINGER,
171        'traces/perfetto/layers_trace.perfetto-trace',
172      )) as ParserSurfaceFlinger
173    ).parse();
174    parser = new ParserSearch(query, UnitTestUtils.getTimestampConverter());
175    await parser.parse();
176    return parser;
177  }
178});
179