Skip to content

Commit

Permalink
Fix mbtiles validation, CI, and logging (#903)
Browse files Browse the repository at this point in the history
  • Loading branch information
nyurik authored Sep 29, 2023
1 parent 73edd19 commit 6f08aa9
Show file tree
Hide file tree
Showing 38 changed files with 143 additions and 101 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ test-int: clean-test install-sqlx
# Run integration tests and save its output as the new expected output
bless: start clean-test
rm -rf tests/temp
cargo test --features bless-tests
tests/test.sh
rm -rf tests/expected
Expand Down Expand Up @@ -216,7 +217,7 @@ git-pre-push: stop start
# Update sqlite database schema.
prepare-sqlite: install-sqlx
mkdir -p martin-mbtiles/.sqlx
cd martin-mbtiles && cargo sqlx prepare --database-url sqlite://$PWD/../tests/fixtures/files/world_cities.mbtiles -- --lib --tests
cd martin-mbtiles && cargo sqlx prepare --database-url sqlite://$PWD/../tests/fixtures/mbtiles/world_cities.mbtiles -- --lib --tests

# Install SQLX cli if not already installed.
[private]
Expand Down
3 changes: 2 additions & 1 deletion martin-mbtiles/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ rust-version.workspace = true
[features]
# TODO: Disable "cli" feature in default builds
default = ["cli", "native-tls"]
cli = ["dep:anyhow", "dep:clap", "dep:tokio"]
cli = ["dep:anyhow", "dep:clap", "dep:env_logger", "dep:tokio"]
# One of the following two must be used
native-tls = ["sqlx/runtime-tokio-native-tls"]
rustls = ["sqlx/runtime-tokio-rustls"]
Expand All @@ -30,6 +30,7 @@ tilejson.workspace = true
# Bin dependencies
anyhow = { workspace = true, optional = true }
clap = { workspace = true, optional = true }
env_logger = { workspace = true, optional = true }
serde_yaml.workspace = true
sqlite-hashes.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
Expand Down
33 changes: 21 additions & 12 deletions martin-mbtiles/src/bin/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use std::path::{Path, PathBuf};

use clap::{Parser, Subcommand};
use log::{error, LevelFilter};
use martin_mbtiles::{
apply_mbtiles_diff, IntegrityCheckType, MbtResult, Mbtiles, TileCopierOptions,
};
use sqlx::sqlite::SqliteConnectOptions;
use sqlx::{Connection, SqliteConnection};

#[derive(Parser, PartialEq, Eq, Debug)]
#[command(
Expand Down Expand Up @@ -73,9 +72,23 @@ enum Commands {
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Args::parse();
async fn main() {
env_logger::builder()
.filter_level(LevelFilter::Info)
.format_indent(None)
.format_module_path(false)
.format_target(false)
.format_timestamp(None)
.init();

if let Err(err) = main_int().await {
error!("{err}");
std::process::exit(1);
}
}

async fn main_int() -> anyhow::Result<()> {
let args = Args::parse();
match args.command {
Commands::MetaAll { file } => {
meta_print_all(file.as_path()).await?;
Expand Down Expand Up @@ -109,17 +122,15 @@ async fn main() -> anyhow::Result<()> {

async fn meta_print_all(file: &Path) -> anyhow::Result<()> {
let mbt = Mbtiles::new(file)?;
let opt = SqliteConnectOptions::new().filename(file).read_only(true);
let mut conn = SqliteConnection::connect_with(&opt).await?;
let mut conn = mbt.open_with_hashes(true).await?;
let metadata = mbt.get_metadata(&mut conn).await?;
println!("{}", serde_yaml::to_string(&metadata)?);
Ok(())
}

async fn meta_get_value(file: &Path, key: &str) -> MbtResult<()> {
let mbt = Mbtiles::new(file)?;
let opt = SqliteConnectOptions::new().filename(file).read_only(true);
let mut conn = SqliteConnection::connect_with(&opt).await?;
let mut conn = mbt.open_with_hashes(true).await?;
if let Some(s) = mbt.get_metadata_value(&mut conn, key).await? {
println!("{s}");
}
Expand All @@ -128,8 +139,7 @@ async fn meta_get_value(file: &Path, key: &str) -> MbtResult<()> {

async fn meta_set_value(file: &Path, key: &str, value: Option<String>) -> MbtResult<()> {
let mbt = Mbtiles::new(file)?;
let opt = SqliteConnectOptions::new().filename(file);
let mut conn = SqliteConnection::connect_with(&opt).await?;
let mut conn = mbt.open_with_hashes(false).await?;
mbt.set_metadata_value(&mut conn, key, value).await
}

Expand All @@ -139,8 +149,7 @@ async fn validate_mbtiles(
update_agg_tiles_hash: bool,
) -> MbtResult<()> {
let mbt = Mbtiles::new(file)?;
let opt = SqliteConnectOptions::new().filename(file).read_only(true);
let mut conn = SqliteConnection::connect_with(&opt).await?;
let mut conn = mbt.open_with_hashes(!update_agg_tiles_hash).await?;
mbt.check_integrity(&mut conn, check_type).await?;
mbt.check_each_tile_hash(&mut conn).await?;
if update_agg_tiles_hash {
Expand Down
51 changes: 25 additions & 26 deletions martin-mbtiles/src/mbtiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,9 @@ impl Mbtiles {
where
for<'e> &'e mut T: SqliteExecutor<'e>,
{
let filepath = self.filepath();
if integrity_check == IntegrityCheckType::Off {
info!("Skipping integrity check for {filepath}");
return Ok(());
}

Expand All @@ -452,30 +454,32 @@ impl Mbtiles {

if result.len() > 1
|| result.get(0).ok_or(FailedIntegrityCheck(
self.filepath().to_string(),
filepath.to_string(),
vec!["SQLite could not perform integrity check".to_string()],
))? != "ok"
{
return Err(FailedIntegrityCheck(self.filepath().to_string(), result));
}

info!("{integrity_check:?} integrity check passed for {filepath}");
Ok(())
}

pub async fn check_agg_tiles_hashes<T>(&self, conn: &mut T) -> MbtResult<()>
where
for<'e> &'e mut T: SqliteExecutor<'e>,
{
let filepath = self.filepath();
let Some(stored) = self.get_agg_tiles_hash(&mut *conn).await? else {
return Err(AggHashValueNotFound(self.filepath().to_string()));
return Err(AggHashValueNotFound(filepath.to_string()));
};

let computed = calc_agg_tiles_hash(&mut *conn).await?;
if stored != computed {
let file = self.filepath().to_string();
let file = filepath.to_string();
return Err(AggHashMismatch(computed, stored, file));
}

info!("The agg_tiles_hashes={computed} has been verified for {filepath}");
Ok(())
}

Expand All @@ -486,23 +490,15 @@ impl Mbtiles {
{
let old_hash = self.get_agg_tiles_hash(&mut *conn).await?;
let hash = calc_agg_tiles_hash(&mut *conn).await?;
let path = self.filepath();
if old_hash.as_ref() == Some(&hash) {
info!(
"agg_tiles_hash is already set to the correct value `{hash}` in {}",
self.filepath()
);
info!("agg_tiles_hash is already set to the correct value `{hash}` in {path}");
Ok(())
} else {
if let Some(old_hash) = old_hash {
info!(
"Updating agg_tiles_hash from {old_hash} to {hash} in {}",
self.filepath()
);
info!("Updating agg_tiles_hash from {old_hash} to {hash} in {path}");
} else {
info!(
"Initializing agg_tiles_hash to {hash} in {}",
self.filepath()
);
info!("Creating new metadata value agg_tiles_hash = {hash} in {path}");
}
self.set_metadata_value(&mut *conn, "agg_tiles_hash", Some(hash))
.await
Expand Down Expand Up @@ -550,7 +546,10 @@ impl Mbtiles {
v.get(0),
v.get(1),
))
})
})?;

info!("All tile hashes are valid for {}", self.filepath());
Ok(())
}
}

Expand Down Expand Up @@ -610,15 +609,15 @@ mod tests {

#[actix_rt::test]
async fn mbtiles_meta() {
let filepath = "../tests/fixtures/files/geography-class-jpg.mbtiles";
let filepath = "../tests/fixtures/mbtiles/geography-class-jpg.mbtiles";
let mbt = Mbtiles::new(filepath).unwrap();
assert_eq!(mbt.filepath(), filepath);
assert_eq!(mbt.filename(), "geography-class-jpg");
}

#[actix_rt::test]
async fn metadata_jpeg() {
let (mut conn, mbt) = open("../tests/fixtures/files/geography-class-jpg.mbtiles").await;
let (mut conn, mbt) = open("../tests/fixtures/mbtiles/geography-class-jpg.mbtiles").await;
let metadata = mbt.get_metadata(&mut conn).await.unwrap();
let tj = metadata.tilejson;

Expand All @@ -635,7 +634,7 @@ mod tests {

#[actix_rt::test]
async fn metadata_mvt() {
let (mut conn, mbt) = open("../tests/fixtures/files/world_cities.mbtiles").await;
let (mut conn, mbt) = open("../tests/fixtures/mbtiles/world_cities.mbtiles").await;
let metadata = mbt.get_metadata(&mut conn).await.unwrap();
let tj = metadata.tilejson;

Expand Down Expand Up @@ -666,7 +665,7 @@ mod tests {

#[actix_rt::test]
async fn metadata_get_key() {
let (mut conn, mbt) = open("../tests/fixtures/files/world_cities.mbtiles").await;
let (mut conn, mbt) = open("../tests/fixtures/mbtiles/world_cities.mbtiles").await;

let res = mbt.get_metadata_value(&mut conn, "bounds").await.unwrap();
assert_eq!(res.unwrap(), "-123.123590,-37.818085,174.763027,59.352706");
Expand Down Expand Up @@ -726,15 +725,15 @@ mod tests {

#[actix_rt::test]
async fn detect_type() {
let (mut conn, mbt) = open("../tests/fixtures/files/world_cities.mbtiles").await;
let (mut conn, mbt) = open("../tests/fixtures/mbtiles/world_cities.mbtiles").await;
let res = mbt.detect_type(&mut conn).await.unwrap();
assert_eq!(res, MbtType::Flat);

let (mut conn, mbt) = open("../tests/fixtures/files/zoomed_world_cities.mbtiles").await;
let (mut conn, mbt) = open("../tests/fixtures/mbtiles/zoomed_world_cities.mbtiles").await;
let res = mbt.detect_type(&mut conn).await.unwrap();
assert_eq!(res, MbtType::FlatWithHash);

let (mut conn, mbt) = open("../tests/fixtures/files/geography-class-jpg.mbtiles").await;
let (mut conn, mbt) = open("../tests/fixtures/mbtiles/geography-class-jpg.mbtiles").await;
let res = mbt.detect_type(&mut conn).await.unwrap();
assert_eq!(res, MbtType::Normalized);

Expand All @@ -745,7 +744,7 @@ mod tests {

#[actix_rt::test]
async fn validate_valid_file() {
let (mut conn, mbt) = open("../tests/fixtures/files/zoomed_world_cities.mbtiles").await;
let (mut conn, mbt) = open("../tests/fixtures/mbtiles/zoomed_world_cities.mbtiles").await;

mbt.check_integrity(&mut conn, IntegrityCheckType::Quick)
.await
Expand All @@ -755,7 +754,7 @@ mod tests {
#[actix_rt::test]
async fn validate_invalid_file() {
let (mut conn, mbt) =
open("../tests/fixtures/files/invalid/invalid_zoomed_world_cities.mbtiles").await;
open("../tests/fixtures/files/invalid_zoomed_world_cities.mbtiles").await;
let result = mbt.check_agg_tiles_hashes(&mut conn).await;
assert!(matches!(result, Err(MbtError::AggHashMismatch(..))));
}
Expand Down
Loading

0 comments on commit 6f08aa9

Please sign in to comment.