Browse Source

Merge pull request #1246 from mnaamani/re-enable-node-tests

Node: re-enabled some unit tests
shamil-gadelshin 4 years ago
parent
commit
3945467324
5 changed files with 460 additions and 317 deletions
  1. 1 1
      .travis.yml
  2. 135 0
      Cargo.lock
  3. 1 1
      node/Cargo.toml
  4. 79 68
      node/src/chain_spec/mod.rs
  5. 244 247
      node/src/service.rs

+ 1 - 1
.travis.yml

@@ -36,7 +36,7 @@ before_script:
 script:
   - export WASM_BUILD_TOOLCHAIN=nightly-2020-05-23
   - BUILD_DUMMY_WASM_BINARY=1 cargo clippy --release --all -- -D warnings
-  - travis_wait 50 cargo test --release --verbose --all
+  - travis_wait 75 cargo test --release --verbose --all -- --ignored
   - cargo build --release
   - ls -l ./target/release/wbuild/joystream-node-runtime/
   - ./target/release/joystream-node --version

+ 135 - 0
Cargo.lock

@@ -2024,6 +2024,7 @@ dependencies = [
  "sc-network",
  "sc-rpc-api",
  "sc-service",
+ "sc-service-test",
  "sc-transaction-pool",
  "serde",
  "serde_json",
@@ -5629,6 +5630,43 @@ dependencies = [
  "wasm-timer",
 ]
 
+[[package]]
+name = "sc-service-test"
+version = "2.0.0-rc4"
+source = "git+https://github.com/paritytech/substrate.git?rev=00768a1f21a579c478fe5d4f51e1fa71f7db9fd4#00768a1f21a579c478fe5d4f51e1fa71f7db9fd4"
+dependencies = [
+ "env_logger",
+ "fdlimit",
+ "futures 0.1.29",
+ "futures 0.3.4",
+ "hex-literal",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sc-block-builder",
+ "sc-client-api",
+ "sc-client-db",
+ "sc-executor",
+ "sc-light",
+ "sc-network",
+ "sc-service",
+ "sp-api",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-externalities",
+ "sp-panic-handler",
+ "sp-runtime",
+ "sp-state-machine",
+ "sp-storage",
+ "sp-transaction-pool",
+ "sp-trie",
+ "substrate-test-runtime",
+ "substrate-test-runtime-client",
+ "tempfile",
+ "tokio 0.1.22",
+]
+
 [[package]]
 name = "sc-state-db"
 version = "0.8.0-rc4"
@@ -6205,6 +6243,20 @@ dependencies = [
  "wasm-timer",
 ]
 
+[[package]]
+name = "sp-consensus-aura"
+version = "0.8.0-rc4"
+source = "git+https://github.com/paritytech/substrate.git?rev=00768a1f21a579c478fe5d4f51e1fa71f7db9fd4#00768a1f21a579c478fe5d4f51e1fa71f7db9fd4"
+dependencies = [
+ "parity-scale-codec",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+ "sp-timestamp",
+]
+
 [[package]]
 name = "sp-consensus-babe"
 version = "0.8.0-rc4"
@@ -6816,6 +6868,89 @@ dependencies = [
  "tokio 0.2.22",
 ]
 
+[[package]]
+name = "substrate-test-client"
+version = "2.0.0-rc4"
+source = "git+https://github.com/paritytech/substrate.git?rev=00768a1f21a579c478fe5d4f51e1fa71f7db9fd4#00768a1f21a579c478fe5d4f51e1fa71f7db9fd4"
+dependencies = [
+ "futures 0.3.4",
+ "hash-db",
+ "parity-scale-codec",
+ "sc-client-api",
+ "sc-client-db",
+ "sc-consensus",
+ "sc-executor",
+ "sc-light",
+ "sc-service",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-keyring",
+ "sp-runtime",
+ "sp-state-machine",
+]
+
+[[package]]
+name = "substrate-test-runtime"
+version = "2.0.0-rc4"
+source = "git+https://github.com/paritytech/substrate.git?rev=00768a1f21a579c478fe5d4f51e1fa71f7db9fd4#00768a1f21a579c478fe5d4f51e1fa71f7db9fd4"
+dependencies = [
+ "cfg-if",
+ "frame-executive",
+ "frame-support",
+ "frame-system",
+ "frame-system-rpc-runtime-api",
+ "log",
+ "memory-db",
+ "pallet-babe",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "sc-service",
+ "serde",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-block-builder",
+ "sp-consensus-aura",
+ "sp-consensus-babe",
+ "sp-core",
+ "sp-finality-grandpa",
+ "sp-inherents",
+ "sp-io",
+ "sp-keyring",
+ "sp-offchain",
+ "sp-runtime",
+ "sp-runtime-interface",
+ "sp-session",
+ "sp-std",
+ "sp-transaction-pool",
+ "sp-trie",
+ "sp-version",
+ "substrate-wasm-builder-runner",
+ "trie-db",
+]
+
+[[package]]
+name = "substrate-test-runtime-client"
+version = "2.0.0-rc4"
+source = "git+https://github.com/paritytech/substrate.git?rev=00768a1f21a579c478fe5d4f51e1fa71f7db9fd4#00768a1f21a579c478fe5d4f51e1fa71f7db9fd4"
+dependencies = [
+ "futures 0.3.4",
+ "parity-scale-codec",
+ "sc-block-builder",
+ "sc-client-api",
+ "sc-consensus",
+ "sc-light",
+ "sc-service",
+ "sp-api",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-runtime",
+ "substrate-test-client",
+ "substrate-test-runtime",
+]
+
 [[package]]
 name = "substrate-wasm-builder-runner"
 version = "1.0.6"

+ 1 - 1
node/Cargo.toml

@@ -79,7 +79,7 @@ tempfile = "3.1.0"
 sp-timestamp = { package = 'sp-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4' }
 sp-keyring = { package = 'sp-keyring', git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4' }
 sc-consensus-babe = { git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4', features = ["test-helpers"]}
-# sc-service-test = { git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4' }
+sc-service-test = { git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4' }
 frame-system = { package = 'frame-system', git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4' }
 pallet-transaction-payment = { package = 'pallet-transaction-payment', git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4' }
 pallet-grandpa = { package = 'pallet-grandpa', git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4' }

+ 79 - 68
node/src/chain_spec/mod.rs

@@ -379,76 +379,87 @@ pub fn testnet_genesis(
     }
 }
 
-// Tests are commented out until we find a solution to why
-// building dependencies for the tests are taking so long on Travis CI
+#[cfg(test)]
+pub(crate) mod tests {
+    use super::*;
+    use crate::service::{new_full, new_light};
+    use sc_service_test;
 
-// #[cfg(test)]
-// pub(crate) mod tests {
-//     use super::*;
-//     use crate::service::{new_full, new_light};
-//     use sc_service_test;
-
-//     fn local_testnet_genesis_instant_single() -> GenesisConfig {
-//         testnet_genesis(
-//             vec![get_authority_keys_from_seed("Alice")],
-//             get_account_id_from_seed::<sr25519::Public>("Alice"),
-//             vec![get_authority_keys_from_seed("Alice").0],
-//             crate::proposals_config::development(),
-//         )
-//     }
+    fn local_testnet_genesis_instant_single() -> GenesisConfig {
+        testnet_genesis(
+            vec![get_authority_keys_from_seed("Alice")],
+            get_account_id_from_seed::<sr25519::Public>("Alice"),
+            vec![get_authority_keys_from_seed("Alice").0],
+            proposals_config::development(),
+            initial_members::none(),
+            forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
+            content_config::empty_versioned_store_config(),
+            content_config::empty_versioned_store_permissions_config(),
+            content_config::empty_data_directory_config(),
+            content_config::empty_content_working_group_config(),
+            vec![],
+        )
+    }
 
-//     /// Local testnet config (single validator - Alice)
-//     pub fn integration_test_config_with_single_authority() -> ChainSpec {
-//         ChainSpec::from_genesis(
-//             "Integration Test",
-//             "test",
-//             ChainType::Development,
-//             local_testnet_genesis_instant_single,
-//             vec![],
-//             None,
-//             None,
-//             None,
-//             Default::default(),
-//         )
-//     }
+    /// Local testnet config (single validator - Alice)
+    pub fn integration_test_config_with_single_authority() -> ChainSpec {
+        ChainSpec::from_genesis(
+            "Integration Test",
+            "test",
+            ChainType::Development,
+            local_testnet_genesis_instant_single,
+            vec![],
+            None,
+            None,
+            None,
+            Default::default(),
+        )
+    }
 
-//     fn local_testnet_genesis() -> GenesisConfig {
-//         testnet_genesis(
-//             vec![
-//                 get_authority_keys_from_seed("Alice"),
-//                 get_authority_keys_from_seed("Bob"),
-//             ],
-//             get_account_id_from_seed::<sr25519::Public>("Alice"),
-//             vec![
-//                 get_authority_keys_from_seed("Alice").0,
-//                 get_authority_keys_from_seed("Bob").0,
-//             ],
-//             crate::proposals_config::development(),
-//         )
-//     }
+    fn local_testnet_genesis() -> GenesisConfig {
+        testnet_genesis(
+            vec![
+                get_authority_keys_from_seed("Alice"),
+                get_authority_keys_from_seed("Bob"),
+            ],
+            get_account_id_from_seed::<sr25519::Public>("Alice"),
+            vec![
+                get_authority_keys_from_seed("Alice").0,
+                get_authority_keys_from_seed("Bob").0,
+            ],
+            proposals_config::development(),
+            initial_members::none(),
+            forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
+            content_config::empty_versioned_store_config(),
+            content_config::empty_versioned_store_permissions_config(),
+            content_config::empty_data_directory_config(),
+            content_config::empty_content_working_group_config(),
+            vec![],
+        )
+    }
 
-//     /// Local testnet config (multivalidator Alice + Bob)
-//     pub fn integration_test_config_with_two_authorities() -> ChainSpec {
-//         ChainSpec::from_genesis(
-//             "Integration Test",
-//             "test",
-//             ChainType::Development,
-//             local_testnet_genesis,
-//             vec![],
-//             None,
-//             None,
-//             None,
-//             Default::default(),
-//         )
-//     }
+    /// Local testnet config (multivalidator Alice + Bob)
+    pub fn integration_test_config_with_two_authorities() -> ChainSpec {
+        ChainSpec::from_genesis(
+            "Integration Test",
+            "test",
+            ChainType::Development,
+            local_testnet_genesis,
+            vec![],
+            None,
+            None,
+            None,
+            Default::default(),
+        )
+    }
 
-//     #[test]
-//     #[ignore]
-//     fn test_connectivity() {
-//         sc_service_test::connectivity(
-//             integration_test_config_with_two_authorities(),
-//             |config| new_full(config),
-//             |config| new_light(config),
-//         );
-//     }
-// }
+    #[test]
+    #[ignore]
+    fn test_connectivity() {
+        sc_service_test::connectivity(
+            integration_test_config_with_two_authorities(),
+            |config| new_full(config),
+            |config| new_light(config),
+        );
+    }
+}

+ 244 - 247
node/src/service.rs

@@ -415,250 +415,247 @@ pub fn new_light(config: Configuration) -> Result<impl AbstractService, ServiceE
     Ok(service)
 }
 
-// Tests are commented out until we find a solution to why
-// building dependencies for the tests are taking so long on Travis CI
-
-// #[cfg(test)]
-// mod tests {
-//     use crate::node_executor;
-//     use crate::node_rpc;
-//     use crate::service::{new_full, new_light};
-//     use codec::{Decode, Encode};
-//     use node_runtime::RuntimeApi;
-//     use node_runtime::{currency::CENTS, SLOT_DURATION};
-//     use node_runtime::{opaque::Block, AccountId, DigestItem, Signature};
-//     use node_runtime::{BalancesCall, Call, UncheckedExtrinsic};
-//     use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY};
-//     use sc_consensus_epochs::descendent_query;
-//     use sc_finality_grandpa::{self as grandpa};
-//     use sc_service::AbstractService;
-//     use sp_consensus::{
-//         BlockImport, BlockImportParams, BlockOrigin, Environment, ForkChoiceStrategy, Proposer,
-//         RecordProof,
-//     };
-//     use sp_core::{crypto::Pair as CryptoPair, H256};
-//     use sp_finality_tracker;
-//     use sp_keyring::AccountKeyring;
-//     use sp_runtime::traits::IdentifyAccount;
-//     use sp_runtime::{
-//         generic::{BlockId, Digest, Era, SignedPayload},
-//         traits::Verify,
-//         traits::{Block as BlockT, Header as HeaderT},
-//         OpaqueExtrinsic,
-//     };
-//     use sp_timestamp;
-//     use sp_transaction_pool::{ChainEvent, MaintainedTransactionPool};
-//     use std::{any::Any, borrow::Cow, sync::Arc};
-
-//     type AccountPublic = <Signature as Verify>::Signer;
-
-//     // Long running test. Run it locally only after the node changes.
-//     #[test]
-//     // It is "ignored", but the node-cli ignored tests are running on the CI.
-//     // This can be run locally with `cargo test --release -p node-cli test_sync -- --ignored`.
-//     #[ignore]
-//     fn test_sync() {
-//         let keystore_path = tempfile::tempdir().expect("Creates keystore path");
-//         let keystore =
-//             sc_keystore::Store::open(keystore_path.path(), None).expect("Creates keystore");
-//         let alice = keystore
-//             .write()
-//             .insert_ephemeral_from_seed::<sc_consensus_babe::AuthorityPair>("//Alice")
-//             .expect("Creates authority pair");
-
-//         let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
-
-//         // For the block factory
-//         let mut slot_num = 1u64;
-
-//         // For the extrinsics factory
-//         let bob = Arc::new(AccountKeyring::Bob.pair());
-//         let charlie = Arc::new(AccountKeyring::Charlie.pair());
-//         let mut index = 0;
-
-//         sc_service_test::sync(
-//             chain_spec,
-//             |config| {
-//                 let mut setup_handles = None;
-//                 new_full!(
-//                     config,
-//                     |block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>,
-//                      babe_link: &sc_consensus_babe::BabeLink<Block>| {
-//                         setup_handles = Some((block_import.clone(), babe_link.clone()));
-//                     }
-//                 )
-//                 .map(move |(node, x)| (node, (x, setup_handles.unwrap())))
-//             },
-//             |config| new_light(config),
-//             |service, &mut (ref inherent_data_providers, (ref mut block_import, ref babe_link))| {
-//                 let mut inherent_data = inherent_data_providers
-//                     .create_inherent_data()
-//                     .expect("Creates inherent data.");
-//                 inherent_data.replace_data(sp_finality_tracker::INHERENT_IDENTIFIER, &1u64);
-
-//                 let parent_id = BlockId::number(service.client().chain_info().best_number);
-//                 let parent_header = service.client().header(&parent_id).unwrap().unwrap();
-//                 let parent_hash = parent_header.hash();
-//                 let parent_number = *parent_header.number();
-
-//                 futures::executor::block_on(service.transaction_pool().maintain(
-//                     ChainEvent::NewBlock {
-//                         is_new_best: true,
-//                         hash: parent_header.hash(),
-//                         tree_route: None,
-//                         header: parent_header.clone(),
-//                     },
-//                 ));
-
-//                 let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
-//                     service.client(),
-//                     service.transaction_pool(),
-//                     None,
-//                 );
-
-//                 let epoch_descriptor = babe_link
-//                     .epoch_changes()
-//                     .lock()
-//                     .epoch_descriptor_for_child_of(
-//                         descendent_query(&*service.client()),
-//                         &parent_hash,
-//                         parent_number,
-//                         slot_num,
-//                     )
-//                     .unwrap()
-//                     .unwrap();
-
-//                 let mut digest = Digest::<H256>::default();
-
-//                 // even though there's only one authority some slots might be empty,
-//                 // so we must keep trying the next slots until we can claim one.
-//                 let babe_pre_digest = loop {
-//                     inherent_data.replace_data(
-//                         sp_timestamp::INHERENT_IDENTIFIER,
-//                         &(slot_num * SLOT_DURATION),
-//                     );
-//                     if let Some(babe_pre_digest) = sc_consensus_babe::test_helpers::claim_slot(
-//                         slot_num,
-//                         &parent_header,
-//                         &*service.client(),
-//                         &keystore,
-//                         &babe_link,
-//                     ) {
-//                         break babe_pre_digest;
-//                     }
-
-//                     slot_num += 1;
-//                 };
-
-//                 digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(
-//                     babe_pre_digest,
-//                 ));
-
-//                 let new_block = futures::executor::block_on(async move {
-//                     let proposer = proposer_factory.init(&parent_header).await;
-//                     proposer
-//                         .unwrap()
-//                         .propose(
-//                             inherent_data,
-//                             digest,
-//                             std::time::Duration::from_secs(1),
-//                             RecordProof::Yes,
-//                         )
-//                         .await
-//                 })
-//                 .expect("Error making test block")
-//                 .block;
-
-//                 let (new_header, new_body) = new_block.deconstruct();
-//                 let pre_hash = new_header.hash();
-//                 // sign the pre-sealed hash of the block and then
-//                 // add it to a digest item.
-//                 let to_sign = pre_hash.encode();
-//                 let signature = alice.sign(&to_sign[..]);
-//                 let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature.into());
-//                 slot_num += 1;
-
-//                 let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
-//                 params.post_digests.push(item);
-//                 params.body = Some(new_body);
-//                 params.intermediates.insert(
-//                     Cow::from(INTERMEDIATE_KEY),
-//                     Box::new(BabeIntermediate::<Block> { epoch_descriptor }) as Box<dyn Any>,
-//                 );
-//                 params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
-
-//                 block_import
-//                     .import_block(params, Default::default())
-//                     .expect("error importing test block");
-//             },
-//             |service, _| {
-//                 let amount = 5 * CENTS;
-//                 let to: AccountId = AccountPublic::from(bob.public()).into_account().into();
-//                 let from: AccountId = AccountPublic::from(charlie.public()).into_account().into();
-//                 let genesis_hash = service.client().block_hash(0).unwrap().unwrap();
-//                 let best_block_id = BlockId::number(service.client().chain_info().best_number);
-//                 let (spec_version, transaction_version) = {
-//                     let version = service.client().runtime_version_at(&best_block_id).unwrap();
-//                     (version.spec_version, version.transaction_version)
-//                 };
-//                 let signer = charlie.clone();
-
-//                 let function = Call::Balances(BalancesCall::transfer(to.into(), amount));
-
-//                 let check_spec_version = frame_system::CheckSpecVersion::new();
-//                 let check_tx_version = frame_system::CheckTxVersion::new();
-//                 let check_genesis = frame_system::CheckGenesis::new();
-//                 let check_era = frame_system::CheckEra::from(Era::Immortal);
-//                 let check_nonce = frame_system::CheckNonce::from(index);
-//                 let check_weight = frame_system::CheckWeight::new();
-//                 let payment = pallet_transaction_payment::ChargeTransactionPayment::from(0);
-//                 let validate_grandpa_equivocation =
-//                     pallet_grandpa::ValidateEquivocationReport::new();
-//                 let extra = (
-//                     check_spec_version,
-//                     check_tx_version,
-//                     check_genesis,
-//                     check_era,
-//                     check_nonce,
-//                     check_weight,
-//                     payment,
-//                     validate_grandpa_equivocation,
-//                 );
-//                 let raw_payload = SignedPayload::from_raw(
-//                     function,
-//                     extra,
-//                     (
-//                         spec_version,
-//                         transaction_version,
-//                         genesis_hash,
-//                         genesis_hash,
-//                         (),
-//                         (),
-//                         (),
-//                         (),
-//                     ),
-//                 );
-//                 let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
-//                 let (function, extra, _) = raw_payload.deconstruct();
-//                 let xt =
-//                     UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra)
-//                         .encode();
-//                 let v: Vec<u8> = Decode::decode(&mut xt.as_slice()).unwrap();
-
-//                 index += 1;
-//                 OpaqueExtrinsic(v)
-//             },
-//         );
-//     }
-
-//     #[test]
-//     #[ignore]
-//     fn test_consensus() {
-//         sc_service_test::consensus(
-//             crate::chain_spec::tests::integration_test_config_with_two_authorities(),
-//             |config| new_full(config),
-//             |config| new_light(config),
-//             vec!["//Alice".into(), "//Bob".into()],
-//         )
-//     }
-// }
+#[cfg(test)]
+mod tests {
+    use crate::node_executor;
+    use crate::node_rpc;
+    use crate::service::{new_full, new_light};
+    use codec::{Decode, Encode};
+    use node_runtime::RuntimeApi;
+    use node_runtime::{currency::CENTS, SLOT_DURATION};
+    use node_runtime::{opaque::Block, AccountId, DigestItem, Signature};
+    use node_runtime::{BalancesCall, Call, UncheckedExtrinsic};
+    use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY};
+    use sc_consensus_epochs::descendent_query;
+    use sc_finality_grandpa::{self as grandpa};
+    use sc_service::AbstractService;
+    use sp_consensus::{
+        BlockImport, BlockImportParams, BlockOrigin, Environment, ForkChoiceStrategy, Proposer,
+        RecordProof,
+    };
+    use sp_core::{crypto::Pair as CryptoPair, H256};
+    use sp_finality_tracker;
+    use sp_keyring::AccountKeyring;
+    use sp_runtime::traits::IdentifyAccount;
+    use sp_runtime::{
+        generic::{BlockId, Digest, Era, SignedPayload},
+        traits::Verify,
+        traits::{Block as BlockT, Header as HeaderT},
+        OpaqueExtrinsic,
+    };
+    use sp_timestamp;
+    use sp_transaction_pool::{ChainEvent, MaintainedTransactionPool};
+    use std::{any::Any, borrow::Cow, sync::Arc};
+
+    type AccountPublic = <Signature as Verify>::Signer;
+
+    // Long running test. Run it locally only after the node changes.
+    #[test]
+    // It is "ignored", but the node-cli ignored tests are running on the CI.
+    // This can be run locally with `cargo test --release -p node-cli test_sync -- --ignored`.
+    #[ignore]
+    fn test_sync() {
+        let keystore_path = tempfile::tempdir().expect("Creates keystore path");
+        let keystore =
+            sc_keystore::Store::open(keystore_path.path(), None).expect("Creates keystore");
+        let alice = keystore
+            .write()
+            .insert_ephemeral_from_seed::<sc_consensus_babe::AuthorityPair>("//Alice")
+            .expect("Creates authority pair");
+
+        let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
+
+        // For the block factory
+        let mut slot_num = 1u64;
+
+        // For the extrinsics factory
+        let bob = Arc::new(AccountKeyring::Bob.pair());
+        let charlie = Arc::new(AccountKeyring::Charlie.pair());
+        let mut index = 0;
+
+        sc_service_test::sync(
+            chain_spec,
+            |config| {
+                let mut setup_handles = None;
+                new_full!(
+                    config,
+                    |block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>,
+                     babe_link: &sc_consensus_babe::BabeLink<Block>| {
+                        setup_handles = Some((block_import.clone(), babe_link.clone()));
+                    }
+                )
+                .map(move |(node, x)| (node, (x, setup_handles.unwrap())))
+            },
+            |config| new_light(config),
+            |service, &mut (ref inherent_data_providers, (ref mut block_import, ref babe_link))| {
+                let mut inherent_data = inherent_data_providers
+                    .create_inherent_data()
+                    .expect("Creates inherent data.");
+                inherent_data.replace_data(sp_finality_tracker::INHERENT_IDENTIFIER, &1u64);
+
+                let parent_id = BlockId::number(service.client().chain_info().best_number);
+                let parent_header = service.client().header(&parent_id).unwrap().unwrap();
+                let parent_hash = parent_header.hash();
+                let parent_number = *parent_header.number();
+
+                futures::executor::block_on(service.transaction_pool().maintain(
+                    ChainEvent::NewBlock {
+                        is_new_best: true,
+                        hash: parent_header.hash(),
+                        tree_route: None,
+                        header: parent_header.clone(),
+                    },
+                ));
+
+                let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
+                    service.client(),
+                    service.transaction_pool(),
+                    None,
+                );
+
+                let epoch_descriptor = babe_link
+                    .epoch_changes()
+                    .lock()
+                    .epoch_descriptor_for_child_of(
+                        descendent_query(&*service.client()),
+                        &parent_hash,
+                        parent_number,
+                        slot_num,
+                    )
+                    .unwrap()
+                    .unwrap();
+
+                let mut digest = Digest::<H256>::default();
+
+                // even though there's only one authority some slots might be empty,
+                // so we must keep trying the next slots until we can claim one.
+                let babe_pre_digest = loop {
+                    inherent_data.replace_data(
+                        sp_timestamp::INHERENT_IDENTIFIER,
+                        &(slot_num * SLOT_DURATION),
+                    );
+                    if let Some(babe_pre_digest) = sc_consensus_babe::test_helpers::claim_slot(
+                        slot_num,
+                        &parent_header,
+                        &*service.client(),
+                        &keystore,
+                        &babe_link,
+                    ) {
+                        break babe_pre_digest;
+                    }
+
+                    slot_num += 1;
+                };
+
+                digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(
+                    babe_pre_digest,
+                ));
+
+                let new_block = futures::executor::block_on(async move {
+                    let proposer = proposer_factory.init(&parent_header).await;
+                    proposer
+                        .unwrap()
+                        .propose(
+                            inherent_data,
+                            digest,
+                            std::time::Duration::from_secs(1),
+                            RecordProof::Yes,
+                        )
+                        .await
+                })
+                .expect("Error making test block")
+                .block;
+
+                let (new_header, new_body) = new_block.deconstruct();
+                let pre_hash = new_header.hash();
+                // sign the pre-sealed hash of the block and then
+                // add it to a digest item.
+                let to_sign = pre_hash.encode();
+                let signature = alice.sign(&to_sign[..]);
+                let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature.into());
+                slot_num += 1;
+
+                let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
+                params.post_digests.push(item);
+                params.body = Some(new_body);
+                params.intermediates.insert(
+                    Cow::from(INTERMEDIATE_KEY),
+                    Box::new(BabeIntermediate::<Block> { epoch_descriptor }) as Box<dyn Any>,
+                );
+                params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
+
+                block_import
+                    .import_block(params, Default::default())
+                    .expect("error importing test block");
+            },
+            |service, _| {
+                let amount = 5 * CENTS;
+                let to: AccountId = AccountPublic::from(bob.public()).into_account().into();
+                let from: AccountId = AccountPublic::from(charlie.public()).into_account().into();
+                let genesis_hash = service.client().block_hash(0).unwrap().unwrap();
+                let best_block_id = BlockId::number(service.client().chain_info().best_number);
+                let (spec_version, transaction_version) = {
+                    let version = service.client().runtime_version_at(&best_block_id).unwrap();
+                    (version.spec_version, version.transaction_version)
+                };
+                let signer = charlie.clone();
+
+                let function = Call::Balances(BalancesCall::transfer(to.into(), amount));
+
+                let check_spec_version = frame_system::CheckSpecVersion::new();
+                let check_tx_version = frame_system::CheckTxVersion::new();
+                let check_genesis = frame_system::CheckGenesis::new();
+                let check_era = frame_system::CheckEra::from(Era::Immortal);
+                let check_nonce = frame_system::CheckNonce::from(index);
+                let check_weight = frame_system::CheckWeight::new();
+                let payment = pallet_transaction_payment::ChargeTransactionPayment::from(0);
+                let validate_grandpa_equivocation =
+                    pallet_grandpa::ValidateEquivocationReport::new();
+                let extra = (
+                    check_spec_version,
+                    check_tx_version,
+                    check_genesis,
+                    check_era,
+                    check_nonce,
+                    check_weight,
+                    payment,
+                    validate_grandpa_equivocation,
+                );
+                let raw_payload = SignedPayload::from_raw(
+                    function,
+                    extra,
+                    (
+                        spec_version,
+                        transaction_version,
+                        genesis_hash,
+                        genesis_hash,
+                        (),
+                        (),
+                        (),
+                        (),
+                    ),
+                );
+                let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
+                let (function, extra, _) = raw_payload.deconstruct();
+                let xt =
+                    UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra)
+                        .encode();
+                let v: Vec<u8> = Decode::decode(&mut xt.as_slice()).unwrap();
+
+                index += 1;
+                OpaqueExtrinsic(v)
+            },
+        );
+    }
+
+    #[test]
+    #[ignore]
+    fn test_consensus() {
+        sc_service_test::consensus(
+            crate::chain_spec::tests::integration_test_config_with_two_authorities(),
+            |config| new_full(config),
+            |config| new_light(config),
+            vec!["//Alice".into(), "//Bob".into()],
+        )
+    }
+}