blob: 272dacd354417d488660c9cc0de63e0142501f48 [file]
#!/usr/bin/env python3
# Copyright 2026 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import shutil
import sys
import tempfile
import unittest
# Ensure the Chromium src directory is in sys.path when running standalone.
_SRC_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)
)
if _SRC_PATH not in sys.path:
sys.path.insert(0, _SRC_PATH)
from unittest import mock
from components.actor.tools.parse_actor_trace import (
extract_raw_payload,
extract_trace_to_dir,
find_or_build_protoc,
parse_actor_trace,
)
class ParseActorTraceTest(unittest.TestCase):
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self.temp_dir, ignore_errors=True)
@mock.patch('components.actor.tools.parse_actor_trace.parse_actor_trace')
def test_extract_trace_to_dir_parented(self, mock_parse_trace):
apc_payload_1 = b'fake_apc_proto_data_step_1'
jpg_payload_1 = bytes([0xFF, 0xD8, 0xFF, 0xE0]) + b'fake_jpeg_step_1'
apc_payload_2 = b'fake_apc_proto_data_step_2'
png_payload_2 = (
bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
+ b'fake_png_step_2'
)
mock_parse_trace.return_value = [
{
'parent_id': 10,
'name': 'PageContext',
'timestamp': 100,
'data': apc_payload_1,
},
{
'parent_id': 10,
'name': 'Screenshot',
'timestamp': 110,
'data': jpg_payload_1,
},
{
'parent_id': 20,
'name': 'PageContext',
'timestamp': 200,
'data': apc_payload_2,
},
{
'parent_id': 20,
'name': 'Screenshot',
'timestamp': 210,
'data': png_payload_2,
},
]
trace_file = os.path.join(self.temp_dir, 'test_trace.pb')
with open(trace_file, 'wb') as f:
f.write(b'fake_trace_data')
out_dir = os.path.join(self.temp_dir, 'extracted_parented')
extract_trace_to_dir(trace_file, out_dir)
# Check that files were created
step1_apc = os.path.join(out_dir, 'step1_apc.pb')
step1_img = os.path.join(out_dir, 'step1_screenshot.jpg')
step2_apc = os.path.join(out_dir, 'step2_apc.pb')
step2_img = os.path.join(out_dir, 'step2_screenshot.png')
self.assertTrue(os.path.exists(step1_apc))
self.assertTrue(os.path.exists(step1_img))
self.assertTrue(os.path.exists(step2_apc))
self.assertTrue(os.path.exists(step2_img))
with open(step1_apc, 'rb') as f:
self.assertEqual(f.read(), apc_payload_1)
with open(step1_img, 'rb') as f:
self.assertEqual(f.read(), jpg_payload_1)
with open(step2_apc, 'rb') as f:
self.assertEqual(f.read(), apc_payload_2)
with open(step2_img, 'rb') as f:
self.assertEqual(f.read(), png_payload_2)
@mock.patch('components.actor.tools.parse_actor_trace.parse_actor_trace')
def test_extract_trace_to_dir_unparented(self, mock_parse_trace):
apc_payload_1 = b'fake_apc_proto_data_step_1'
jpg_payload_1 = bytes([0xFF, 0xD8, 0xFF, 0xE0]) + b'fake_jpeg_step_1'
mock_parse_trace.return_value = [
{'name': 'PageContext', 'timestamp': 100, 'data': apc_payload_1},
{'name': 'Screenshot', 'timestamp': 110, 'data': jpg_payload_1},
]
trace_file = os.path.join(self.temp_dir, 'test_unparented.pb')
with open(trace_file, 'wb') as f:
f.write(b'fake_trace_data')
out_dir = os.path.join(self.temp_dir, 'extracted_unparented')
extract_trace_to_dir(trace_file, out_dir)
step1_apc = os.path.join(out_dir, 'step1_apc.pb')
step1_img = os.path.join(out_dir, 'step1_screenshot.jpg')
self.assertTrue(os.path.exists(step1_apc))
self.assertTrue(os.path.exists(step1_img))
@mock.patch('components.actor.tools.parse_actor_trace.parse_actor_trace')
def test_extract_trace_to_dir_mixed(self, mock_parse_trace):
apc_payload_1 = b'fake_apc_proto_data_step_1'
jpg_payload_1 = bytes([0xFF, 0xD8, 0xFF, 0xE0]) + b'fake_jpeg_step_1'
apc_payload_2 = b'fake_apc_proto_data_step_2'
jpg_payload_2 = bytes([0xFF, 0xD8, 0xFF, 0xE0]) + b'fake_jpeg_step_2'
mock_parse_trace.return_value = [
{
'parent_id': 10,
'name': 'PageContext',
'timestamp': 100,
'data': apc_payload_1,
},
{
'parent_id': 10,
'name': 'Screenshot',
'timestamp': 110,
'data': jpg_payload_1,
},
{
'name': 'PageContext',
'timestamp': 200,
'data': apc_payload_2,
},
{
'name': 'Screenshot',
'timestamp': 210,
'data': jpg_payload_2,
},
]
trace_file = os.path.join(self.temp_dir, 'test_mixed.pb')
with open(trace_file, 'wb') as f:
f.write(b'fake_trace_data')
out_dir = os.path.join(self.temp_dir, 'extracted_mixed')
extract_trace_to_dir(trace_file, out_dir)
step1_apc = os.path.join(out_dir, 'step1_apc.pb')
step1_img = os.path.join(out_dir, 'step1_screenshot.jpg')
step2_apc = os.path.join(out_dir, 'step2_apc.pb')
step2_img = os.path.join(out_dir, 'step2_screenshot.jpg')
self.assertTrue(os.path.exists(step1_apc))
self.assertTrue(os.path.exists(step1_img))
self.assertTrue(os.path.exists(step2_apc))
self.assertTrue(os.path.exists(step2_img))
def test_extract_raw_payload(self):
raw_binary = b'abcd\x00\x01\x02\x03'
self.assertEqual(extract_raw_payload(raw_binary), raw_binary)
b64_str = 'aGVsbG8gd29ybGQ='
self.assertEqual(extract_raw_payload(b64_str), b'hello world')
def test_find_or_build_protoc(self):
# Test non-existent build directory returns None or builds
non_existent = os.path.join(self.temp_dir, 'no_such_dir')
self.assertIsNone(find_or_build_protoc(non_existent))
if __name__ == '__main__':
unittest.main()