Adding tests for ethstore

This commit is contained in:
Tomasz Drwięga 2016-12-09 09:45:34 +00:00
parent 8596134c0f
commit 930183831b
4 changed files with 192 additions and 56 deletions

View File

@ -25,7 +25,7 @@ use std::collections::HashMap;
use std::time::{Instant, Duration}; use std::time::{Instant, Duration};
use util::{RwLock, Itertools}; use util::{RwLock, Itertools};
use ethstore::{SimpleSecretStore, SecretStore, Error as SSError, SafeAccount, EthStore, EthMultiStore, random_string}; use ethstore::{SimpleSecretStore, SecretStore, Error as SSError, SafeAccount, EthStore, EthMultiStore, random_string};
use ethstore::dir::{KeyDirectory}; use ethstore::dir::{KeyDirectory, MemoryDirectory};
use ethstore::ethkey::{Address, Message, Public, Secret, Random, Generator}; use ethstore::ethkey::{Address, Message, Public, Secret, Random, Generator};
use ethjson::misc::AccountMeta; use ethjson::misc::AccountMeta;
pub use ethstore::ethkey::Signature; pub use ethstore::ethkey::Signature;
@ -73,54 +73,11 @@ impl From<SSError> for Error {
} }
} }
#[derive(Default)]
struct NullDir {
accounts: RwLock<HashMap<Address, Vec<SafeAccount>>>,
}
impl KeyDirectory for NullDir {
fn load(&self) -> Result<Vec<SafeAccount>, SSError> {
Ok(self.accounts.read().values().cloned().flatten().collect())
}
fn update(&self, account: SafeAccount) -> Result<SafeAccount, SSError> {
let mut lock = self.accounts.write();
let mut accounts = lock.entry(account.address.clone()).or_insert_with(Vec::new);
// If the filename is the same we just need to replace the entry
accounts.retain(|acc| acc.filename != account.filename);
accounts.push(account.clone());
Ok(account)
}
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, SSError> {
let mut lock = self.accounts.write();
let mut accounts = lock.entry(account.address.clone()).or_insert_with(Vec::new);
accounts.push(account.clone());
Ok(account)
}
fn remove(&self, account: &SafeAccount) -> Result<(), SSError> {
let mut accounts = self.accounts.write();
let is_empty = if let Some(mut accounts) = accounts.get_mut(&account.address) {
if let Some(position) = accounts.iter().position(|acc| acc == account) {
accounts.remove(position);
}
accounts.is_empty()
} else {
false
};
if is_empty {
accounts.remove(&account.address);
}
Ok(())
}
}
/// Dapp identifier /// Dapp identifier
pub type DappId = String; pub type DappId = String;
fn transient_sstore() -> EthMultiStore { fn transient_sstore() -> EthMultiStore {
EthMultiStore::open(Box::new(NullDir::default())).expect("NullDir load always succeeds; qed") EthMultiStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory load always succeeds; qed")
} }
type AccountToken = String; type AccountToken = String;
@ -155,7 +112,7 @@ impl AccountProvider {
unlocked: RwLock::new(HashMap::new()), unlocked: RwLock::new(HashMap::new()),
address_book: RwLock::new(AddressBook::transient()), address_book: RwLock::new(AddressBook::transient()),
dapps_settings: RwLock::new(DappsSettingsStore::transient()), dapps_settings: RwLock::new(DappsSettingsStore::transient()),
sstore: Box::new(EthStore::open(Box::new(NullDir::default())).expect("NullDir load always succeeds; qed")), sstore: Box::new(EthStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory load always succeeds; qed")),
transient_sstore: transient_sstore(), transient_sstore: transient_sstore(),
} }
} }

View File

@ -0,0 +1,67 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::HashMap;
use parking_lot::RwLock;
use itertools::Itertools;
use ethkey::Address;
use {SafeAccount, Error};
use super::KeyDirectory;
#[derive(Default)]
pub struct MemoryDirectory {
accounts: RwLock<HashMap<Address, Vec<SafeAccount>>>,
}
impl KeyDirectory for MemoryDirectory {
fn load(&self) -> Result<Vec<SafeAccount>, Error> {
Ok(self.accounts.read().values().cloned().flatten().collect())
}
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
let mut lock = self.accounts.write();
let mut accounts = lock.entry(account.address.clone()).or_insert_with(Vec::new);
// If the filename is the same we just need to replace the entry
accounts.retain(|acc| acc.filename != account.filename);
accounts.push(account.clone());
Ok(account)
}
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
let mut lock = self.accounts.write();
let mut accounts = lock.entry(account.address.clone()).or_insert_with(Vec::new);
accounts.push(account.clone());
Ok(account)
}
fn remove(&self, account: &SafeAccount) -> Result<(), Error> {
let mut accounts = self.accounts.write();
let is_empty = if let Some(mut accounts) = accounts.get_mut(&account.address) {
if let Some(position) = accounts.iter().position(|acc| acc == account) {
accounts.remove(position);
}
accounts.is_empty()
} else {
false
};
if is_empty {
accounts.remove(&account.address);
}
Ok(())
}
}

View File

@ -19,6 +19,7 @@ use {SafeAccount, Error};
mod disk; mod disk;
mod geth; mod geth;
mod memory;
mod parity; mod parity;
pub enum DirectoryType { pub enum DirectoryType {
@ -36,4 +37,5 @@ pub trait KeyDirectory: Send + Sync {
pub use self::disk::DiskDirectory; pub use self::disk::DiskDirectory;
pub use self::geth::GethDirectory; pub use self::geth::GethDirectory;
pub use self::memory::MemoryDirectory;
pub use self::parity::ParityDirectory; pub use self::parity::ParityDirectory;

View File

@ -16,18 +16,16 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::mem; use std::mem;
use ethkey::KeyPair; use parking_lot::RwLock;
use crypto::KEY_ITERATIONS; use crypto::KEY_ITERATIONS;
use random::Random; use random::Random;
use ethkey::{Signature, Address, Message, Secret, Public}; use ethkey::{Signature, Address, Message, Secret, Public, KeyPair};
use dir::KeyDirectory; use dir::KeyDirectory;
use account::SafeAccount; use account::SafeAccount;
use {Error, SimpleSecretStore, SecretStore}; use json::{self, UUID};
use json;
use json::UUID;
use parking_lot::RwLock;
use presale::PresaleWallet; use presale::PresaleWallet;
use import; use {import, Error, SimpleSecretStore, SecretStore};
pub struct EthStore { pub struct EthStore {
store: EthMultiStore, store: EthMultiStore,
@ -323,8 +321,120 @@ impl SimpleSecretStore for EthMultiStore {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test]
fn should_have_some_tests() { use dir::MemoryDirectory;
assert_eq!(true, false) use ethkey::{Random, Generator, KeyPair};
use secret_store::{SimpleSecretStore, SecretStore};
use super::{EthStore, EthMultiStore};
fn keypair() -> KeyPair {
Random.generate().unwrap()
} }
fn store() -> EthStore {
EthStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory always load successfuly; qed")
}
fn multi_store() -> EthMultiStore {
EthMultiStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory always load successfuly; qed")
}
#[test]
fn should_insert_account_successfully() {
// given
let store = store();
let keypair = keypair();
// when
let address = store.insert_account(keypair.secret().clone(), "test").unwrap();
// then
assert_eq!(address, keypair.address());
assert!(store.get(&address).is_ok(), "Should contain account.");
assert_eq!(store.accounts().unwrap().len(), 1, "Should have one account.");
}
#[test]
fn should_update_meta_and_name() {
// given
let store = store();
let keypair = keypair();
let address = store.insert_account(keypair.secret().clone(), "test").unwrap();
assert_eq!(&store.meta(&address).unwrap(), "{}");
assert_eq!(&store.name(&address).unwrap(), "");
// when
store.set_meta(&address, "meta".into()).unwrap();
store.set_name(&address, "name".into()).unwrap();
// then
assert_eq!(&store.meta(&address).unwrap(), "meta");
assert_eq!(&store.name(&address).unwrap(), "name");
assert_eq!(store.accounts().unwrap().len(), 1);
}
#[test]
fn should_remove_account() {
// given
let store = store();
let keypair = keypair();
let address = store.insert_account(keypair.secret().clone(), "test").unwrap();
// when
store.remove_account(&address, "test").unwrap();
// then
assert_eq!(store.accounts().unwrap().len(), 0, "Should remove account.");
}
#[test]
fn should_return_true_if_password_is_correct() {
// given
let store = store();
let keypair = keypair();
let address = store.insert_account(keypair.secret().clone(), "test").unwrap();
// when
let res1 = store.test_password(&address, "x").unwrap();
let res2 = store.test_password(&address, "test").unwrap();
assert!(!res1, "First password should be invalid.");
assert!(res2, "Second password should be correct.");
}
#[test]
fn multistore_should_be_able_to_have_the_same_account_twice() {
// given
let store = multi_store();
let keypair = keypair();
let address = store.insert_account(keypair.secret().clone(), "test").unwrap();
let address2 = store.insert_account(keypair.secret().clone(), "xyz").unwrap();
assert_eq!(address, address2);
// when
assert!(store.remove_account(&address, "test").is_ok(), "First password should work.");
assert_eq!(store.accounts().unwrap().len(), 1);
assert!(store.remove_account(&address, "xyz").is_ok(), "Second password should work too.");
assert_eq!(store.accounts().unwrap().len(), 0);
}
#[test]
fn should_copy_account() {
// given
let store = store();
let multi_store = multi_store();
let keypair = keypair();
let address = store.insert_account(keypair.secret().clone(), "test").unwrap();
assert_eq!(multi_store.accounts().unwrap().len(), 0);
// when
store.copy_account(&multi_store, &address, "test", "xyz").unwrap();
// then
assert!(store.test_password(&address, "test").unwrap(), "First password should work for store.");
assert!(multi_store.sign(&address, "xyz", &Default::default()).is_ok(), "Second password should work for second store.");
assert_eq!(multi_store.accounts().unwrap().len(), 1);
}
} }