Exemplo n.º 1
0
def test_geopackage_locking_edit(data_working_copy, cli_runner, monkeypatch):
    with data_working_copy("points") as (repo_path, wc_path):
        wc = KartRepo(repo_path).working_copy

        is_checked = False
        orig_func = BaseWorkingCopy._write_features

        def _wrap(*args, **kwargs):
            nonlocal is_checked
            if not is_checked:
                with pytest.raises(sqlalchemy.exc.OperationalError,
                                   match=r"database is locked"):
                    with wc.session() as sess:
                        sess.execute(
                            "UPDATE gpkg_contents SET table_name=table_name;")
                is_checked = True

            return orig_func(*args, **kwargs)

        monkeypatch.setattr(BaseWorkingCopy, "_write_features", _wrap)

        r = cli_runner.invoke(["checkout", H.POINTS.HEAD1_SHA])
        assert r.exit_code == 0, r
        assert is_checked

        with wc.session() as sess:
            assert H.last_change_time(sess) == "2019-06-11T11:03:58.000000Z"
Exemplo n.º 2
0
    def _data_working_copy(archive_path, force_new=False):
        nonlocal incr

        archive_path = get_archive_path(archive_path)
        with data_archive(archive_path) as repo_dir:
            repo = KartRepo(repo_dir)
            if repo.working_copy:
                wc_path = repo.working_copy.full_path
                if force_new:
                    L.info("force_new is set, deleting existing WC: %s",
                           wc_path)
                    del repo.working_copy
                    assert not hasattr(repo, "_working_copy")
                    del wc_path

            if not repo.working_copy:
                wc_path = (
                    tmp_path_factory.mktemp(request.node.name, str(incr)) /
                    archive_path.with_suffix(".gpkg").name)
                incr += 1
                L.info("Creating working copy at %s", wc_path)
                r = cli_runner.invoke(
                    ["create-workingcopy", wc_path, "--delete-existing"])
                assert r.exit_code == 0, r.stderr

            del repo

            L.info("data_working_copy: %s %s", repo_dir, wc_path)
            yield repo_dir, wc_path
Exemplo n.º 3
0
def test_switch_pre_import_post_import(data_working_copy,
                                       data_archive_readonly, cli_runner):
    with data_archive_readonly("gpkg-au-census") as data:
        with data_working_copy("polygons") as (repo_path, wc_path):
            wc = KartRepo(repo_path).working_copy

            r = cli_runner.invoke([
                "import",
                data / "census2016_sdhca_ot_short.gpkg",
                "census2016_sdhca_ot_ced_short",
            ])
            assert r.exit_code == 0, r.stderr
            r = cli_runner.invoke(["checkout", "HEAD^"])
            assert r.exit_code == 0, r.stderr

            with wc.session() as sess:
                count = sess.scalar(
                    f"""SELECT COUNT(name) FROM sqlite_master where type='table' AND name='census2016_sdhca_ot_ced_short';"""
                )
                assert count == 0

            r = cli_runner.invoke(["checkout", "main"])
            assert r.exit_code == 0, r.stderr

            with wc.session() as sess:
                count = sess.scalar(
                    f"""SELECT COUNT(name) FROM sqlite_master where type='table' AND name='census2016_sdhca_ot_ced_short';"""
                )
                assert count == 1
Exemplo n.º 4
0
def test_switch_with_trivial_schema_change(data_working_copy, cli_runner):
    # Column renames are one of the only schema changes we can do without having to recreate the whole table.
    with data_working_copy("points") as (repo_path, wc_path):
        wc = KartRepo(repo_path).working_copy
        with wc.session() as sess:
            sess.execute(
                f"""ALTER TABLE "{H.POINTS.LAYER}" RENAME "name_ascii" TO "name_latin1";"""
            )

        r = cli_runner.invoke(["commit", "-m", "change schema"])
        assert r.exit_code == 0, r.stderr
        r = cli_runner.invoke(["checkout", "HEAD^"])
        assert r.exit_code == 0, r.stderr
        with wc.session() as sess:
            name = sess.scalar(
                f"""SELECT name FROM pragma_table_info('{H.POINTS.LAYER}') WHERE cid = 3;"""
            )
            assert name == "name_ascii"

        r = cli_runner.invoke(["checkout", "main"])
        assert r.exit_code == 0, r.stderr
        with wc.session() as sess:
            name = sess.scalar(
                f"""SELECT name FROM pragma_table_info('{H.POINTS.LAYER}') WHERE cid = 3;"""
            )
            assert name == "name_latin1"
Exemplo n.º 5
0
def test_switch_with_meta_items(data_working_copy, cli_runner):
    with data_working_copy("points") as (repo_path, wc_path):
        wc = KartRepo(repo_path).working_copy
        with wc.session() as sess:
            sess.execute(
                """UPDATE gpkg_contents SET identifier = 'new identifier', description='new description'"""
            )

        r = cli_runner.invoke(
            ["commit", "-m", "change identifier and description"])
        assert r.exit_code == 0, r.stderr
        r = cli_runner.invoke(["checkout", "HEAD^"])
        assert r.exit_code == 0, r.stderr

        with wc.session() as sess:
            r = sess.execute(
                """SELECT identifier, description FROM gpkg_contents""")
            identifier, description = r.fetchone()
            assert identifier == "NZ Pa Points (Topo, 1:50k)"
            assert description.startswith("Defensive earthworks")

        r = cli_runner.invoke(["checkout", "main"])
        assert r.exit_code == 0, r.stderr

        with wc.session() as sess:
            r = sess.execute(
                """SELECT identifier, description FROM gpkg_contents""")
            identifier, description = r.fetchone()
            assert identifier == "new identifier"
            assert description == "new description"
Exemplo n.º 6
0
def test_checkout_workingcopy(archive, table, commit_sha, data_archive,
                              tmp_path, cli_runner):
    """ Checkout a working copy to edit """
    with data_archive(archive) as repo_path:
        H.clear_working_copy()

        repo = KartRepo(repo_path)
        dataset = repo.datasets()[table]
        geom_cols = dataset.schema.geometry_columns

        r = cli_runner.invoke(["checkout"])
        wc_path = Path(repo.config["kart.workingcopy.location"])
        assert r.exit_code == 0, r
        assert r.stdout.splitlines() == [
            f"Creating working copy at {wc_path} ..."
        ]
        assert wc_path.exists()
        wc = repo.working_copy

        assert repo.head.name == "refs/heads/main"
        assert repo.head.shorthand == "main"
        assert wc.get_db_tree() == repo.head_tree.hex

        if geom_cols:
            with wc.session() as sess:
                spatial_index_count = sess.execute(
                    f"""SELECT COUNT(*) FROM "rtree_{table}_{geom_cols[0].name}";"""
                ).scalar()
                assert spatial_index_count == dataset.feature_count

        table_spec = KartAdapter_GPKG.v2_schema_to_sql_spec(dataset.schema)
        expected_col_spec = f"{KartAdapter_GPKG.quote(dataset.primary_key)} INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"
        assert expected_col_spec in table_spec
Exemplo n.º 7
0
def test_status_merging(data_archive, cli_runner):
    with data_archive("conflicts/points.tgz") as repo_path:
        repo = KartRepo(repo_path)
        r = cli_runner.invoke(["merge", "theirs_branch"])
        assert r.exit_code == 0, r

        assert repo.state == KartRepoState.MERGING
        assert text_status(cli_runner) == [
            "On branch ours_branch",
            "",
            'Repository is in "merging" state.',
            'Merging branch "theirs_branch" into ours_branch',
            "Conflicts:",
            "",
            "nz_pa_points_topo_150k:",
            "    nz_pa_points_topo_150k:feature: 4 conflicts",
            "",
            "View conflicts with `kart conflicts` and resolve them with `kart resolve`.",
            "Once no conflicts remain, complete this merge with `kart merge --continue`.",
            "Or use `kart merge --abort` to return to the previous state.",
        ]

        ancestor = CommitWithReference.resolve(repo, "ancestor_branch")
        ours = CommitWithReference.resolve(repo, "ours_branch")
        theirs = CommitWithReference.resolve(repo, "theirs_branch")
        assert json_status(cli_runner) == {
            "kart.status/v1": {
                "abbrevCommit": ours.short_id,
                "commit": ours.id.hex,
                "branch": "ours_branch",
                "upstream": None,
                "state": "merging",
                "merging": {
                    "ancestor": {
                        "abbrevCommit": ancestor.short_id,
                        "commit": ancestor.id.hex,
                    },
                    "ours": {
                        "abbrevCommit": ours.short_id,
                        "commit": ours.id.hex,
                        "branch": "ours_branch",
                    },
                    "theirs": {
                        "abbrevCommit": theirs.short_id,
                        "commit": theirs.id.hex,
                        "branch": "theirs_branch",
                    },
                },
                "conflicts": {
                    "nz_pa_points_topo_150k": {
                        "feature": 4
                    }
                },
                "spatialFilter": None,
            }
        }
Exemplo n.º 8
0
    def clear_working_copy(cls, repo_path="."):
        """ Delete any existing working copy & associated config """
        repo = KartRepo(repo_path)
        wc = repo.get_working_copy(allow_invalid_state=True)
        if wc:
            print(
                f"Deleting existing working copy: {repo.workingcopy_location}")
            wc.delete()

        if repo.WORKINGCOPY_LOCATION_KEY in repo.config:
            del repo.config[repo.WORKINGCOPY_LOCATION_KEY]
Exemplo n.º 9
0
def test_postgis_wc_with_long_index_name(
    data_archive,
    tmp_path,
    cli_runner,
    chdir,
    new_postgis_db_schema,
):
    with data_archive("gpkg-points") as data:
        # list tables
        repo_path = tmp_path / "repo"
        repo_path.mkdir()

        # create a repo
        with new_postgis_db_schema() as (
                postgres_url,
                postgres_schema,
        ):
            r = cli_runner.invoke(
                ["init", f"--workingcopy-path={postgres_url}",
                 str(repo_path)])
            assert r.exit_code == 0, r.stderr

            # import a very long named dataset
            r = cli_runner.invoke([
                "-C",
                str(repo_path),
                "import",
                f"{data}/nz-pa-points-topo-150k.gpkg",
                "nz_pa_points_topo_150k:a_really_long_table_name_that_is_really_actually_quite_long_dont_you_think",
            ])
            assert r.exit_code == 0, r.stderr

            repo = KartRepo(repo_path)
            assert not repo.is_bare
            assert not repo.is_empty

            wc = repo.working_copy
            insp = inspect(wc.engine)
            indexes = insp.get_indexes(
                "a_really_long_table_name_that_is_really_actually_quite_long_dont_you_think",
                schema=postgres_schema,
            )
            assert len(indexes) == 1
            assert indexes[0] == {
                "name":
                "a_really_long_table_na_0ccb228e66871172f030077f3a9974d2b58d1ee5",
                "unique": False,
                "column_names": ["geom"],
                "include_columns": [],
                "dialect_options": {
                    "postgresql_include": [],
                    "postgresql_using": "gist",
                },
            }
Exemplo n.º 10
0
def test_empty_geometry_roundtrip(data_working_copy, cli_runner):
    with data_working_copy("empty-geometry") as (repo_path, wc_path):
        repo = KartRepo(repo_path)
        with repo.working_copy.session() as sess:
            # We don't diff values unless they're marked as dirty in the WC - move the row to make it dirty.
            sess.execute('UPDATE point_test SET "PK"="PK" + 1000;')
            sess.execute('UPDATE point_test SET "PK"="PK" - 1000;')
            sess.execute('UPDATE polygon_test SET "PK"="PK" + 1000;')
            sess.execute('UPDATE polygon_test SET "PK"="PK" - 1000;')
        r = cli_runner.invoke(["diff", "--exit-code"])
        assert r.exit_code == 0, r.stdout
Exemplo n.º 11
0
def test_values_roundtrip(data_working_copy, cli_runner):
    # If values roundtripping code isn't working for certain types,
    # we could get spurious diffs on those values.
    with data_working_copy("types") as (repo_path, wc_path):
        repo = KartRepo(repo_path)
        with repo.working_copy.session() as sess:
            # We don't diff values unless they're marked as dirty in the WC - move the row to make it dirty.
            sess.execute('UPDATE manytypes SET "PK"="PK" + 1000;')
            sess.execute('UPDATE manytypes SET "PK"="PK" - 1000;')
        r = cli_runner.invoke(["diff", "--exit-code"])
        assert r.exit_code == 0, r.stdout
Exemplo n.º 12
0
def test_tag(data_working_copy, cli_runner):
    """ review commit history """
    with data_working_copy("points") as (repo_dir, wc):
        # create a tag
        r = cli_runner.invoke(["tag", "version1"])
        assert r.exit_code == 0, r

        repo = KartRepo(repo_dir)
        assert "refs/tags/version1" in repo.references
        ref = repo.lookup_reference_dwim("version1")
        assert ref.target.hex == H.POINTS.HEAD_SHA