mirror of https://github.com/hyperledger/besu
Database Migration acceptance testing - using pre-generated database archives (#430)
Signed-off-by: Abdelhamid Bakhta <abdelhamid.bakhta@consensys.net>pull/446/head
parent
6b9a877f1d
commit
f03061d2b4
@ -0,0 +1,57 @@ |
|||||||
|
/* |
||||||
|
* Copyright ConsenSys AG. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.tests.acceptance.dsl.condition.account; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.web3j.utils.Convert.toWei; |
||||||
|
|
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.WaitUtils; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.account.Account; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.node.Node; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions; |
||||||
|
|
||||||
|
import java.math.BigDecimal; |
||||||
|
import java.math.BigInteger; |
||||||
|
|
||||||
|
import org.web3j.utils.Convert.Unit; |
||||||
|
|
||||||
|
public class ExpectAccountBalanceAtBlock implements Condition { |
||||||
|
|
||||||
|
private final EthTransactions eth; |
||||||
|
private final Account account; |
||||||
|
private final BigInteger block; |
||||||
|
private final BigInteger expectedBalance; |
||||||
|
|
||||||
|
public ExpectAccountBalanceAtBlock( |
||||||
|
final EthTransactions eth, |
||||||
|
final Account account, |
||||||
|
final BigInteger block, |
||||||
|
final BigDecimal expectedBalance, |
||||||
|
final Unit balanceUnit) { |
||||||
|
this.account = account; |
||||||
|
this.eth = eth; |
||||||
|
this.block = block; |
||||||
|
this.expectedBalance = toWei(expectedBalance, balanceUnit).toBigIntegerExact(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void verify(final Node node) { |
||||||
|
WaitUtils.waitFor( |
||||||
|
() -> |
||||||
|
assertThat(node.execute(eth.getBalanceAtBlock(account, block))) |
||||||
|
.isEqualTo(expectedBalance)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
/* |
||||||
|
* Copyright ConsenSys AG. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.tests.acceptance.dsl.condition.blockchain; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.node.Node; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
|
||||||
|
public class ExpectBlockNumber implements Condition { |
||||||
|
|
||||||
|
private final EthTransactions eth; |
||||||
|
private final BigInteger blockNumber; |
||||||
|
|
||||||
|
public ExpectBlockNumber(final EthTransactions eth, final BigInteger blockNumber) { |
||||||
|
this.blockNumber = blockNumber; |
||||||
|
this.eth = eth; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void verify(final Node node) { |
||||||
|
assertThat(node.execute(eth.blockNumber())).isEqualTo(blockNumber); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
/* |
||||||
|
* Copyright ConsenSys AG. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.tests.acceptance.dsl.transaction.eth; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.account.Account; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.math.BigInteger; |
||||||
|
|
||||||
|
import org.web3j.protocol.core.DefaultBlockParameter; |
||||||
|
import org.web3j.protocol.core.methods.response.EthGetBalance; |
||||||
|
|
||||||
|
public class EthGetBalanceAtBlockTransaction implements Transaction<BigInteger> { |
||||||
|
|
||||||
|
private final Account account; |
||||||
|
private final BigInteger block; |
||||||
|
|
||||||
|
EthGetBalanceAtBlockTransaction(final Account account, final BigInteger block) { |
||||||
|
this.account = account; |
||||||
|
this.block = block; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public BigInteger execute(final NodeRequests node) { |
||||||
|
try { |
||||||
|
final EthGetBalance result = |
||||||
|
node.eth() |
||||||
|
.ethGetBalance(account.getAddress(), DefaultBlockParameter.valueOf(block)) |
||||||
|
.send(); |
||||||
|
assertThat(result).isNotNull(); |
||||||
|
assertThat(result.hasError()).isFalse(); |
||||||
|
|
||||||
|
return result.getBalance(); |
||||||
|
|
||||||
|
} catch (final IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,206 @@ |
|||||||
|
/* |
||||||
|
* Copyright ConsenSys AG. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.hyperledger.besu.tests.acceptance.database; |
||||||
|
|
||||||
|
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.core.Address; |
||||||
|
import org.hyperledger.besu.ethereum.core.Wei; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; |
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeConfigurationBuilder; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.FileInputStream; |
||||||
|
import java.io.FileOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.math.BigInteger; |
||||||
|
import java.net.URISyntaxException; |
||||||
|
import java.net.URL; |
||||||
|
import java.nio.file.Files; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.nio.file.Paths; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Optional; |
||||||
|
import java.util.stream.Stream; |
||||||
|
|
||||||
|
import com.google.common.base.Charsets; |
||||||
|
import com.google.common.io.Resources; |
||||||
|
import org.apache.commons.compress.archivers.tar.TarArchiveEntry; |
||||||
|
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; |
||||||
|
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; |
||||||
|
import org.apache.commons.compress.utils.IOUtils; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.junit.runners.Parameterized; |
||||||
|
import org.junit.runners.Parameterized.Parameters; |
||||||
|
|
||||||
|
@RunWith(Parameterized.class) |
||||||
|
public class DatabaseMigrationAcceptanceTest extends AcceptanceTestBase { |
||||||
|
private final String testName; |
||||||
|
private final String dataPath; |
||||||
|
private final long expectedChainHeight; |
||||||
|
private Path hostDataPath; |
||||||
|
private BesuNode node; |
||||||
|
private final List<AccountData> testAccounts; |
||||||
|
|
||||||
|
public DatabaseMigrationAcceptanceTest( |
||||||
|
final String testName, |
||||||
|
final String dataPath, |
||||||
|
final long expectedChainHeight, |
||||||
|
final List<AccountData> testAccounts) { |
||||||
|
this.testName = testName; |
||||||
|
this.dataPath = dataPath; |
||||||
|
this.expectedChainHeight = expectedChainHeight; |
||||||
|
this.testAccounts = testAccounts; |
||||||
|
} |
||||||
|
|
||||||
|
@Parameters(name = "{0}") |
||||||
|
public static Object[][] getParameters() { |
||||||
|
return new Object[][] { |
||||||
|
// First 10 blocks of ropsten
|
||||||
|
new Object[] { |
||||||
|
"Before versioning was enabled", |
||||||
|
"version0", |
||||||
|
0xA, |
||||||
|
Arrays.asList( |
||||||
|
new AccountData( |
||||||
|
"0xd1aeb42885a43b72b518182ef893125814811048", |
||||||
|
BigInteger.valueOf(0xA), |
||||||
|
Wei.fromHexString("0x2B5E3AF16B1880000"))), |
||||||
|
}, |
||||||
|
new Object[] { |
||||||
|
"After versioning was enabled and using multiple RocksDB columns", |
||||||
|
"version1", |
||||||
|
0xA, |
||||||
|
Arrays.asList( |
||||||
|
new AccountData( |
||||||
|
"0xd1aeb42885a43b72b518182ef893125814811048", |
||||||
|
BigInteger.valueOf(0xA), |
||||||
|
Wei.fromHexString("0x2B5E3AF16B1880000"))) |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() throws Exception { |
||||||
|
final URL rootURL = DatabaseMigrationAcceptanceTest.class.getResource(dataPath); |
||||||
|
hostDataPath = copyDataDir(rootURL); |
||||||
|
final Path databaseArchive = |
||||||
|
Paths.get( |
||||||
|
DatabaseMigrationAcceptanceTest.class |
||||||
|
.getResource(String.format("%s/besu-db-archive.tar.gz", dataPath)) |
||||||
|
.toURI()); |
||||||
|
extract(databaseArchive, hostDataPath.toAbsolutePath().toString()); |
||||||
|
node = besu.createNode(testName, this::configureNode); |
||||||
|
cluster.start(node); |
||||||
|
} |
||||||
|
|
||||||
|
private BesuNodeConfigurationBuilder configureNode( |
||||||
|
final BesuNodeConfigurationBuilder nodeBuilder) { |
||||||
|
final String genesisData = getGenesisConfiguration(); |
||||||
|
return nodeBuilder |
||||||
|
.devMode(false) |
||||||
|
.dataPath(hostDataPath) |
||||||
|
.genesisConfigProvider((nodes) -> Optional.of(genesisData)) |
||||||
|
.jsonRpcEnabled(); |
||||||
|
} |
||||||
|
|
||||||
|
private String getGenesisConfiguration() { |
||||||
|
try { |
||||||
|
return Resources.toString( |
||||||
|
hostDataPath.resolve("genesis.json").toUri().toURL(), Charsets.UTF_8); |
||||||
|
} catch (IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void shouldReturnCorrectBlockHeight() { |
||||||
|
blockchain.currentHeight(expectedChainHeight).verify(node); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void shouldReturnCorrectAccountBalance() { |
||||||
|
testAccounts.forEach( |
||||||
|
accountData -> |
||||||
|
accounts |
||||||
|
.createAccount(Address.fromHexString(accountData.accountAddress)) |
||||||
|
.balanceAtBlockEquals( |
||||||
|
Amount.wei(accountData.expectedBalance.toBigInteger()), accountData.block) |
||||||
|
.verify(node)); |
||||||
|
} |
||||||
|
|
||||||
|
private static void extract(final Path path, final String destDirectory) throws IOException { |
||||||
|
try (TarArchiveInputStream fin = |
||||||
|
new TarArchiveInputStream( |
||||||
|
new GzipCompressorInputStream(new FileInputStream(path.toAbsolutePath().toString())))) { |
||||||
|
TarArchiveEntry entry; |
||||||
|
while ((entry = fin.getNextTarEntry()) != null) { |
||||||
|
if (entry.isDirectory()) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
final File curfile = new File(destDirectory, entry.getName()); |
||||||
|
final File parent = curfile.getParentFile(); |
||||||
|
if (!parent.exists()) { |
||||||
|
parent.mkdirs(); |
||||||
|
} |
||||||
|
IOUtils.copy(fin, new FileOutputStream(curfile)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Path copyDataDir(final URL url) { |
||||||
|
if (url == null) { |
||||||
|
throw new RuntimeException("Unable to locate resource."); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
final Path tmpDir = Files.createTempDirectory("data"); |
||||||
|
Files.delete(tmpDir); |
||||||
|
final Path toCopy = Paths.get(url.toURI()); |
||||||
|
try (final Stream<Path> pathStream = Files.walk(toCopy)) { |
||||||
|
pathStream.forEach(source -> copy(source, tmpDir.resolve(toCopy.relativize(source)))); |
||||||
|
return tmpDir.toAbsolutePath(); |
||||||
|
} |
||||||
|
} catch (URISyntaxException | IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void copy(final Path source, final Path dest) { |
||||||
|
try { |
||||||
|
Files.copy(source, dest, REPLACE_EXISTING); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException(e.getMessage(), e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class AccountData { |
||||||
|
private final String accountAddress; |
||||||
|
private final BigInteger block; |
||||||
|
private final Wei expectedBalance; |
||||||
|
|
||||||
|
private AccountData(final String account, final BigInteger block, final Wei expectedBalance) { |
||||||
|
this.accountAddress = account; |
||||||
|
this.block = block; |
||||||
|
this.expectedBalance = expectedBalance; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue