xref: /aosp_15_r20/development/tools/winscope/src/viewers/viewer_transactions/presenter_test.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1/*
2 * Copyright (C) 2022 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 ANYf 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 {InMemoryStorage} from 'common/in_memory_storage';
19import {TracePositionUpdate} from 'messaging/winscope_event';
20import {TraceBuilder} from 'test/unit/trace_builder';
21import {UnitTestUtils} from 'test/unit/utils';
22import {Parser} from 'trace/parser';
23import {Trace} from 'trace/trace';
24import {TraceType} from 'trace/trace_type';
25import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
26import {NotifyLogViewCallbackType} from 'viewers/common/abstract_log_viewer_presenter';
27import {AbstractLogViewerPresenterTest} from 'viewers/common/abstract_log_viewer_presenter_test';
28import {LogSelectFilter} from 'viewers/common/log_filters';
29import {LogHeader} from 'viewers/common/ui_data_log';
30import {Presenter} from './presenter';
31import {UiData} from './ui_data';
32
33class PresenterTransactionsTest extends AbstractLogViewerPresenterTest<UiData> {
34  override readonly expectedHeaders = [
35    {
36      header: new LogHeader(
37        {name: 'TX ID', cssClass: 'transaction-id right-align'},
38        new LogSelectFilter(Array.from({length: 1295}, () => '')),
39      ),
40    },
41    {
42      header: new LogHeader(
43        {name: 'VSYNC ID', cssClass: 'vsyncid right-align'},
44        new LogSelectFilter(Array.from({length: 710}, () => '')),
45      ),
46    },
47    {
48      header: new LogHeader(
49        {name: 'PID', cssClass: 'pid right-align'},
50        new LogSelectFilter(Array.from({length: 8}, () => '')),
51      ),
52      options: ['N/A', '0', '515', '1593', '2022', '2322', '2463', '3300'],
53    },
54    {
55      header: new LogHeader(
56        {name: 'UID', cssClass: 'uid right-align'},
57        new LogSelectFilter(Array.from({length: 6}, () => '')),
58      ),
59      options: ['N/A', '1000', '1003', '10169', '10235', '10239'],
60    },
61    {
62      header: new LogHeader(
63        {name: 'TYPE', cssClass: 'transaction-type'},
64        new LogSelectFilter(Array.from({length: 6}, () => '')),
65      ),
66      options: [
67        'DISPLAY_CHANGED',
68        'LAYER_ADDED',
69        'LAYER_CHANGED',
70        'LAYER_DESTROYED',
71        'LAYER_HANDLE_DESTROYED',
72        'NO_OP',
73      ],
74    },
75    {
76      header: new LogHeader(
77        {name: 'LAYER/DISP ID', cssClass: 'layer-or-display-id right-align'},
78        new LogSelectFilter(Array.from({length: 117}, () => '')),
79      ),
80    },
81    {
82      header: new LogHeader(
83        {name: 'Flags', cssClass: 'flags'},
84        new LogSelectFilter(
85          Array.from({length: 30}, () => ''),
86          true,
87          '250',
88          '100%',
89        ),
90      ),
91    },
92  ];
93  private trace: Trace<PropertyTreeNode> | undefined;
94  private positionUpdate: TracePositionUpdate | undefined;
95
96  override executeSpecializedTests() {
97    describe('Specialized tests', () => {
98      let presenter: Presenter;
99      let uiData: UiData;
100
101      beforeAll(async () => {
102        await this.setUpTestEnvironment();
103      });
104
105      beforeEach(async () => {
106        presenter = await this.createPresenter((newData: UiData) => {
107          uiData = newData;
108        });
109      });
110
111      it('keeps properties related to what has changed regardless of hide defaults', async () => {
112        await presenter.onAppEvent(this.getPositionUpdate());
113        await presenter.onLogEntryClick(10);
114        expect(
115          assertDefined(uiData.propertiesTree).getAllChildren().length,
116        ).toEqual(8);
117        expect(
118          uiData.propertiesTree?.getChildByName('transformToDisplayInverse'),
119        ).toBeDefined();
120        expect(
121          uiData.propertiesTree?.getChildByName('destinationFrame'),
122        ).toBeDefined();
123        expect(
124          uiData.propertiesTree?.getChildByName('autoRefresh'),
125        ).toBeDefined();
126
127        await presenter.onLogEntryClick(279);
128        expect(uiData.propertiesTree?.getChildByName('flags')).toBeDefined();
129        expect(uiData.propertiesTree?.getChildByName('parentId')).toBeDefined();
130        expect(
131          uiData.propertiesTree?.getChildByName('relativeParentId'),
132        ).toBeDefined();
133        expect(
134          uiData.propertiesTree?.getChildByName('transformToDisplayInverse'),
135        ).toBeUndefined();
136        expect(
137          uiData.propertiesTree?.getChildByName('destinationFrame'),
138        ).toBeUndefined();
139        expect(
140          uiData.propertiesTree?.getChildByName('autoRefresh'),
141        ).toBeUndefined();
142
143        await presenter.onLogEntryClick(584);
144        expect(uiData.propertiesTree?.getChildByName('flags')).toBeDefined();
145        expect(uiData.propertiesTree?.getChildByName('layerId')).toBeDefined();
146        expect(uiData.propertiesTree?.getChildByName('x')).toBeDefined();
147        expect(uiData.propertiesTree?.getChildByName('y')).toBeDefined();
148        expect(uiData.propertiesTree?.getChildByName('z')).toBeDefined();
149        expect(
150          uiData.propertiesTree?.getChildByName('parentId'),
151        ).toBeUndefined();
152        expect(
153          uiData.propertiesTree?.getChildByName('relativeParentId'),
154        ).toBeUndefined();
155      });
156    });
157  }
158
159  override async setUpTestEnvironment(): Promise<void> {
160    const parser = (await UnitTestUtils.getParser(
161      'traces/elapsed_and_real_timestamp/Transactions.pb',
162    )) as Parser<PropertyTreeNode>;
163    this.trace = new TraceBuilder<PropertyTreeNode>()
164      .setType(TraceType.TRANSACTIONS)
165      .setParser(parser)
166      .build();
167    this.positionUpdate = TracePositionUpdate.fromTraceEntry(
168      this.trace.getEntry(0),
169    );
170  }
171
172  override async createPresenterWithEmptyTrace(
173    callback: NotifyLogViewCallbackType<UiData>,
174  ): Promise<Presenter> {
175    const trace = UnitTestUtils.makeEmptyTrace(TraceType.TRANSACTIONS);
176    return new Presenter(trace, new InMemoryStorage(), callback);
177  }
178
179  override async createPresenter(
180    callback: NotifyLogViewCallbackType<UiData>,
181  ): Promise<Presenter> {
182    const presenter = new Presenter(
183      assertDefined(this.trace),
184      new InMemoryStorage(),
185      callback,
186    );
187    await presenter.onAppEvent(this.getPositionUpdate()); // trigger initialization
188    return presenter;
189  }
190
191  override getPositionUpdate(): TracePositionUpdate {
192    return assertDefined(this.positionUpdate);
193  }
194}
195
196describe('PresenterTransactions', () => {
197  new PresenterTransactionsTest().execute();
198});
199