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 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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 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;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user