Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  env-migration.rs   Sprache: unbekannt

 
// Copyright 2018-2019 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

use std::{fs, path::Path};

use tempfile::Builder;

use rkv::{
    backend::{Lmdb, LmdbEnvironment, SafeMode, SafeModeEnvironment},
    Manager, Migrator, Rkv, StoreOptions, Value,
};

macro_rules! populate_store {
    ($env:expr) => {
        let store = $env
            .open_single("store", StoreOptions::create())
            .expect("opened");
        let mut writer = $env.write().expect("writer");
        store
            .put(&mut writer, "foo", &Value::I64(1234))
            .expect("wrote");
        store
            .put(&mut writer, "bar", &Value::Bool(true))
            .expect("wrote");
        store
            .put(&mut writer, "baz", &Value::Str("héllo, yöu"))
            .expect("wrote");
        writer.commit().expect("committed");
    };
}

#[test]
fn test_open_migrator_lmdb_to_safe() {
    let root = Builder::new()
        .prefix("test_open_migrator_lmdb_to_safe")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    // Populate source environment and persist to disk.
    {
        let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
        populate_store!(&src_env);
        src_env.sync(true).expect("synced");
    }
    // Check if the files were written to disk.
    {
        let mut datamdb = root.path().to_path_buf();
        let mut lockmdb = root.path().to_path_buf();
        datamdb.push("data.mdb");
        lockmdb.push("lock.mdb");
        assert!(datamdb.exists());
        assert!(lockmdb.exists());
    }
    // Verify that database was written to disk.
    {
        let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
        let store = src_env
            .open_single("store", StoreOptions::default())
            .expect("opened");
        let reader = src_env.read().expect("reader");
        assert_eq!(
            store.get(&reader, "foo").expect("read"),
            Some(Value::I64(1234))
        );
        assert_eq!(
            store.get(&reader, "bar").expect("read"),
            Some(Value::Bool(true))
        );
        assert_eq!(
            store.get(&reader, "baz").expect("read"),
            Some(Value::Str("héllo, yöu"))
        );
    }
    // Open and migrate.
    {
        let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
        Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env)
            .expect("migrated");
    }
    // Verify that the database was indeed migrated.
    {
        let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
        let store = dst_env
            .open_single("store", StoreOptions::default())
            .expect("opened");
        let reader = dst_env.read().expect("reader");
        assert_eq!(
            store.get(&reader, "foo").expect("read"),
            Some(Value::I64(1234))
        );
        assert_eq!(
            store.get(&reader, "bar").expect("read"),
            Some(Value::Bool(true))
        );
        assert_eq!(
            store.get(&reader, "baz").expect("read"),
            Some(Value::Str("héllo, yöu"))
        );
    }
    // Check if the old files were deleted from disk.
    {
        let mut datamdb = root.path().to_path_buf();
        let mut lockmdb = root.path().to_path_buf();
        datamdb.push("data.mdb");
        lockmdb.push("lock.mdb");
        assert!(!datamdb.exists());
        assert!(!lockmdb.exists());
    }
}

#[test]
fn test_open_migrator_safe_to_lmdb() {
    let root = Builder::new()
        .prefix("test_open_migrator_safe_to_lmdb")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    // Populate source environment and persist to disk.
    {
        let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
        populate_store!(&src_env);
        src_env.sync(true).expect("synced");
    }
    // Check if the files were written to disk.
    {
        let mut safebin = root.path().to_path_buf();
        safebin.push("data.safe.bin");
        assert!(safebin.exists());
    }
    // Verify that database was written to disk.
    {
        let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
        let store = src_env
            .open_single("store", StoreOptions::default())
            .expect("opened");
        let reader = src_env.read().expect("reader");
        assert_eq!(
            store.get(&reader, "foo").expect("read"),
            Some(Value::I64(1234))
        );
        assert_eq!(
            store.get(&reader, "bar").expect("read"),
            Some(Value::Bool(true))
        );
        assert_eq!(
            store.get(&reader, "baz").expect("read"),
            Some(Value::Str("héllo, yöu"))
        );
    }
    // Open and migrate.
    {
        let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
        Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env)
            .expect("migrated");
    }
    // Verify that the database was indeed migrated.
    {
        let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
        let store = dst_env
            .open_single("store", StoreOptions::default())
            .expect("opened");
        let reader = dst_env.read().expect("reader");
        assert_eq!(
            store.get(&reader, "foo").expect("read"),
            Some(Value::I64(1234))
        );
        assert_eq!(
            store.get(&reader, "bar").expect("read"),
            Some(Value::Bool(true))
        );
        assert_eq!(
            store.get(&reader, "baz").expect("read"),
            Some(Value::Str("héllo, yöu"))
        );
    }
    // Check if the old files were deleted from disk.
    {
        let mut safebin = root.path().to_path_buf();
        safebin.push("data.safe.bin");
        assert!(!safebin.exists());
    }
}

#[test]
fn test_open_migrator_round_trip() {
    let root = Builder::new()
        .prefix("test_open_migrator_lmdb_to_safe")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    // Populate source environment and persist to disk.
    {
        let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
        populate_store!(&src_env);
        src_env.sync(true).expect("synced");
    }
    // Open and migrate.
    {
        let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
        Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env)
            .expect("migrated");
    }
    // Open and migrate back.
    {
        let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
        Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env)
            .expect("migrated");
    }
    // Verify that the database was indeed migrated twice.
    {
        let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
        let store = dst_env
            .open_single("store", StoreOptions::default())
            .expect("opened");
        let reader = dst_env.read().expect("reader");
        assert_eq!(
            store.get(&reader, "foo").expect("read"),
            Some(Value::I64(1234))
        );
        assert_eq!(
            store.get(&reader, "bar").expect("read"),
            Some(Value::Bool(true))
        );
        assert_eq!(
            store.get(&reader, "baz").expect("read"),
            Some(Value::Str("héllo, yöu"))
        );
    }
    // Check if the right files are finally present on disk.
    {
        let mut datamdb = root.path().to_path_buf();
        let mut lockmdb = root.path().to_path_buf();
        let mut safebin = root.path().to_path_buf();
        datamdb.push("data.mdb");
        lockmdb.push("lock.mdb");
        safebin.push("data.safe.bin");
        assert!(datamdb.exists());
        assert!(lockmdb.exists());
        assert!(!safebin.exists());
    }
}

#[test]
fn test_easy_migrator_no_dir_1() {
    let root = Builder::new()
        .prefix("test_easy_migrator_no_dir")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    // This won't fail with IoError even though the path is a bogus path, because this
    // is the "easy mode" migration which automatically handles (ignores) this error.
    let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    Migrator::easy_migrate_lmdb_to_safe_mode(Path::new("bogus"), &dst_env).expect("migrated");

    let mut datamdb = root.path().to_path_buf();
    let mut lockmdb = root.path().to_path_buf();
    let mut safebin = root.path().to_path_buf();
    datamdb.push("data.mdb");
    lockmdb.push("lock.mdb");
    safebin.push("data.safe.bin");
    assert!(!datamdb.exists());
    assert!(!lockmdb.exists());
    assert!(!safebin.exists()); // safe mode doesn't write an empty db to disk
}

#[test]
fn test_easy_migrator_no_dir_2() {
    let root = Builder::new()
        .prefix("test_easy_migrator_no_dir")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    // This won't fail with IoError even though the path is a bogus path, because this
    // is the "easy mode" migration which automatically handles (ignores) this error.
    let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    Migrator::easy_migrate_safe_mode_to_lmdb(Path::new("bogus"), &dst_env).expect("migrated");

    let mut datamdb = root.path().to_path_buf();
    let mut lockmdb = root.path().to_path_buf();
    let mut safebin = root.path().to_path_buf();
    datamdb.push("data.mdb");
    lockmdb.push("lock.mdb");
    safebin.push("data.safe.bin");
    assert!(datamdb.exists()); // lmdb writes an empty db to disk
    assert!(lockmdb.exists());
    assert!(!safebin.exists());
}

#[test]
fn test_easy_migrator_invalid_1() {
    let root = Builder::new()
        .prefix("test_easy_migrator_invalid")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let dbfile = root.path().join("data.mdb");
    fs::write(dbfile, "bogus").expect("dbfile created");

    // This won't fail with FileInvalid even though the database is a bogus file, because this
    // is the "easy mode" migration which automatically handles (ignores) this error.
    let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    Migrator::easy_migrate_lmdb_to_safe_mode(root.path(), &dst_env).expect("migrated");

    let mut datamdb = root.path().to_path_buf();
    let mut lockmdb = root.path().to_path_buf();
    let mut safebin = root.path().to_path_buf();
    datamdb.push("data.mdb");
    lockmdb.push("lock.mdb");
    safebin.push("data.safe.bin");
    assert!(datamdb.exists()); // corrupted db isn't deleted
    assert!(lockmdb.exists());
    assert!(!safebin.exists());
}

#[test]
fn test_easy_migrator_invalid_2() {
    let root = Builder::new()
        .prefix("test_easy_migrator_invalid")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let dbfile = root.path().join("data.safe.bin");
    fs::write(dbfile, "bogus").expect("dbfile created");

    // This won't fail with FileInvalid even though the database is a bogus file, because this
    // is the "easy mode" migration which automatically handles (ignores) this error.
    let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    Migrator::easy_migrate_safe_mode_to_lmdb(root.path(), &dst_env).expect("migrated");

    let mut datamdb = root.path().to_path_buf();
    let mut lockmdb = root.path().to_path_buf();
    let mut safebin = root.path().to_path_buf();
    datamdb.push("data.mdb");
    lockmdb.push("lock.mdb");
    safebin.push("data.safe.bin");
    assert!(datamdb.exists()); // lmdb writes an empty db to disk
    assert!(lockmdb.exists());
    assert!(safebin.exists()); // corrupted db isn't deleted
}

#[test]
#[should_panic(expected = "migrated: SourceEmpty")]
fn test_migrator_lmdb_to_safe_1() {
    let root = Builder::new()
        .prefix("test_migrate_lmdb_to_safe")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    Migrator::migrate_lmdb_to_safe_mode(&src_env, &dst_env).expect("migrated");
}

#[test]
#[should_panic(expected = "migrated: DestinationNotEmpty")]
fn test_migrator_lmdb_to_safe_2() {
    let root = Builder::new()
        .prefix("test_migrate_lmdb_to_safe")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    populate_store!(&src_env);
    let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    populate_store!(&dst_env);
    Migrator::migrate_lmdb_to_safe_mode(&src_env, &dst_env).expect("migrated");
}

#[test]
fn test_migrator_lmdb_to_safe_3() {
    let root = Builder::new()
        .prefix("test_migrate_lmdb_to_safe")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    populate_store!(&src_env);
    let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    Migrator::migrate_lmdb_to_safe_mode(&src_env, &dst_env).expect("migrated");

    let store = dst_env
        .open_single("store", StoreOptions::default())
        .expect("opened");
    let reader = dst_env.read().expect("reader");
    assert_eq!(
        store.get(&reader, "foo").expect("read"),
        Some(Value::I64(1234))
    );
    assert_eq!(
        store.get(&reader, "bar").expect("read"),
        Some(Value::Bool(true))
    );
    assert_eq!(
        store.get(&reader, "baz").expect("read"),
        Some(Value::Str("héllo, yöu"))
    );
}

#[test]
#[should_panic(expected = "migrated: SourceEmpty")]
fn test_migrator_safe_to_lmdb_1() {
    let root = Builder::new()
        .prefix("test_migrate_safe_to_lmdb")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    Migrator::migrate_safe_mode_to_lmdb(&src_env, &dst_env).expect("migrated");
}

#[test]
#[should_panic(expected = "migrated: DestinationNotEmpty")]
fn test_migrator_safe_to_lmdb_2() {
    let root = Builder::new()
        .prefix("test_migrate_safe_to_lmdb")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    populate_store!(&src_env);
    let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    populate_store!(&dst_env);
    Migrator::migrate_safe_mode_to_lmdb(&src_env, &dst_env).expect("migrated");
}

#[test]
fn test_migrator_safe_to_lmdb_3() {
    let root = Builder::new()
        .prefix("test_migrate_safe_to_lmdb")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    populate_store!(&src_env);
    let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    Migrator::migrate_safe_mode_to_lmdb(&src_env, &dst_env).expect("migrated");

    let store = dst_env
        .open_single("store", StoreOptions::default())
        .expect("opened");
    let reader = dst_env.read().expect("reader");
    assert_eq!(
        store.get(&reader, "foo").expect("read"),
        Some(Value::I64(1234))
    );
    assert_eq!(
        store.get(&reader, "bar").expect("read"),
        Some(Value::Bool(true))
    );
    assert_eq!(
        store.get(&reader, "baz").expect("read"),
        Some(Value::Str("héllo, yöu"))
    );
}

#[test]
fn test_easy_migrator_failed_migration_1() {
    let root = Builder::new()
        .prefix("test_easy_migrator_failed_migration_1")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let dbfile = root.path().join("data.mdb");
    fs::write(&dbfile, "bogus").expect("bogus dbfile created");

    // This won't fail with FileInvalid even though the database is a bogus file, because this
    // is the "easy mode" migration which automatically handles (ignores) this error.
    let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    Migrator::easy_migrate_lmdb_to_safe_mode(root.path(), &dst_env).expect("migrated");

    // Populate destination environment and persist to disk.
    populate_store!(&dst_env);
    dst_env.sync(true).expect("synced");

    // Delete bogus file and create a valid source environment in its place.
    fs::remove_file(&dbfile).expect("bogus dbfile removed");
    let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    populate_store!(&src_env);
    src_env.sync(true).expect("synced");

    // Attempt to migrate again. This should *NOT* fail with DestinationNotEmpty.
    Migrator::easy_migrate_lmdb_to_safe_mode(root.path(), &dst_env).expect("migrated");
}

#[test]
fn test_easy_migrator_failed_migration_2() {
    let root = Builder::new()
        .prefix("test_easy_migrator_failed_migration_2")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    let dbfile = root.path().join("data.safe.bin");
    fs::write(&dbfile, "bogus").expect("bogus dbfile created");

    // This won't fail with FileInvalid even though the database is a bogus file, because this
    // is the "easy mode" migration which automatically handles (ignores) this error.
    let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
    Migrator::easy_migrate_safe_mode_to_lmdb(root.path(), &dst_env).expect("migrated");

    // Populate destination environment and persist to disk.
    populate_store!(&dst_env);
    dst_env.sync(true).expect("synced");

    // Delete bogus file and create a valid source environment in its place.
    fs::remove_file(&dbfile).expect("bogus dbfile removed");
    let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
    populate_store!(&src_env);
    src_env.sync(true).expect("synced");

    // Attempt to migrate again. This should *NOT* fail with DestinationNotEmpty.
    Migrator::easy_migrate_safe_mode_to_lmdb(root.path(), &dst_env).expect("migrated");
}

fn test_easy_migrator_from_manager_failed_migration_1() {
    let root = Builder::new()
        .prefix("test_easy_migrator_from_manager_failed_migration_1")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    {
        let mut src_manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
        let created_src_arc = src_manager
            .get_or_create(root.path(), Rkv::new::<Lmdb>)
            .unwrap();
        let src_env = created_src_arc.read().unwrap();
        populate_store!(&src_env);
        src_env.sync(true).expect("synced");
    }
    {
        let mut dst_manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
        let created_dst_arc_1 = dst_manager
            .get_or_create(root.path(), Rkv::new::<SafeMode>)
            .unwrap();
        let dst_env_1 = created_dst_arc_1.read().unwrap();
        populate_store!(&dst_env_1);
        dst_env_1.sync(true).expect("synced");
    }

    // Attempt to migrate again in a new env. This should *NOT* fail with DestinationNotEmpty.
    let dst_manager = Manager::<SafeModeEnvironment>::singleton().read().unwrap();
    let created_dst_arc_2 = dst_manager.get(root.path()).unwrap().unwrap();
    let dst_env_2 = created_dst_arc_2.read().unwrap();
    Migrator::easy_migrate_lmdb_to_safe_mode(root.path(), dst_env_2).expect("migrated");
}

fn test_easy_migrator_from_manager_failed_migration_2() {
    let root = Builder::new()
        .prefix("test_easy_migrator_from_manager_failed_migration_2")
        .tempdir()
        .expect("tempdir");
    fs::create_dir_all(root.path()).expect("dir created");

    {
        let mut src_manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
        let created_src_arc = src_manager
            .get_or_create(root.path(), Rkv::new::<SafeMode>)
            .unwrap();
        let src_env = created_src_arc.read().unwrap();
        populate_store!(&src_env);
        src_env.sync(true).expect("synced");
    }
    {
        let mut dst_manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
        let created_dst_arc_1 = dst_manager
            .get_or_create(root.path(), Rkv::new::<Lmdb>)
            .unwrap();
        let dst_env_1 = created_dst_arc_1.read().unwrap();
        populate_store!(&dst_env_1);
        dst_env_1.sync(true).expect("synced");
    }

    // Attempt to migrate again in a new env. This should *NOT* fail with DestinationNotEmpty.
    let dst_manager = Manager::<LmdbEnvironment>::singleton().read().unwrap();
    let created_dst_arc_2 = dst_manager.get(root.path()).unwrap().unwrap();
    let dst_env_2 = created_dst_arc_2.read().unwrap();
    Migrator::easy_migrate_safe_mode_to_lmdb(root.path(), dst_env_2).expect("migrated");
}

#[test]
fn test_easy_migrator_from_manager_failed_migration() {
    test_easy_migrator_from_manager_failed_migration_1();
    test_easy_migrator_from_manager_failed_migration_2();
}

[ Dauer der Verarbeitung: 0.33 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge