Adding tests for ethstore
This commit is contained in:
parent
8596134c0f
commit
930183831b
@ -25,7 +25,7 @@ use std::collections::HashMap;
|
||||
use std::time::{Instant, Duration};
|
||||
use util::{RwLock, Itertools};
|
||||
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 ethjson::misc::AccountMeta;
|
||||
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
|
||||
pub type DappId = String;
|
||||
|
||||
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;
|
||||
@ -155,7 +112,7 @@ impl AccountProvider {
|
||||
unlocked: RwLock::new(HashMap::new()),
|
||||
address_book: RwLock::new(AddressBook::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(),
|
||||
}
|
||||
}
|
||||
|
67
ethstore/src/dir/memory.rs
Normal file
67
ethstore/src/dir/memory.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use {SafeAccount, Error};
|
||||
|
||||
mod disk;
|
||||
mod geth;
|
||||
mod memory;
|
||||
mod parity;
|
||||
|
||||
pub enum DirectoryType {
|
||||
@ -36,4 +37,5 @@ pub trait KeyDirectory: Send + Sync {
|
||||
|
||||
pub use self::disk::DiskDirectory;
|
||||
pub use self::geth::GethDirectory;
|
||||
pub use self::memory::MemoryDirectory;
|
||||
pub use self::parity::ParityDirectory;
|
||||
|
@ -16,18 +16,16 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::mem;
|
||||
use ethkey::KeyPair;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use crypto::KEY_ITERATIONS;
|
||||
use random::Random;
|
||||
use ethkey::{Signature, Address, Message, Secret, Public};
|
||||
use ethkey::{Signature, Address, Message, Secret, Public, KeyPair};
|
||||
use dir::KeyDirectory;
|
||||
use account::SafeAccount;
|
||||
use {Error, SimpleSecretStore, SecretStore};
|
||||
use json;
|
||||
use json::UUID;
|
||||
use parking_lot::RwLock;
|
||||
use json::{self, UUID};
|
||||
use presale::PresaleWallet;
|
||||
use import;
|
||||
use {import, Error, SimpleSecretStore, SecretStore};
|
||||
|
||||
pub struct EthStore {
|
||||
store: EthMultiStore,
|
||||
@ -323,8 +321,120 @@ impl SimpleSecretStore for EthMultiStore {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn should_have_some_tests() {
|
||||
assert_eq!(true, false)
|
||||
|
||||
use dir::MemoryDirectory;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user