code: def test_update_simple(origin=None, src_path=None, dst_path=None):
      ca = dict(result_renderer="disabled")
      # a remote dataset with a subdataset underneath
      origds = Dataset(origin).create(**ca)
      # naming is weird, but a legacy artifact
      _ = origds.create("subm 1", **ca)
      _ = origds.create("2", **ca)
  
      # prepare src
      source = install(src_path, source=origin, recursive=True)
      # forget we cloned it by removing remote, which should lead to
      # setting tracking branch to target:
      source.repo.remove_remote(DEFAULT_REMOTE)
      # also forget the declared absolute location of the submodules, and turn them
      # relative to this/a clone
      for sub in source.subdatasets(
          result_xfm=lambda x: x["gitmodule_name"]
      ):
          source.subdatasets(
              path=sub, set_property=[("url", "./{}".format(sub))]
          )
  
      # dataset without sibling will not need updates
      assert_status("notneeded", source.update())
      # deprecation message doesn't ruin things
      assert_status("notneeded", source.update(fetch_all=True))
      # but error if unknown sibling is given
      assert_status(
          "impossible",
          source.update(sibling="funky", on_failure="ignore"),
      )
  
      # get a clone to update later on:
      dest = install(dst_path, source=src_path, recursive=True)
      # test setup done;
      # assert all fine
      assert_repo_status(dst_path)
      assert_repo_status(src_path)
  
      # update yields nothing => up-to-date
      assert_status("ok", dest.update())
      assert_repo_status(dst_path)
  
      # modify remote:
      with open(opj(src_path, "update.txt"), "w") as f:
          f.write("Additional content")
      source.save(path="update.txt", message="Added update.txt")
      assert_repo_status(src_path)
  
      # update without `merge` only fetches:
      assert_status("ok", dest.update())
      # modification is not known to active branch:
      assert_not_in(
          "update.txt",
          dest.repo.get_files(dest.repo.get_active_branch()),
      )
      # modification is known to branch <default remote>/<default branch>
      assert_in(
          "update.txt",
          dest.repo.get_files(DEFAULT_REMOTE + "/" + DEFAULT_BRANCH),
      )
  
      # merge:
      assert_status("ok", dest.update(merge=True))
      # modification is now known to active branch:
      assert_in(
          "update.txt",
          dest.repo.get_files(dest.repo.get_active_branch()),
      )
      # it's known to annex, but has no content yet:
      annexprops = dest.repo.get_file_annexinfo(
          "update.txt", eval_availability=True
      )
      annexprops["key"]  # blows if unknown
      eq_(False, annexprops["has_content"])
  
      # check subdataset path constraints, baseline (parent + 2 subds)
      assert_result_count(
          dest.update(recursive=True), 3, status="ok", type="dataset"
      )
      # no recursion and invalid path still updates the parent
      res = dest.update(path="whatever")
      assert_result_count(res, 1, status="ok", type="dataset")
      assert_result_count(res, 1, status="ok", path=dest.path)
      # invalid path with recursion also does
      res = dest.update(recursive=True, path="whatever")
      assert_result_count(res, 1, status="ok", type="dataset")
      assert_result_count(res, 1, status="ok", path=dest.path)
      # valid path and no recursion only updates the parent
      res = dest.update(path="subm 1")
      assert_result_count(res, 1, status="ok", type="dataset")
      assert_result_count(res, 1, status="ok", path=dest.path)
      # valid path and recursion updates matching
      res = dest.update(recursive=True, path="subm 1")
      assert_result_count(res, 2, status="ok", type="dataset")
      assert_result_count(res, 1, status="ok", path=dest.path)
      assert_result_count(
          res, 1, status="ok", path=str(dest.pathobj / "subm 1")
      )
      # additional invalid path doesn't hurt
      res = dest.update(recursive=True, path=["subm 1", "mike"])
      assert_result_count(res, 2, status="ok", type="dataset")
      # full match
      res = dest.update(recursive=True, path=["subm 1", "2"])
      assert_result_count(res, 3, status="ok", type="dataset")
  
      # test that update doesn't crash if we specify only a single path (submod) to
      # operate on
      with chpwd(dest.path):
          # in 0.11.x it would be a single result since "pwd" dataset is not
          # considered, and would be relative path (as specified).
          # In 0.12.0 - it would include implicit pwd dataset, and paths would be absolute
          res_update = update(path=["subm 1"], recursive=True)
          assert_result_count(res_update, 2)
          for p in dest.path, str(dest.pathobj / "subm 1"):
              assert_in_results(
                  res_update,
                  path=p,
                  action="update",
                  status="ok",
                  type="dataset",
              )
  
          # and with merge we would also try to save (but there would be no changes)
          res_merge = update(
              path=["subm 1"], recursive=True, merge=True
          )
          assert_result_count(res_merge, 2, action="update")
          # 2 of "updates" really.
          assert_in_results(
              res_merge, action="update", status="ok", type="dataset"
          )
          assert_in_results(
              res_merge,
              action="save",
              status="notneeded",
              type="dataset",
          )
  
      # smoke-test if recursive update doesn't fail if submodule is removed
      # and that we can run it from within a dataset without providing it
      # explicitly
      assert_result_count(
          dest.remove("subm 1"),
          1,
          status="ok",
          action="remove",
          path=opj(dest.path, "subm 1"),
      )
      with chpwd(dest.path):
          assert_result_count(
              update(recursive=True), 2, status="ok", type="dataset"
          )
      assert_result_count(
          dest.update(merge=True, recursive=True),
          2,
          action="update",
          status="ok",
          type="dataset",
      )
  
      # and now test recursive update with merging in differences
      create_tree(opj(source.path, "2"), {"load.dat": "heavy"})
      source.save(
          opj("2", "load.dat"),
          message="saving changes within subm2",
          recursive=True,
      )
      assert_result_count(
          dest.update(merge=True, recursive=True),
          2,
          action="update",
          status="ok",
          type="dataset",
      )
      # and now we can get new file
      dest.get(opj("2", "load.dat"))
      ok_file_has_content(opj(dest.path, "2", "load.dat"), "heavy")
  
imports: import os
  import os.path
  from os.path import exists
  from os.path import join
  from unittest.mock import patch
  import pytest
  from datalad import cfg
  from datalad.api import clone, install, remove, update
  from datalad.distribution.update import _process_how_args
  from datalad.support.annexrepo import AnnexRepo
  from datalad.support.external_versions import external_versions
  from datalad.support.gitrepo import GitRepo
  from datalad.tests.utils_pytest import DEFAULT_BRANCH, DEFAULT_REMOTE, SkipTest, assert_false, assert_in, assert_in_results, assert_is_instance, assert_not_in, assert_raises, assert_repo_status, assert_result_count, assert_status, create_tree, eq_, known_failure_windows, maybe_adjust_repo, neq_, ok_, ok_file_has_content, skip_if_adjusted_branch, slow, with_tempfile
  from datalad.utils import Path, chpwd, knows_annex, rmtree
  from ..dataset import Dataset
label_desc: Use image node_id 1 for calling a global function with example usage: test_update_simple(origin, src_path, dst_path) without return types