mirror of
https://fuchsia.googlesource.com/third_party/pigweed.googlesource.com/pigweed/pigweed
synced 2024-09-20 05:41:06 +00:00
e059107b73
Adds support for including a root metadata when creating a bundle. No-Docs-Update-Reason: module in early development. Change-Id: Ibdced04fd355e8f520d0d3ba6e5cf25276929d72 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/63640 Commit-Queue: Ali Zhang <alizhang@google.com> Reviewed-by: Joe Ethier <jethier@google.com>
202 lines
8.1 KiB
Python
202 lines
8.1 KiB
Python
# Copyright 2021 The Pigweed Authors
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
# use this file except in compliance with the License. You may obtain a copy of
|
|
# the License at
|
|
#
|
|
# https://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations under
|
|
# the License.
|
|
"""Unit tests for pw_software_update/update_bundle.py."""
|
|
|
|
from pathlib import Path
|
|
import tempfile
|
|
import unittest
|
|
|
|
from pw_software_update import update_bundle
|
|
from pw_software_update.tuf_pb2 import SignedRootMetadata, TargetsMetadata
|
|
|
|
|
|
class TargetsFromDirectoryTest(unittest.TestCase):
|
|
"""Test turning a directory into TUF targets."""
|
|
def test_excludes(self):
|
|
"""Checks that excludes are excluded."""
|
|
with tempfile.TemporaryDirectory() as tempdir_name:
|
|
temp_root = Path(tempdir_name)
|
|
foo_path = temp_root / 'foo.bin'
|
|
bar_path = temp_root / 'bar.bin'
|
|
baz_path = temp_root / 'baz.bin'
|
|
qux_path = temp_root / 'qux.exe'
|
|
for path in (foo_path, bar_path, baz_path, qux_path):
|
|
path.touch()
|
|
|
|
targets = update_bundle.targets_from_directory(
|
|
temp_root, exclude=(Path('foo.bin'), Path('baz.bin')))
|
|
|
|
self.assertNotIn('foo.bin', targets)
|
|
self.assertEqual(bar_path, targets['bar.bin'])
|
|
self.assertNotIn('baz.bin', targets)
|
|
self.assertEqual(qux_path, targets['qux.exe'])
|
|
|
|
def test_excludes_and_remapping(self):
|
|
"""Checks that remapping works, even in combination with excludes."""
|
|
with tempfile.TemporaryDirectory() as tempdir_name:
|
|
temp_root = Path(tempdir_name)
|
|
foo_path = temp_root / 'foo.bin'
|
|
bar_path = temp_root / 'bar.bin'
|
|
baz_path = temp_root / 'baz.bin'
|
|
qux_path = temp_root / 'qux.exe'
|
|
remap_paths = {
|
|
Path('foo.bin'): 'main',
|
|
Path('bar.bin'): 'backup',
|
|
Path('baz.bin'): 'tertiary',
|
|
}
|
|
for path in (foo_path, bar_path, baz_path, qux_path):
|
|
path.touch()
|
|
|
|
targets = update_bundle.targets_from_directory(
|
|
temp_root,
|
|
exclude=(Path('qux.exe'), ),
|
|
remap_paths=remap_paths)
|
|
|
|
self.assertEqual(foo_path, targets['main'])
|
|
self.assertEqual(bar_path, targets['backup'])
|
|
self.assertEqual(baz_path, targets['tertiary'])
|
|
self.assertNotIn('qux.exe', targets)
|
|
|
|
def test_incomplete_remapping_logs(self):
|
|
"""Checks that incomplete remappings log warnings."""
|
|
with tempfile.TemporaryDirectory() as tempdir_name:
|
|
temp_root = Path(tempdir_name)
|
|
foo_path = temp_root / 'foo.bin'
|
|
bar_path = temp_root / 'bar.bin'
|
|
foo_path.touch()
|
|
bar_path.touch()
|
|
remap_paths = {Path('foo.bin'): 'main'}
|
|
|
|
with self.assertLogs(level='WARNING') as log:
|
|
update_bundle.targets_from_directory(
|
|
temp_root,
|
|
exclude=(Path('qux.exe'), ),
|
|
remap_paths=remap_paths)
|
|
|
|
self.assertIn('Some remaps defined, but not "bar.bin"',
|
|
log.output[0])
|
|
|
|
def test_remap_of_missing_file(self):
|
|
"""Checks that remapping a missing file raises an error."""
|
|
with tempfile.TemporaryDirectory() as tempdir_name:
|
|
temp_root = Path(tempdir_name)
|
|
foo_path = temp_root / 'foo.bin'
|
|
foo_path.touch()
|
|
remap_paths = {
|
|
Path('foo.bin'): 'main',
|
|
Path('bar.bin'): 'backup',
|
|
}
|
|
|
|
with self.assertRaises(FileNotFoundError):
|
|
update_bundle.targets_from_directory(temp_root,
|
|
remap_paths=remap_paths)
|
|
|
|
|
|
class GenUnsignedUpdateBundleTest(unittest.TestCase):
|
|
"""Test the generation of unsigned update bundles."""
|
|
def test_bundle_generation(self):
|
|
"""Tests basic creation of an UpdateBundle."""
|
|
with tempfile.TemporaryDirectory() as tempdir_name:
|
|
temp_root = Path(tempdir_name)
|
|
foo_path = temp_root / 'foo.bin'
|
|
bar_path = temp_root / 'bar.bin'
|
|
baz_path = temp_root / 'baz.bin'
|
|
qux_path = temp_root / 'subdir' / 'qux.exe'
|
|
foo_bytes = b'\xf0\x0b\xa4'
|
|
bar_bytes = b'\x0b\xa4\x99'
|
|
baz_bytes = b'\xba\x59\x06'
|
|
qux_bytes = b'\x8a\xf3\x12'
|
|
foo_path.write_bytes(foo_bytes)
|
|
bar_path.write_bytes(bar_bytes)
|
|
baz_path.write_bytes(baz_bytes)
|
|
(temp_root / 'subdir').mkdir()
|
|
qux_path.write_bytes(qux_bytes)
|
|
targets = {
|
|
foo_path: 'foo',
|
|
bar_path: 'bar',
|
|
baz_path: 'baz',
|
|
qux_path: 'qux',
|
|
}
|
|
serialized_root_metadata_bytes = b'\x12\x34\x56\x78'
|
|
|
|
bundle = update_bundle.gen_unsigned_update_bundle(
|
|
targets,
|
|
targets_metadata_version=42,
|
|
root_metadata=SignedRootMetadata(
|
|
serialized_root_metadata=serialized_root_metadata_bytes))
|
|
|
|
self.assertEqual(foo_bytes, bundle.target_payloads['foo'])
|
|
self.assertEqual(bar_bytes, bundle.target_payloads['bar'])
|
|
self.assertEqual(baz_bytes, bundle.target_payloads['baz'])
|
|
self.assertEqual(qux_bytes, bundle.target_payloads['qux'])
|
|
targets_metadata = TargetsMetadata.FromString(
|
|
bundle.targets_metadata['targets'].serialized_targets_metadata)
|
|
self.assertEqual(targets_metadata.common_metadata.version, 42)
|
|
self.assertEqual(serialized_root_metadata_bytes,
|
|
bundle.root_metadata.serialized_root_metadata)
|
|
|
|
def test_persist_to_disk(self):
|
|
"""Tests persisting the TUF repo to disk for debugging"""
|
|
with tempfile.TemporaryDirectory() as tempdir_name:
|
|
temp_root = Path(tempdir_name)
|
|
foo_path = temp_root / 'foo.bin'
|
|
bar_path = temp_root / 'bar.bin'
|
|
baz_path = temp_root / 'baz.bin'
|
|
qux_path = temp_root / 'subdir' / 'qux.exe'
|
|
foo_bytes = b'\xf0\x0b\xa4'
|
|
bar_bytes = b'\x0b\xa4\x99'
|
|
baz_bytes = b'\xba\x59\x06'
|
|
qux_bytes = b'\x8a\xf3\x12'
|
|
foo_path.write_bytes(foo_bytes)
|
|
bar_path.write_bytes(bar_bytes)
|
|
baz_path.write_bytes(baz_bytes)
|
|
(temp_root / 'subdir').mkdir()
|
|
qux_path.write_bytes(qux_bytes)
|
|
targets = {
|
|
foo_path: 'foo',
|
|
bar_path: 'bar',
|
|
baz_path: 'baz',
|
|
qux_path: 'subdir/qux',
|
|
}
|
|
persist_path = temp_root / 'persisted'
|
|
|
|
update_bundle.gen_unsigned_update_bundle(targets,
|
|
persist=persist_path)
|
|
|
|
self.assertEqual(foo_bytes, (persist_path / 'foo').read_bytes())
|
|
self.assertEqual(bar_bytes, (persist_path / 'bar').read_bytes())
|
|
self.assertEqual(baz_bytes, (persist_path / 'baz').read_bytes())
|
|
self.assertEqual(qux_bytes,
|
|
(persist_path / 'subdir' / 'qux').read_bytes())
|
|
|
|
|
|
class ParseTargetArgTest(unittest.TestCase):
|
|
"""Test the parsing of target argument strings."""
|
|
def test_valid_arg(self):
|
|
"""Checks that valid remap strings are parsed correctly."""
|
|
file_path, target_name = update_bundle.parse_target_arg(
|
|
'foo.bin > main')
|
|
|
|
self.assertEqual(Path('foo.bin'), file_path)
|
|
self.assertEqual('main', target_name)
|
|
|
|
def test_invalid_arg_raises(self):
|
|
"""Checks that invalid remap string raise an error."""
|
|
with self.assertRaises(ValueError):
|
|
update_bundle.parse_target_arg('foo.bin main')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|