diff --git a/ops/model.py b/ops/model.py
index 1d88eaa..cd1733e 100644
--- a/ops/model.py
+++ b/ops/model.py
@@ -2275,6 +2275,9 @@ class Container:
             try:
                 for info in Container._list_recursive(local_list, source_path):
                     dstpath = self._build_destpath(info.path, source_path, dest_dir)
+                    if info.type is pebble.FileType.DIRECTORY:
+                        self.make_dir(dstpath, make_parents=True)
+                        continue
                     with open(info.path) as src:
                         self.push(
                             dstpath,
@@ -2352,6 +2355,9 @@ class Container:
             try:
                 for info in Container._list_recursive(self.list_files, source_path):
                     dstpath = self._build_destpath(info.path, source_path, dest_dir)
+                    if info.type is pebble.FileType.DIRECTORY:
+                        dstpath.mkdir(parents=True, exist_ok=True)
+                        continue
                     dstpath.parent.mkdir(parents=True, exist_ok=True)
                     with self.pull(info.path, encoding=None) as src:
                         with dstpath.open(mode='wb') as dst:
@@ -2406,6 +2412,9 @@ class Container:
 
         for info in list_func(path):
             if info.type is pebble.FileType.DIRECTORY:
+                # Yield the directory to ensure empty directories are created, then
+                # all of the contained files.
+                yield info
                 yield from Container._list_recursive(list_func, Path(info.path))
             elif info.type in (pebble.FileType.FILE, pebble.FileType.SYMLINK):
                 yield info

diff --git a/test/test_model.py b/test/test_model.py
index d9ea9d7..365ddff 100755
--- a/test/test_model.py
+++ b/test/test_model.py
@@ -981,14 +981,18 @@ class PushPullCase:
                  files: typing.List[str],
                  want: typing.Optional[typing.Set[str]] = None,
                  dst: typing.Optional[str] = None,
-                 errors: typing.Optional[typing.Set[str]] = None):
+                 errors: typing.Optional[typing.Set[str]] = None,
+                 dirs: typing.Optional[typing.Set[str]] = None,
+                 want_dirs: typing.Optional[typing.Set[str]] = None):
         self.pattern = None
         self.dst = dst
         self.errors = errors or set()
         self.name = name
         self.path = path
         self.files = files
+        self.dirs = dirs or set()
         self.want = want or set()
+        self.want_dirs = want_dirs or set()
 
 
 recursive_list_cases = [
@@ -996,13 +1000,13 @@ recursive_list_cases = [
         name='basic recursive list',
         path='/',
         files=['/foo/bar.txt', '/baz.txt'],
-        want={'/foo/bar.txt', '/baz.txt'},
+        want={'/foo', '/foo/bar.txt', '/baz.txt'},
     ),
     PushPullCase(
         name='basic recursive list reverse',
         path='/',
         files=['/baz.txt', '/foo/bar.txt'],
-        want={'/foo/bar.txt', '/baz.txt'},
+        want={'/foo', '/foo/bar.txt', '/baz.txt'},
     ),
     PushPullCase(
         name='directly list a (non-directory) file',
@@ -1156,6 +1160,14 @@ recursive_push_pull_cases = [
         files=['/foo/bar/baz.txt', '/foo/foobar.txt', '/quux.txt'],
         want={'/baz/foobar.txt', '/baz/bar/baz.txt'},
     ),
+    PushPullCase(
+        name='push/pull an empty directory',
+        path='/foo',
+        dst='/foobar',
+        files=[],
+        dirs={'/foo/baz'},
+        want_dirs={'/foobar/foo/baz'},
+    ),
 ]
 
 
@@ -1179,6 +1191,10 @@ def test_recursive_push_and_pull(case: PushPullCase):
         os.makedirs(os.path.dirname(fpath), exist_ok=True)
         with open(fpath, 'w') as f:
             f.write('hello')
+    if case.dirs:
+        for directory in case.dirs:
+            fpath = os.path.join(push_src.name, directory[1:])
+            os.makedirs(fpath, exist_ok=True)
 
     # test push
     if isinstance(case.path, list):
@@ -1204,11 +1220,16 @@ def test_recursive_push_and_pull(case: PushPullCase):
         f'push_path gave wrong expected errors: want {case.errors}, got {errors}'
     for fpath in case.want:
         assert c.exists(fpath), f'push_path failed: file {fpath} missing at destination'
+    for fdir in case.want_dirs:
+        assert c.isdir(fdir), f'push_path failed: dir {fdir} missing at destination'
 
     # create pull test case filesystem structure
     pull_dst = tempfile.TemporaryDirectory()
     for fpath in case.files:
         c.push(fpath, 'hello', make_dirs=True)
+    if case.dirs:
+        for directory in case.dirs:
+            c.make_dir(directory, make_parents=True)
 
     # test pull
     errors: typing.Set[str] = set()
@@ -1223,6 +1244,8 @@ def test_recursive_push_and_pull(case: PushPullCase):
         f'pull_path gave wrong expected errors: want {case.errors}, got {errors}'
     for fpath in case.want:
         assert c.exists(fpath), f'pull_path failed: file {fpath} missing at destination'
+    for fdir in case.want_dirs:
+        assert c.isdir(fdir), f'pull_path failed: dir {fdir} missing at destination'
 
 
 @pytest.mark.parametrize('case', [
diff --git a/test/test_testing.py b/test/test_testing.py
index d49c4a9..e28ef55 100644
--- a/test/test_testing.py
+++ b/test/test_testing.py
@@ -4574,11 +4574,13 @@ class TestFilesystem(unittest.TestCase, _TestingPebbleClientMixin):
             (tempdir / "foo/bar").mkdir(parents=True)
             (tempdir / "foo/test").write_text("test")
             (tempdir / "foo/bar/foobar").write_text("foobar")
+            (tempdir / "foo/baz").mkdir(parents=True)
             self.container.push_path(tempdir / "foo", "/tmp")
 
             self.assertTrue((self.root / "tmp").is_dir())
             self.assertTrue((self.root / "tmp/foo").is_dir())
             self.assertTrue((self.root / "tmp/foo/bar").is_dir())
+            self.assertTrue((self.root / "tmp/foo/baz").is_dir())
             self.assertEqual((self.root / "tmp/foo/test").read_text(), "test")
             self.assertEqual((self.root / "tmp/foo/bar/foobar").read_text(), "foobar")
 
@@ -4595,16 +4597,14 @@ class TestFilesystem(unittest.TestCase, _TestingPebbleClientMixin):
     def test_pull_path(self):
         (self.root / "foo").mkdir()
         (self.root / "foo/bar").write_text("bar")
-        # TODO: pull_path doesn't pull empty directories
-        # https://github.com/canonical/operator/issues/968
-        # (self.root / "foobar").mkdir()
+        (self.root / "foobar").mkdir()
         (self.root / "test").write_text("test")
         with tempfile.TemporaryDirectory() as temp:
             tempdir = pathlib.Path(temp)
             self.container.pull_path("/", tempdir)
             self.assertTrue((tempdir / "foo").is_dir())
             self.assertEqual((tempdir / "foo/bar").read_text(), "bar")
-            # self.assertTrue((tempdir / "foobar").is_dir())
+            self.assertTrue((tempdir / "foobar").is_dir())
             self.assertEqual((tempdir / "test").read_text(), "test")
 
     def test_list_files(self):

pull_path doesn't retrieve empty directories
Per [this comment](https://github.com/canonical/operator/pull/960#issuecomment-1628001631), `Container.pull_path` doesn't retrieve empty directories. This seems like a bug, not a feature (Git's behaviour notwithstanding). From a quick look at the code, I think `push_path` will have a similar problem.

We probably need to change the `_list_recursive` helper to also yield directories (before recursing), and the callers test if it's a directory and create it, otherwise copy the file.
test/test_model.py::test_recursive_list[case0] test/test_model.py::test_recursive_list[case1] test/test_model.py::test_recursive_push_and_pull[case9] test/test_testing.py::TestFilesystem::test_pull_path test/test_testing.py::TestFilesystem::test_push_path
test/test_model.py::TestModel::test_active_message_default test/test_model.py::TestModel::test_app_immutable test/test_model.py::TestModel::test_app_relation_data_modify_local_as_leader test/test_model.py::TestModel::test_app_relation_data_modify_local_as_minion test/test_model.py::TestModel::test_base_status_instance_raises test/test_model.py::TestModel::test_config test/test_model.py::TestModel::test_config_immutable test/test_model.py::TestModel::test_get_app_relation_data test/test_model.py::TestModel::test_get_relation test/test_model.py::TestModel::test_invalid_type_relation_data test/test_model.py::TestModel::test_is_leader test/test_model.py::TestModel::test_local_set_valid_app_status test/test_model.py::TestModel::test_local_set_valid_unit_status test/test_model.py::TestModel::test_model_attributes test/test_model.py::TestModel::test_model_name_from_backend test/test_model.py::TestModel::test_our_unit_is_our test/test_model.py::TestModel::test_peer_relation_app test/test_model.py::TestModel::test_pod_immutable test/test_model.py::TestModel::test_pod_spec test/test_model.py::TestModel::test_relation_data_access_peer_leader test/test_model.py::TestModel::test_relation_data_access_peer_minion test/test_model.py::TestModel::test_relation_data_del_key test/test_model.py::TestModel::test_relation_data_del_missing_key test/test_model.py::TestModel::test_relation_data_modify_our test/test_model.py::TestModel::test_relation_data_modify_remote test/test_model.py::TestModel::test_relation_data_type_check test/test_model.py::TestModel::test_relation_local_app_data_readability_follower test/test_model.py::TestModel::test_relation_local_app_data_readability_leader test/test_model.py::TestModel::test_relation_no_units test/test_model.py::TestModel::test_relation_set_fail test/test_model.py::TestModel::test_relations_immutable test/test_model.py::TestModel::test_relations_keys test/test_model.py::TestModel::test_remote_app_relation_data test/test_model.py::TestModel::test_remote_app_status test/test_model.py::TestModel::test_remote_unit_status test/test_model.py::TestModel::test_remote_units_is_our test/test_model.py::TestModel::test_resources test/test_model.py::TestModel::test_resources_immutable test/test_model.py::TestModel::test_run_error test/test_model.py::TestModel::test_set_app_status_invalid test/test_model.py::TestModel::test_set_app_status_non_leader_raises test/test_model.py::TestModel::test_set_unit_status_invalid test/test_model.py::TestModel::test_status_eq test/test_model.py::TestModel::test_status_repr test/test_model.py::TestModel::test_storage test/test_model.py::TestModel::test_storages_immutable test/test_model.py::TestModel::test_unit_immutable test/test_model.py::TestModel::test_unit_relation_data test/test_model.py::TestModel::test_workload_version test/test_model.py::TestModel::test_workload_version_invalid test/test_model.py::test_recursive_list[case2] test/test_model.py::test_recursive_push_and_pull[case0] test/test_model.py::test_recursive_push_and_pull[case1] test/test_model.py::test_recursive_push_and_pull[case2] test/test_model.py::test_recursive_push_and_pull[case3] test/test_model.py::test_recursive_push_and_pull[case4] test/test_model.py::test_recursive_push_and_pull[case5] test/test_model.py::test_recursive_push_and_pull[case6] test/test_model.py::test_recursive_push_and_pull[case7] test/test_model.py::test_recursive_push_and_pull[case8] test/test_model.py::test_push_path_relative[case0] test/test_model.py::test_push_path_relative[case1] test/test_model.py::test_push_path_relative[case2] test/test_model.py::TestApplication::test_mocked_get_services test/test_model.py::TestApplication::test_planned_units test/test_model.py::TestApplication::test_planned_units_garbage_values test/test_model.py::TestApplication::test_planned_units_override test/test_model.py::TestApplication::test_planned_units_user_set test/test_model.py::TestContainers::test_unit_containers test/test_model.py::TestContainers::test_unit_get_container test/test_model.py::TestContainerPebble::test_add_layer test/test_model.py::TestContainerPebble::test_autostart test/test_model.py::TestContainerPebble::test_can_connect test/test_model.py::TestContainerPebble::test_can_connect_api_error test/test_model.py::TestContainerPebble::test_can_connect_connection_error test/test_model.py::TestContainerPebble::test_can_connect_file_not_found_error test/test_model.py::TestContainerPebble::test_can_connect_simple test/test_model.py::TestContainerPebble::test_get_check test/test_model.py::TestContainerPebble::test_get_checks test/test_model.py::TestContainerPebble::test_get_plan test/test_model.py::TestContainerPebble::test_get_service test/test_model.py::TestContainerPebble::test_get_services test/test_model.py::TestContainerPebble::test_list_files test/test_model.py::TestContainerPebble::test_make_dir test/test_model.py::TestContainerPebble::test_pull test/test_model.py::TestContainerPebble::test_push test/test_model.py::TestContainerPebble::test_remove_path test/test_model.py::TestContainerPebble::test_replan test/test_model.py::TestContainerPebble::test_restart test/test_model.py::TestContainerPebble::test_restart_fallback test/test_model.py::TestContainerPebble::test_restart_fallback_non_400_error test/test_model.py::TestContainerPebble::test_restart_no_arguments test/test_model.py::TestContainerPebble::test_send_signal test/test_model.py::TestContainerPebble::test_socket_path test/test_model.py::TestContainerPebble::test_start test/test_model.py::TestContainerPebble::test_start_no_arguments test/test_model.py::TestContainerPebble::test_stop test/test_model.py::TestContainerPebble::test_stop_no_arguments test/test_model.py::TestContainerPebble::test_type_errors test/test_model.py::TestModelBindings::test_binding_by_relation test/test_model.py::TestModelBindings::test_binding_by_relation_name test/test_model.py::TestModelBindings::test_binding_no_iface_name test/test_model.py::TestModelBindings::test_dead_relations test/test_model.py::TestModelBindings::test_empty_bind_addresses test/test_model.py::TestModelBindings::test_empty_interface_info test/test_model.py::TestModelBindings::test_invalid_keys test/test_model.py::TestModelBindings::test_missing_bind_addresses test/test_model.py::TestModelBindings::test_missing_egress_subnets test/test_model.py::TestModelBindings::test_missing_ingress_addresses test/test_model.py::TestModelBindings::test_no_bind_addresses test/test_model.py::TestModelBindings::test_unresolved_ingress_addresses test/test_model.py::TestModelBackend::test_action_fail test/test_model.py::TestModelBackend::test_action_get test/test_model.py::TestModelBackend::test_action_get_error test/test_model.py::TestModelBackend::test_action_log test/test_model.py::TestModelBackend::test_action_log_error test/test_model.py::TestModelBackend::test_action_set test/test_model.py::TestModelBackend::test_action_set_dotted_dict test/test_model.py::TestModelBackend::test_action_set_duplicated_keys test/test_model.py::TestModelBackend::test_action_set_error test/test_model.py::TestModelBackend::test_action_set_key_validation test/test_model.py::TestModelBackend::test_action_set_more_nested test/test_model.py::TestModelBackend::test_action_set_nested test/test_model.py::TestModelBackend::test_application_version_set test/test_model.py::TestModelBackend::test_application_version_set_invalid test/test_model.py::TestModelBackend::test_invalid_metric_label_values test/test_model.py::TestModelBackend::test_invalid_metric_labels test/test_model.py::TestModelBackend::test_invalid_metric_names test/test_model.py::TestModelBackend::test_invalid_metric_values test/test_model.py::TestModelBackend::test_is_leader_refresh test/test_model.py::TestModelBackend::test_juju_log test/test_model.py::TestModelBackend::test_local_get_status test/test_model.py::TestModelBackend::test_local_set_invalid_status test/test_model.py::TestModelBackend::test_network_get test/test_model.py::TestModelBackend::test_network_get_errors test/test_model.py::TestModelBackend::test_planned_units test/test_model.py::TestModelBackend::test_relation_get_juju_version_quirks test/test_model.py::TestModelBackend::test_relation_get_set_is_app_arg test/test_model.py::TestModelBackend::test_relation_remote_app_name_env test/test_model.py::TestModelBackend::test_relation_remote_app_name_script_errors test/test_model.py::TestModelBackend::test_relation_remote_app_name_script_success test/test_model.py::TestModelBackend::test_relation_set_juju_version_quirks test/test_model.py::TestModelBackend::test_relation_tool_errors test/test_model.py::TestModelBackend::test_status_get test/test_model.py::TestModelBackend::test_status_is_app_forced_kwargs test/test_model.py::TestModelBackend::test_status_set_is_app_not_bool_raises test/test_model.py::TestModelBackend::test_storage_tool_errors test/test_model.py::TestModelBackend::test_valid_metrics test/test_model.py::TestLazyMapping::test_invalidate test/test_model.py::TestSecrets::test_add_secret_errors test/test_model.py::TestSecrets::test_app_add_secret_args test/test_model.py::TestSecrets::test_app_add_secret_simple test/test_model.py::TestSecrets::test_get_secret_id test/test_model.py::TestSecrets::test_get_secret_id_and_label test/test_model.py::TestSecrets::test_get_secret_label test/test_model.py::TestSecrets::test_get_secret_no_args test/test_model.py::TestSecrets::test_get_secret_not_found test/test_model.py::TestSecrets::test_get_secret_other_error test/test_model.py::TestSecrets::test_secret_unique_identifier test/test_model.py::TestSecrets::test_unit_add_secret_args test/test_model.py::TestSecrets::test_unit_add_secret_errors test/test_model.py::TestSecrets::test_unit_add_secret_simple test/test_model.py::TestSecretInfo::test_from_dict test/test_model.py::TestSecretInfo::test_init test/test_model.py::TestSecretClass::test_get_content_cached test/test_model.py::TestSecretClass::test_get_content_copies_dict test/test_model.py::TestSecretClass::test_get_content_refresh test/test_model.py::TestSecretClass::test_get_content_uncached test/test_model.py::TestSecretClass::test_get_info test/test_model.py::TestSecretClass::test_grant test/test_model.py::TestSecretClass::test_id_and_label test/test_model.py::TestSecretClass::test_peek_content test/test_model.py::TestSecretClass::test_remove_all_revisions test/test_model.py::TestSecretClass::test_remove_revision test/test_model.py::TestSecretClass::test_revoke test/test_model.py::TestSecretClass::test_set_content test/test_model.py::TestSecretClass::test_set_content_invalidates_cache test/test_model.py::TestSecretClass::test_set_info test/test_model.py::TestPorts::test_close_port test/test_model.py::TestPorts::test_close_port_error test/test_model.py::TestPorts::test_open_port test/test_model.py::TestPorts::test_open_port_error test/test_model.py::TestPorts::test_opened_ports test/test_model.py::TestPorts::test_opened_ports_warnings test/test_model.py::TestPorts::test_set_ports_all_open test/test_model.py::TestPorts::test_set_ports_close_all test/test_model.py::TestPorts::test_set_ports_mixed test/test_model.py::TestPorts::test_set_ports_noop test/test_model.py::TestPorts::test_set_ports_replace test/test_testing.py::TestHarness::test_actions_from_directory test/test_testing.py::TestHarness::test_actions_from_directory_charmcraft_yaml test/test_testing.py::TestHarness::test_actions_passed_in test/test_testing.py::TestHarness::test_add_oci_resource_custom test/test_testing.py::TestHarness::test_add_oci_resource_no_image test/test_testing.py::TestHarness::test_add_peer_relation_with_initial_data_leader test/test_testing.py::TestHarness::test_add_relation test/test_testing.py::TestHarness::test_add_relation_and_unit test/test_testing.py::TestHarness::test_add_relation_with_app_data test/test_testing.py::TestHarness::test_add_relation_with_our_initial_data test/test_testing.py::TestHarness::test_add_relation_with_remote_app_data test/test_testing.py::TestHarness::test_add_relation_with_unit_data test/test_testing.py::TestHarness::test_add_resource_but_oci test/test_testing.py::TestHarness::test_add_resource_bytes test/test_testing.py::TestHarness::test_add_resource_string test/test_testing.py::TestHarness::test_add_resource_unknown test/test_testing.py::TestHarness::test_add_resource_unknown_filename test/test_testing.py::TestHarness::test_add_storage_after_harness_begin test/test_testing.py::TestHarness::test_add_storage_before_harness_begin test/test_testing.py::TestHarness::test_add_storage_not_attached_default test/test_testing.py::TestHarness::test_add_storage_then_harness_begin test/test_testing.py::TestHarness::test_add_storage_without_metadata_key_fails test/test_testing.py::TestHarness::test_app_status test/test_testing.py::TestHarness::test_attach_storage test/test_testing.py::TestHarness::test_attach_storage_before_harness_begin test/test_testing.py::TestHarness::test_bad_config_option_type test/test_testing.py::TestHarness::test_begin_twice test/test_testing.py::TestHarness::test_begin_with_initial_hooks_install_sets_status test/test_testing.py::TestHarness::test_begin_with_initial_hooks_multiple_relation_same_endpoint test/test_testing.py::TestHarness::test_begin_with_initial_hooks_no_relations test/test_testing.py::TestHarness::test_begin_with_initial_hooks_no_relations_not_leader test/test_testing.py::TestHarness::test_begin_with_initial_hooks_peer_relation_pre_defined test/test_testing.py::TestHarness::test_begin_with_initial_hooks_relation_charm_with_no_relation test/test_testing.py::TestHarness::test_begin_with_initial_hooks_unknown_status test/test_testing.py::TestHarness::test_begin_with_initial_hooks_with_application_data test/test_testing.py::TestHarness::test_begin_with_initial_hooks_with_multiple_units test/test_testing.py::TestHarness::test_begin_with_initial_hooks_with_one_relation test/test_testing.py::TestHarness::test_begin_with_initial_hooks_with_peer_relation test/test_testing.py::TestHarness::test_can_connect_begin_with_initial_hooks test/test_testing.py::TestHarness::test_can_connect_default test/test_testing.py::TestHarness::test_config_from_directory test/test_testing.py::TestHarness::test_config_from_directory_charmcraft_yaml test/test_testing.py::TestHarness::test_container_isdir_and_exists test/test_testing.py::TestHarness::test_container_pebble_ready test/test_testing.py::TestHarness::test_create_harness_twice test/test_testing.py::TestHarness::test_detach_storage test/test_testing.py::TestHarness::test_detach_storage_before_harness_begin test/test_testing.py::TestHarness::test_empty_config_raises test/test_testing.py::TestHarness::test_evaluate_status test/test_testing.py::TestHarness::test_event_context test/test_testing.py::TestHarness::test_event_context_inverse test/test_testing.py::TestHarness::test_get_backend_calls test/test_testing.py::TestHarness::test_get_backend_calls_with_kwargs test/test_testing.py::TestHarness::test_get_filesystem_root test/test_testing.py::TestHarness::test_get_pebble_container_plan test/test_testing.py::TestHarness::test_get_pebble_container_plan_unknown test/test_testing.py::TestHarness::test_get_pod_spec test/test_testing.py::TestHarness::test_get_relation_data test/test_testing.py::TestHarness::test_harness_leader_misconfig test/test_testing.py::TestHarness::test_hooks_disabled_contextmanager test/test_testing.py::TestHarness::test_hooks_disabled_nested_contextmanager test/test_testing.py::TestHarness::test_hooks_disabled_noop test/test_testing.py::TestHarness::test_hooks_enabled_and_disabled test/test_testing.py::TestHarness::test_metadata_from_directory test/test_testing.py::TestHarness::test_metadata_from_directory_charmcraft_yaml test/test_testing.py::TestHarness::test_no_config_option_type test/test_testing.py::TestHarness::test_no_event_on_empty_update_relation_unit_app test/test_testing.py::TestHarness::test_no_event_on_empty_update_relation_unit_bag test/test_testing.py::TestHarness::test_no_event_on_no_diff_update_relation_unit_app test/test_testing.py::TestHarness::test_no_event_on_no_diff_update_relation_unit_bag test/test_testing.py::TestHarness::test_populate_oci_resources test/test_testing.py::TestHarness::test_relation_events test/test_testing.py::TestHarness::test_relation_get_when_broken test/test_testing.py::TestHarness::test_relation_set_app_not_leader test/test_testing.py::TestHarness::test_relation_set_deletes test/test_testing.py::TestHarness::test_relation_set_nonstring test/test_testing.py::TestHarness::test_remove_detached_storage test/test_testing.py::TestHarness::test_remove_relation test/test_testing.py::TestHarness::test_remove_relation_unit test/test_testing.py::TestHarness::test_remove_specific_relation_id test/test_testing.py::TestHarness::test_remove_storage_after_harness_begin test/test_testing.py::TestHarness::test_remove_storage_before_harness_begin test/test_testing.py::TestHarness::test_remove_storage_without_metadata_key_fails test/test_testing.py::TestHarness::test_removing_invalid_relation_id_raises_exception test/test_testing.py::TestHarness::test_removing_relation_refreshes_charm_model test/test_testing.py::TestHarness::test_removing_relation_removes_remote_app_data test/test_testing.py::TestHarness::test_removing_relation_unit_does_not_remove_other_unit_and_data test/test_testing.py::TestHarness::test_removing_relation_unit_removes_data_also test/test_testing.py::TestHarness::test_resource_folder_cleanup test/test_testing.py::TestHarness::test_set_leader test/test_testing.py::TestHarness::test_set_model_info_after_begin test/test_testing.py::TestHarness::test_set_model_name test/test_testing.py::TestHarness::test_set_model_name_after_begin test/test_testing.py::TestHarness::test_set_model_uuid_after_begin test/test_testing.py::TestHarness::test_set_workload_version test/test_testing.py::TestHarness::test_storage_with_hyphens_works test/test_testing.py::TestHarness::test_uncastable_config_option_type test/test_testing.py::TestHarness::test_unit_status test/test_testing.py::TestHarness::test_update_config test/test_testing.py::TestHarness::test_update_config_bad_type test/test_testing.py::TestHarness::test_update_config_undefined_option test/test_testing.py::TestHarness::test_update_config_unset_boolean test/test_testing.py::TestHarness::test_update_peer_relation_app_data test/test_testing.py::TestHarness::test_update_peer_relation_no_local_unit_change_event test/test_testing.py::TestHarness::test_update_relation_exposes_new_data test/test_testing.py::TestHarness::test_update_relation_no_local_app_change_event test/test_testing.py::TestHarness::test_update_relation_no_local_unit_change_event test/test_testing.py::TestHarness::test_update_relation_remove_data test/test_testing.py::TestNetwork::test_add_network_all_args test/test_testing.py::TestNetwork::test_add_network_default_fallback test/test_testing.py::TestNetwork::test_add_network_defaults test/test_testing.py::TestNetwork::test_add_network_endpoint_and_relation_id_do_not_correspond test/test_testing.py::TestNetwork::test_add_network_endpoint_fallback test/test_testing.py::TestNetwork::test_add_network_endpoint_not_in_meta test/test_testing.py::TestNetwork::test_add_network_ipv6 test/test_testing.py::TestNetwork::test_add_network_relation_id_incorrect test/test_testing.py::TestNetwork::test_add_network_relation_id_set_endpoint_not_set test/test_testing.py::TestNetwork::test_add_network_specific_endpoint test/test_testing.py::TestNetwork::test_add_network_specific_relation test/test_testing.py::TestNetwork::test_network_get_relation_not_found test/test_testing.py::TestTestingModelBackend::test_conforms_to_model_backend test/test_testing.py::TestTestingModelBackend::test_get_pebble_methods test/test_testing.py::TestTestingModelBackend::test_lazy_resource_directory test/test_testing.py::TestTestingModelBackend::test_model_uuid_is_uuid_v4 test/test_testing.py::TestTestingModelBackend::test_relation_get_unknown_relation_id test/test_testing.py::TestTestingModelBackend::test_relation_ids_unknown_relation test/test_testing.py::TestTestingModelBackend::test_relation_list_unknown_relation_id test/test_testing.py::TestTestingModelBackend::test_relation_remote_app_name test/test_testing.py::TestTestingModelBackend::test_resource_get_no_resource test/test_testing.py::TestTestingModelBackend::test_status_set_get_app test/test_testing.py::TestTestingModelBackend::test_status_set_get_unit test/test_testing.py::TestTestingPebbleClient::test_add_layer test/test_testing.py::TestTestingPebbleClient::test_add_layer_combine_no_override test/test_testing.py::TestTestingPebbleClient::test_add_layer_combine_override_merge test/test_testing.py::TestTestingPebbleClient::test_add_layer_combine_override_replace test/test_testing.py::TestTestingPebbleClient::test_add_layer_combine_override_unknown test/test_testing.py::TestTestingPebbleClient::test_add_layer_merge test/test_testing.py::TestTestingPebbleClient::test_add_layer_not_combined test/test_testing.py::TestTestingPebbleClient::test_add_layer_three_services test/test_testing.py::TestTestingPebbleClient::test_get_services_autostart test/test_testing.py::TestTestingPebbleClient::test_get_services_bad_request test/test_testing.py::TestTestingPebbleClient::test_get_services_none test/test_testing.py::TestTestingPebbleClient::test_get_services_not_started test/test_testing.py::TestTestingPebbleClient::test_get_services_start_stop test/test_testing.py::TestTestingPebbleClient::test_get_services_subset test/test_testing.py::TestTestingPebbleClient::test_get_services_unknown test/test_testing.py::TestTestingPebbleClient::test_invalid_start_service test/test_testing.py::TestTestingPebbleClient::test_methods_match_pebble_client test/test_testing.py::TestTestingPebbleClient::test_mixed_start_service test/test_testing.py::TestTestingPebbleClient::test_send_signal test/test_testing.py::TestTestingPebbleClient::test_start_service_str test/test_testing.py::TestTestingPebbleClient::test_start_started_service test/test_testing.py::TestTestingPebbleClient::test_stop_service_str test/test_testing.py::TestTestingPebbleClient::test_stop_services_unknown test/test_testing.py::TestTestingPebbleClient::test_stop_stopped_service test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_container_storage_mounts test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_list_directory_object_itself test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_list_files_not_found_raises test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_make_dir_with_ownership test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_make_dir_with_permission_mask test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_make_directory test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_make_directory_recursively test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_make_directory_with_relative_path_fails test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_make_subdir_of_file_fails test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_pull_directory test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_pull_not_found test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_and_list_file test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_and_pull_bytes test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_and_pull_larger_file test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_and_pull_non_utf8_data test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_as_child_of_file_raises_error test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_bytes_ignore_encoding test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_bytesio_ignore_encoding test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_file_with_relative_path_fails test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_files_and_list test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_files_and_list_by_pattern test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_to_non_existent_subdir test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_with_ownership test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_push_with_permission_mask test/test_testing.py::TestPebbleStorageAPIsUsingMocks::test_remove_path test/test_testing.py::TestFilesystem::test_list_files test/test_testing.py::TestFilesystem::test_make_dir test/test_testing.py::TestFilesystem::test_pull test/test_testing.py::TestFilesystem::test_push test/test_testing.py::TestFilesystem::test_push_create_parent test/test_testing.py::TestFilesystem::test_storage_mount test/test_testing.py::TestSecrets::test_add_model_secret_by_app_instance test/test_testing.py::TestSecrets::test_add_model_secret_by_app_name_str test/test_testing.py::TestSecrets::test_add_model_secret_by_unit_instance test/test_testing.py::TestSecrets::test_add_model_secret_invalid_content test/test_testing.py::TestSecrets::test_get_secret_grants test/test_testing.py::TestSecrets::test_grant_secret_and_revoke_secret test/test_testing.py::TestSecrets::test_grant_secret_no_relation test/test_testing.py::TestSecrets::test_grant_secret_wrong_app test/test_testing.py::TestSecrets::test_grant_secret_wrong_unit test/test_testing.py::TestSecrets::test_set_secret_content test/test_testing.py::TestSecrets::test_set_secret_content_invalid_content test/test_testing.py::TestSecrets::test_set_secret_content_invalid_secret_id test/test_testing.py::TestSecrets::test_set_secret_content_wrong_owner test/test_testing.py::TestSecrets::test_trigger_secret_expiration test/test_testing.py::TestSecrets::test_trigger_secret_removal test/test_testing.py::TestSecrets::test_trigger_secret_rotation test/test_testing.py::TestPorts::test_errors test/test_testing.py::TestPorts::test_ports test/test_testing.py::TestHandleExec::test_combined_error test/test_testing.py::TestHandleExec::test_exec_service_context test/test_testing.py::TestHandleExec::test_exec_stdin test/test_testing.py::TestHandleExec::test_exec_stdout_stderr test/test_testing.py::TestHandleExec::test_exec_timeout test/test_testing.py::TestHandleExec::test_re_register_handler test/test_testing.py::TestHandleExec::test_register_handler test/test_testing.py::TestHandleExec::test_register_match_all_prefix test/test_testing.py::TestHandleExec::test_register_with_handler test/test_testing.py::TestHandleExec::test_register_with_result