def test_layer_from_demo_sendstreams(self): # `btrfs_diff.demo_sendstream` produces a subvolume send-stream with # fairly thorough coverage of filesystem features. This test grabs # that send-stream, receives it into an `image_layer`, and validates # that the send-stream of the **received** volume has the same # rendering as the original send-stream was supposed to have. # # In other words, besides testing `image_sendstream_layer`, this is # also a test of idempotence for btrfs send+receive. # # Notes: # - `compiler/tests/TARGETS` explains why `mutate_ops` is not here. # - Currently, `mutate_ops` also uses `--no-data`, which would # break this test of idempotence. for original_name, subvol_name, mount_config in [ ('create_ops', 'create_ops', None), ('create_ops', 'create_ops-from-dir', None), ('create_ops', 'create_ops-from-layer', None), ('create_ops', 'create_ops-alias', { 'build_source': { 'type': 'layer', 'source': '//fs_image/compiler/tests:create_ops', } }), ]: with self.target_subvol( subvol_name, mount_config=mount_config, ) as sv: self.assertEqual( render_demo_subvols(**{original_name: original_name}), render_sendstream(sv.mark_readonly_and_get_sendstream()), )
def _render_sendstream_path(path): if path.endswith('.zst'): data = subprocess.check_output( ['zstd', '--decompress', '--stdout', path] ) else: with open(path, 'rb') as infile: data = infile.read() return render_sendstream(data)
def test_receive(self, temp_subvols): new_subvol_name = 'differs_from_create_ops' sv = temp_subvols.caller_will_create(new_subvol_name) with open(Path(__file__).dirname() / 'create_ops.sendstream') as f, \ sv.receive(f): pass self.assertEqual( render_demo_subvols(create_ops=new_subvol_name), render_sendstream(sv.mark_readonly_and_get_sendstream()), )
def _assert_sendstream_files_equal(self, path1: str, path2: str): renders = [] for path in [path1, path2]: if path.endswith('.zst'): data = subprocess.check_output( ['zstd', '--decompress', '--stdout', path]) else: with open(path, 'rb') as infile: data = infile.read() renders.append(render_sendstream(data)) self.assertEqual(*renders)
def test_check_layers(self): meta = { 'meta': [ '(Dir)', { 'private': [ '(Dir)', { 'opts': [ '(Dir)', { 'artifacts_may_require_repo': ['(File d2)'], } ] } ] } ] } # The parent has a couple of directories. self.assertEqual( ['(Dir)', { 'a': ['(Dir)', { 'b': ['(Dir)', {}] }], **meta }], render_sendstream( find_built_subvol(self._resource_path( 'parent')).mark_readonly_and_get_sendstream()), ) # The child is near-empty because the `remove_paths` cleaned it up. self.assertEqual( ['(Dir)', { **meta }], render_sendstream( find_built_subvol(self._resource_path( 'child')).mark_readonly_and_get_sendstream()), )
def test_receive_sendstream(self): item = ReceiveSendstreamItem( from_target='t', source=Path(__file__).dirname() / 'create_ops.sendstream', ) self.assertEqual(PhaseOrder.MAKE_SUBVOL, item.phase_order()) with TempSubvolumes(sys.argv[0]) as temp_subvolumes: new_subvol_name = 'differs_from_create_ops' subvol = temp_subvolumes.caller_will_create(new_subvol_name) item.get_phase_builder([item], DUMMY_LAYER_OPTS)(subvol) self.assertEqual( render_demo_subvols(create_ops=new_subvol_name), render_sendstream(subvol.mark_readonly_and_get_sendstream()), )
def test_check_layers(self): # The parent has a couple of directories. self.assertEqual( [ '(Dir)', { 'a': ['(Dir)', { 'b': ['(Dir)', {}] }], 'meta': ['(Dir)', {}], } ], render_sendstream( find_built_subvol(self._resource_path( 'parent')).mark_readonly_and_get_sendstream()), ) # The child is near-empty because the `remove_paths` cleaned it up. self.assertEqual( ['(Dir)', { 'meta': ['(Dir)', {}] }], render_sendstream( find_built_subvol(self._resource_path( 'child')).mark_readonly_and_get_sendstream()), )
def test_layer_from_demo_sendstreams(self): # `btrfs_diff.demo_sendstream` produces a subvolume send-stream with # fairly thorough coverage of filesystem features. This test grabs # that send-stream, receives it into an `image_layer`, and validates # that the send-stream of the **received** volume has the same # rendering as the original send-stream was supposed to have. # # In other words, besides testing `image_layer`'s `from_sendstream`, # this is also a test of idempotence for btrfs send+receive. # # Notes: # - `compiler/tests/TARGETS` explains why `mutate_ops` is not here. # - Currently, `mutate_ops` also uses `--no-data`, which would # break this test of idempotence. for op in ['create_ops']: with self.target_subvol(op) as sv: self.assertEqual( render_demo_subvols(**{op: True}), render_sendstream(sv.mark_readonly_and_get_sendstream()), )
def test_write_to_tarball(self, temp_subvols): # create a subvol from a demo sendstream, tar it, untar into a new # subvol, then compare the two demo_sv_name = 'demo_sv' demo_sv = temp_subvols.caller_will_create(demo_sv_name) with open(Path(__file__).dirname() / 'create_ops.sendstream') as f, \ demo_sv.receive(f): pass unpacked_sv = temp_subvols.create('subvol') with tempfile.NamedTemporaryFile() as tar_file: with demo_sv.write_to_tarball(tar_file): pass demo_sv.run_as_root([ 'tar', 'xzf', tar_file.name, '--xattrs', '-C', unpacked_sv.path(), ]) demo_render = render_demo_subvols(create_ops=demo_sv_name) # Tar does not preserve the original's cloned extents of # zeros demo_render[1]['56KB_nuls'] = ['(File d57344)'] demo_render[1]['56KB_nuls_clone'] = ['(File d57344)'] # Tar des not preserve unix domain sockets, as these are usable only for # the lifetime of the associated process and should therefore be safe to # ignore. demo_render[1].pop('unix_sock') self.assertEqual( demo_render, render_sendstream(unpacked_sv.mark_readonly_and_get_sendstream()), )
def test_build_appliance(self): with self.target_subvol('validates-build-appliance') as sv: r = render_sendstream(sv.mark_readonly_and_get_sendstream()) ino, = _pop_path(r, 'bin/sh') # Busybox from `rpm-test-milk` # NB: We changed permissions on this at some point, but after # the migration diffs land, the [75] can become a 5. self.assertRegex(ino, r'^\(File m[75]55 d[0-9]+\)$') ino, = _pop_path(r, 'var/log/yum.log') self.assertRegex(ino, r'^\(File m600 d[0-9]+\)$') # Ignore a bunch of yum & RPM spam for ignore_dir in [ 'usr/lib/.build-id', 'var/cache/yum', 'var/lib/rpm', 'var/lib/yum', ]: ino, _ = _pop_path(r, ignore_dir) self.assertEqual('(Dir)', ino) self.assertEqual( [ '(Dir)', { 'bin': ['(Dir)', {}], 'dev': ['(Dir)', {}], 'meta': [ '(Dir)', { 'private': [ '(Dir)', { 'opts': [ '(Dir)', { 'artifacts_may_require_repo': ['(File d2)'], } ] } ] } ], 'usr': [ '(Dir)', { 'lib': ['(Dir)', {}], 'share': [ '(Dir)', { 'rpm_test': [ '(Dir)', { 'milk.txt': ['(File d12)'], # From the `rpm-test-milk` post-install script 'post.txt': ['(File d6)'], } ], } ], } ], 'var': [ '(Dir)', { 'cache': ['(Dir)', {}], 'lib': ['(Dir)', {}], 'log': ['(Dir)', {}], 'tmp': ['(Dir)', {}], } ], } ], r)
def _render_subvol(subvol: 'Subvol'): rendered = render_sendstream(subvol.mark_readonly_and_get_sendstream()) subvol.set_readonly(False) # YES, all our subvolumes are read-write. return rendered
def _assert_sendstream_files_equal(self, path1: str, path2: str): renders = [] for path in [path1, path2]: with open(path, 'rb') as infile: renders.append(render_sendstream(infile.read())) self.assertEqual(*renders)