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
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"
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"
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"
def test_switch_with_schema_change(data_working_copy, cli_runner): with data_working_copy("polygons") as (repo_path, wc_path): wc = KartRepo(repo_path).working_copy with wc.session() as sess: sess.execute( f"""ALTER TABLE "{H.POLYGONS.LAYER}" ADD COLUMN "colour" TEXT;""" ) 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: r = sess.execute( f"""SELECT name, type FROM pragma_table_info('{H.POLYGONS.LAYER}');""" ) result = list(r) assert result == [ ("id", "INTEGER"), ("geom", "MULTIPOLYGON"), ("date_adjusted", "DATETIME"), ("survey_reference", "TEXT(50)"), ("adjusted_nodes", "MEDIUMINT"), ] r = cli_runner.invoke(["checkout", "main"]) assert r.exit_code == 0, r.stderr with wc.session() as sess: r = sess.execute( f"""SELECT name, type FROM pragma_table_info('{H.POLYGONS.LAYER}');""" ) result = list(r) assert result == [ ("id", "INTEGER"), ("geom", "MULTIPOLYGON"), ("date_adjusted", "DATETIME"), ("survey_reference", "TEXT(50)"), ("adjusted_nodes", "MEDIUMINT"), ("colour", "TEXT"), ]
def test_switch_xml_metadata_added(data_working_copy, cli_runner): with data_working_copy("table") as (repo_path, wc_path): wc = KartRepo(repo_path).working_copy with wc.session() as sess: sess.execute(""" INSERT INTO gpkg_metadata (id, md_scope, md_standard_uri, mime_type, metadata) VALUES (1, "dataset", "http://www.isotc211.org/2005/gmd", "text/xml", "<test metadata>"); """) sess.execute(""" INSERT INTO gpkg_metadata_reference (reference_scope, table_name, md_file_id) VALUES ("table", "countiestbl", 1); """) r = cli_runner.invoke(["commit", "-m", "change xml metadata"]) 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: xml_metadata = sess.execute(""" SELECT m.metadata FROM gpkg_metadata m JOIN gpkg_metadata_reference r ON m.id = r.md_file_id WHERE r.table_name = 'countiestbl' """).fetchone() assert not xml_metadata r = cli_runner.invoke(["checkout", "main"]) assert r.exit_code == 0, r.stderr with wc.session() as sess: xml_metadata = sess.execute(""" SELECT m.metadata FROM gpkg_metadata m JOIN gpkg_metadata_reference r ON m.id = r.md_file_id WHERE r.table_name = 'countiestbl' """).scalar() assert xml_metadata == "<test metadata>"
def test_reset_transaction(data_working_copy, cli_runner, edit_points): with data_working_copy("points") as (repo_path, wc_path): wc = KartRepo(repo_path).working_copy with wc.session() as sess: edit_points(sess) r = cli_runner.invoke(["status", "--output-format=json"]) assert r.exit_code == 0, r changes = json.loads( r.stdout)["kart.status/v1"]["workingCopy"]["changes"] assert changes == { H.POINTS.LAYER: { "feature": { "inserts": 1, "updates": 2, "deletes": 5 } } } with wc.session() as sess: # This modification makes the gpkg_kart_state table work like normal for reading, # but writing to it will fail due to the CHECK. sess.execute( """ALTER TABLE "gpkg_kart_state" RENAME TO "gpkg_kart_state_backup";""" ) value = sess.scalar("SELECT value FROM gpkg_kart_state_backup;") sess.execute(f""" CREATE TABLE "gpkg_kart_state" ("table_name" TEXT NOT NULL, "key" TEXT NOT NULL, "value" TEXT NULL CHECK("value" = '{value}')); """) sess.execute( """INSERT INTO "gpkg_kart_state" SELECT * FROM "gpkg_kart_state_backup";""" ) # This should fail and so the entire transaction should be rolled back. # Therefore, the GPKG should remain unchanged with 6 uncommitted changes - # even though the failed write to gpkg_kart_state happens after the changes # are discarded and after working copy is reset to the new commit - all of # that will be rolled back. with pytest.raises(sqlalchemy.exc.IntegrityError): r = cli_runner.invoke(["checkout", "HEAD^", "--discard-changes"]) with wc.session() as sess: sess.execute("DROP TABLE IF EXISTS gpkg_kart_state;") sess.execute( """ALTER TABLE "gpkg_kart_state_backup" RENAME TO "gpkg_kart_state";""" ) r = cli_runner.invoke(["status", "--output-format=json"]) assert r.exit_code == 0, r.stderr changes = json.loads( r.stdout)["kart.status/v1"]["workingCopy"]["changes"] assert changes == { H.POINTS.LAYER: { "feature": { "inserts": 1, "updates": 2, "deletes": 5 } } }