コード例 #1
0
def test_import_replace_existing_with_column_renames(
    data_archive,
    tmp_path,
    cli_runner,
    chdir,
):
    with data_archive("gpkg-polygons") as data:
        repo_path = tmp_path / "emptydir"
        r = cli_runner.invoke(["init", repo_path])
        assert r.exit_code == 0
        with chdir(repo_path):
            r = cli_runner.invoke([
                "import",
                data / "nz-waca-adjustments.gpkg",
                "nz_waca_adjustments:mytable",
            ])
            assert r.exit_code == 0, r.stderr

            # Now rename
            # * doesn't include the `survey_reference` column
            # * has the columns in a different order
            # * has a new column
            with Db_GPKG.create_engine(
                    data / "nz-waca-adjustments.gpkg").connect() as conn:
                conn.execute("""
                    ALTER TABLE "nz_waca_adjustments" RENAME COLUMN "survey_reference" TO "renamed_survey_reference";
                    """)

            r = cli_runner.invoke([
                "import",
                "--replace-existing",
                data / "nz-waca-adjustments.gpkg",
                "nz_waca_adjustments:mytable",
            ])
            assert r.exit_code == 0, r.stderr
            r = cli_runner.invoke(["show", "-o", "json"])
            assert r.exit_code == 0, r.stderr
            diff = json.loads(r.stdout)["kart.diff/v1+hexwkb"]["mytable"]

            # The schema changed, but the features didn't.
            assert diff["meta"]["schema.json"]
            assert not diff.get("feature")

            repo = KartRepo(repo_path)
            head_rs = repo.structure("HEAD")
            old_rs = repo.structure("HEAD^")
            assert head_rs.tree != old_rs.tree
            new_feature_tree = head_rs.tree / "mytable/.table-dataset/feature"
            old_feature_tree = old_rs.tree / "mytable/.table-dataset/feature"
            assert new_feature_tree == old_feature_tree
コード例 #2
0
ファイル: test_resolve.py プロジェクト: koordinates/kart
def test_resolve_with_version(data_archive, cli_runner):
    with data_archive("conflicts/polygons.tgz") as repo_path:
        repo = KartRepo(repo_path)

        r = cli_runner.invoke(["merge", "theirs_branch", "-o", "json"])
        assert r.exit_code == 0, r.stderr
        assert json.loads(r.stdout)["kart.merge/v1"]["conflicts"]
        assert repo.state == KartRepoState.MERGING

        # Can't just complete the merge until we resolve the conflicts.
        r = cli_runner.invoke(["merge", "--continue"])
        assert r.exit_code == INVALID_OPERATION

        conflict_ids = get_conflict_ids(cli_runner)
        resolutions = iter(["ancestor", "ours", "theirs", "delete"])

        # Keep track of which order we resolve the conflicts - each conflict
        # resolved will have a primary key, and we resolve conflicts in
        # primary key order, but the primary keys are not contiguous.
        pk_order = []
        # Each conflict also has an internal "conflict" key - just its index
        # in the original list of conflicts - these are contiguous, but
        # we don't necessarily resolve the conflicts in this order.
        ck_order = []

        while conflict_ids:
            num_conflicts = len(conflict_ids)
            conflict_id = conflict_ids[0]
            pk = conflict_id.split(":", 2)[2]
            pk_order += [pk]

            r = cli_runner.invoke(
                ["resolve", conflict_id, f"--with={next(resolutions)}"])
            assert r.exit_code == 0, r.stderr
            conflict_ids = get_conflict_ids(cli_runner)
            assert len(conflict_ids) == num_conflicts - 1

            resolved_keys = MergeIndex.read_from_repo(repo).resolves.keys()
            ck_order += [k for k in resolved_keys if k not in ck_order]

        assert len(conflict_ids) == 0

        merge_index = MergeIndex.read_from_repo(repo)
        assert len(merge_index.entries) == 237
        assert len(merge_index.conflicts) == 4
        assert len(merge_index.resolves) == 4

        ck0, ck1, ck2, ck3 = ck_order
        # Conflict ck0 is resolved to ancestor, but the ancestor is None.
        assert merge_index.resolves[ck0] == []
        assert merge_index.conflicts[ck0].ancestor is None
        assert merge_index.resolves[ck1] == [merge_index.conflicts[ck1].ours]
        assert merge_index.resolves[ck2] == [merge_index.conflicts[ck2].theirs]
        assert merge_index.resolves[ck3] == []

        r = cli_runner.invoke(["merge", "--continue", "-m", "merge commit"])
        assert r.exit_code == 0, r.stderr
        assert repo.head_commit.message == "merge commit"
        assert repo.state != KartRepoState.MERGING

        merged = repo.structure("HEAD")
        ours = repo.structure("ours_branch")
        theirs = repo.structure("theirs_branch")
        l = H.POLYGONS.LAYER

        pk0, pk1, pk2, pk3 = pk_order
        # Feature at pk0 was resolved to ancestor, which was None.
        assert get_json_feature(merged, l, pk0) is None
        assert get_json_feature(merged, l,
                                pk1) == get_json_feature(ours, l, pk1)
        assert get_json_feature(merged, l,
                                pk2) == get_json_feature(theirs, l, pk2)
        assert get_json_feature(merged, l, pk3) is None
コード例 #3
0
ファイル: test_resolve.py プロジェクト: koordinates/kart
def test_resolve_with_file(data_archive, cli_runner):
    with data_archive("conflicts/polygons.tgz") as repo_path:
        repo = KartRepo(repo_path)

        r = cli_runner.invoke(
            ["diff", "ancestor_branch..ours_branch", "-o", "geojson"])
        assert r.exit_code == 0, r.stderr
        ours_geojson = json.loads(r.stdout)["features"][0]
        assert ours_geojson["id"] == "nz_waca_adjustments:feature:98001:I"

        r = cli_runner.invoke(
            ["diff", "ancestor_branch..theirs_branch", "-o", "geojson"])
        assert r.exit_code == 0, r.stderr
        theirs_geojson = json.loads(r.stdout)["features"][0]
        assert theirs_geojson["id"] == "nz_waca_adjustments:feature:98001:I"

        r = cli_runner.invoke(["merge", "theirs_branch", "-o", "json"])
        assert r.exit_code == 0, r.stderr
        assert json.loads(r.stdout)["kart.merge/v1"]["conflicts"]

        r = cli_runner.invoke(["conflicts", "-s", "-o", "json"])
        assert r.exit_code == 0, r.stderr

        conflicts = json.loads(r.stdout)["kart.conflicts/v1"]
        add_add_conflict_pk = conflicts[H.POLYGONS.LAYER]["feature"][0]
        assert add_add_conflict_pk == 98001

        # These IDs are irrelevant, but we change them to at least be unique.
        ours_geojson["id"] = "ours-feature"
        theirs_geojson["id"] = "theirs-feature"
        # Changing this ID means the two features no long conflict.
        theirs_geojson["properties"]["id"] = 98002

        resolution = {
            "features": [ours_geojson, theirs_geojson],
            "type": "FeatureCollection",
        }
        (repo.workdir_path / "resolution.geojson").write_text(
            json.dumps(resolution))
        r = cli_runner.invoke([
            "resolve",
            f"{H.POLYGONS.LAYER}:feature:98001",
            "--with-file=resolution.geojson",
        ])
        assert r.exit_code == 0, r.stderr

        merge_index = MergeIndex.read_from_repo(repo)
        assert len(merge_index.entries) == 237
        assert len(merge_index.conflicts) == 4
        assert len(merge_index.resolves) == 1

        ck = next(iter(merge_index.resolves.keys()))
        assert len(merge_index.resolves[ck]) == 2  # Resolved with 2 features

        delete_remaining_conflicts(cli_runner)

        r = cli_runner.invoke(["merge", "--continue", "-m", "merge commit"])
        assert r.exit_code == 0, r.stderr
        assert repo.head_commit.message == "merge commit"
        assert repo.state != KartRepoState.MERGING

        merged = repo.structure("HEAD")
        ours = repo.structure("ours_branch")
        theirs = repo.structure("theirs_branch")
        l = H.POLYGONS.LAYER

        # Both features are present in the merged repo, ours at 98001 and theirs at 98002.
        assert get_json_feature(merged, l,
                                98001) == get_json_feature(ours, l, 98001)
        # Theirs feature is slightly different - it has a new primary key.
        assert get_json_feature(merged, l, 98002) != get_json_feature(
            theirs, l, 98001)

        modified_theirs_json = get_json_feature(theirs, l, 98001)
        modified_theirs_json["id"] = 98002
        assert get_json_feature(merged, l, 98002) == modified_theirs_json
コード例 #4
0
def test_import_replace_existing_with_compatible_schema_changes(
    data_archive,
    tmp_path,
    cli_runner,
    chdir,
):
    with data_archive("gpkg-polygons") as data:
        repo_path = tmp_path / "emptydir"
        r = cli_runner.invoke(["init", repo_path])
        assert r.exit_code == 0
        with chdir(repo_path):
            r = cli_runner.invoke([
                "import",
                data / "nz-waca-adjustments.gpkg",
                "nz_waca_adjustments:mytable",
            ])
            assert r.exit_code == 0, r.stderr

            # Now replace with a table which
            # * doesn't include the `survey_reference` column
            # * has the columns in a different order
            # * has a new column
            with Db_GPKG.create_engine(
                    data / "nz-waca-adjustments.gpkg").connect() as conn:
                conn.execute("""
                        CREATE TABLE IF NOT EXISTS "nz_waca_adjustments_2" (
                            "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
                            "geom" MULTIPOLYGON,
                            "date_adjusted" DATETIME,
                            "adjusted_nodes" MEDIUMINT,
                            "newcolumn" TEXT
                        );
                    """)
                conn.execute("""
                        INSERT INTO nz_waca_adjustments_2 (id, geom, date_adjusted, adjusted_nodes, newcolumn)
                            SELECT id, geom, date_adjusted, adjusted_nodes, NULL FROM nz_waca_adjustments;
                    """)
                conn.execute("""DROP TABLE nz_waca_adjustments;""")
                conn.execute(
                    """ALTER TABLE "nz_waca_adjustments_2" RENAME TO "nz_waca_adjustments";"""
                )

            r = cli_runner.invoke([
                "import",
                "--replace-existing",
                data / "nz-waca-adjustments.gpkg",
                "nz_waca_adjustments:mytable",
            ])
            assert r.exit_code == 0, r.stderr
            r = cli_runner.invoke(["show", "-o", "json"])
            assert r.exit_code == 0, r.stderr
            diff = json.loads(r.stdout)["kart.diff/v1+hexwkb"]["mytable"]

            # The schema changed, but the features didn't.
            assert diff["meta"]["schema.json"]
            assert not diff.get("feature")

            repo = KartRepo(repo_path)
            head_rs = repo.structure("HEAD")
            old_rs = repo.structure("HEAD^")
            assert head_rs.tree != old_rs.tree
            new_feature_tree = head_rs.tree / "mytable/.table-dataset/feature"
            old_feature_tree = old_rs.tree / "mytable/.table-dataset/feature"
            assert new_feature_tree == old_feature_tree
コード例 #5
0
def test_edit_crs(data_archive, cli_runner, new_postgis_db_schema):
    with data_archive("points") as repo_path:
        repo = KartRepo(repo_path)
        H.clear_working_copy()

        with new_postgis_db_schema() as (postgres_url, postgres_schema):
            r = cli_runner.invoke(["create-workingcopy", postgres_url])
            assert r.exit_code == 0, r.stderr

            wc = repo.working_copy
            assert wc.status() & WorkingCopyStatus.INITIALISED
            assert wc.status() & WorkingCopyStatus.HAS_DATA
            assert not wc.is_dirty()

            # The test is run inside a single transaction which we always roll back -
            # this is because we are editing the public.spatial_ref_sys table, which is shared by
            # everything in the postgis DB - we don't want these temporary changes to make other
            # tests fail, and we want to roll them immediately whether the test passes or fails.
            with pytest.raises(SucceedAndRollback):
                with wc.session() as sess:

                    crs = sess.scalar(
                        "SELECT srtext FROM public.spatial_ref_sys WHERE srid=4326"
                    )
                    assert crs.startswith('GEOGCS["WGS 84",')
                    assert crs.endswith('AUTHORITY["EPSG","4326"]]')

                    # Make an unimportant, cosmetic change, while keeping the CRS basically EPSG:4326
                    crs = crs.replace('GEOGCS["WGS 84",', 'GEOGCS["WGS 1984",')
                    sess.execute(
                        """UPDATE public.spatial_ref_sys SET srtext=:srtext WHERE srid=4326;""",
                        {"srtext": crs},
                    )

                    # kart diff hides differences between dataset CRS and WC CRS if they are both supposed to be EPSG:4326
                    # (or any other standard CRS). See POSTGIS_WC.md
                    assert not wc.is_dirty()

                    # Change the CRS authority to CUSTOM
                    crs = crs.replace('AUTHORITY["EPSG","4326"]]',
                                      'AUTHORITY["CUSTOM","4326"]]')

                    sess.execute(
                        """UPDATE public.spatial_ref_sys SET srtext=:srtext WHERE srid=4326;""",
                        {"srtext": crs},
                    )

                    # Now kart diff should show the change, and it is possible to commit the change.
                    assert wc.is_dirty()

                    commit_id = repo.structure().commit_diff(
                        wc.diff_to_tree(), "Modify CRS")
                    wc.update_state_table_tree(commit_id.hex)

                    assert not wc.is_dirty()

                    r = cli_runner.invoke(["show"])
                    lines = r.stdout.splitlines()
                    assert "--- nz_pa_points_topo_150k:meta:crs/EPSG:4326.wkt" in lines
                    assert (
                        "+++ nz_pa_points_topo_150k:meta:crs/CUSTOM:4326.wkt"
                        in lines)

                    raise SucceedAndRollback()