Skip to content

Commit

Permalink
Merge pull request #1949 from aeternity/feature/test-on-testnet-2
Browse files Browse the repository at this point in the history
test: add ability to run on testnet, mainnet
  • Loading branch information
davidyuk authored Feb 27, 2024
2 parents 236d7a2 + b3ba3ff commit f348a22
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .mocharc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module.exports = {
require: 'tooling/babel-register.js',
recursive: true,
extension: '.js,.ts',
timeout: '40s',
timeout: process.env.NETWORK ? '400s' : '40s',
ignore: 'test/environment/**',
exit: true // TODO: fix in state channel tests
}
2 changes: 1 addition & 1 deletion src/utils/autorest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export const genRetryOnFailurePolicy = (
const intervals = new Array(retryCount).fill(0)
.map((_, idx) => ((idx + 1) / retryCount) ** 2);
const intervalSum = intervals.reduce((a, b) => a + b, 0);
const intervalsInMs = intervals.map((el) => (el / intervalSum) * retryOverallDelay);
const intervalsInMs = intervals.map((e) => Math.floor((e / intervalSum) * retryOverallDelay));

let error = new RestError('Not expected to be thrown');
for (let attempt = 0; attempt <= retryCount; attempt += 1) {
Expand Down
17 changes: 8 additions & 9 deletions test/integration/AeSdkMethods.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { describe, it, before } from 'mocha';
import { expect } from 'chai';
import { getSdk, url, compilerUrl } from '.';
import { getSdk } from '.';
import { assertNotNull } from '../utils';
import {
AeSdkMethods, Node, CompilerHttp, AccountBase,
} from '../../src';
import { AeSdkMethods, AccountBase } from '../../src';

describe('AeSdkMethods', () => {
let accounts: AccountBase[];
let aeSdkMethods: AeSdkMethods;

before(async () => {
accounts = Object.values((await getSdk(2)).accounts);
const sdk = await getSdk(2);
accounts = Object.values(sdk.accounts);
aeSdkMethods = new AeSdkMethods({
onAccount: accounts[0],
onNode: new Node(url),
onCompiler: new CompilerHttp(compilerUrl),
onNode: sdk.api,
onCompiler: sdk.compilerApi,
});
});

Expand Down Expand Up @@ -91,7 +90,7 @@ describe('AeSdkMethods', () => {
{ name: 'logPolicy' },
],
},
$host: 'http://localhost:3013',
$host: data.onNode.$host,
intAsString: true,
},
onCompiler: {
Expand Down Expand Up @@ -134,7 +133,7 @@ describe('AeSdkMethods', () => {
{ name: 'logPolicy' },
],
},
$host: 'http://localhost:3080',
$host: data.onCompiler.api.$host,
},
},
});
Expand Down
3 changes: 2 additions & 1 deletion test/integration/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ describe('Accounts', () => {
expect(await aeSdk.getBalance(genesis, { height: 0 })).to.be.equal('10000000000000000000000');
});

it('validate account balance by height before and after spend tx', async () => {
(networkId === 'ae_devnet' ? it : it.skip)('validate account balance by height before and after spend tx', async () => {
async function getBalance(height?: number): Promise<bigint> {
return (await aeSdk.getAccount(aeSdk.address, { height })).balance;
}
Expand Down Expand Up @@ -206,5 +206,6 @@ describe('Accounts', () => {
const th = await aeSdk.spend(1, receiver.address, { waitMined: false });
th.should.be.a('object');
th.hash.slice(0, 3).should.equal('th_');
await aeSdk.poll(th.hash);
});
});
30 changes: 19 additions & 11 deletions test/integration/aens.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { describe, it, before } from 'mocha';
import { expect } from 'chai';
import { getSdk } from '.';
import { assertNotNull, randomName, randomString } from '../utils';
import { getSdk, isLimitedCoins } from '.';
import {
assertNotNull, ensureEqual, randomName, randomString,
} from '../utils';
import {
AeSdk, generateKeyPair, buildContractId, computeBidFee, ensureName, produceNameId,
AensPointerContextError, encode, decode, Encoding, ContractMethodsBase, ConsensusProtocolVersion,
unpackTx, Tag, buildTxHash,
} from '../../src';
import { pause } from '../../src/utils/other';

describe('Aens', () => {
let aeSdk: AeSdk;
Expand Down Expand Up @@ -74,9 +76,10 @@ describe('Aens', () => {
expect(claimed.extendTtl).to.be.a('function');
assertNotNull(claimed.tx);
assertNotNull(claimed.signatures);
expect(claimed.tx.fee).to.be.oneOf([16940000000000n, 16960000000000n]);
expect(claimed).to.be.eql({
tx: {
fee: 16960000000000n,
fee: claimed.tx.fee,
nonce: claimed.tx.nonce,
accountId: aeSdk.address,
name: n,
Expand Down Expand Up @@ -110,9 +113,6 @@ describe('Aens', () => {
});

it('queries names', async () => {
// For some reason the node will return 404 when name is queried
// just right after claim tx has been mined so we wait 0.5s
await pause(500);
await aeSdk.aensQuery(name).should.eventually.be.an('object');
});

Expand Down Expand Up @@ -169,11 +169,19 @@ describe('Aens', () => {
});

it('throws error on updating names not owned by the account', async () => {
const preclaim = await aeSdk.aensPreclaim(randomName(30));
await preclaim.claim();
const onAccount = aeSdk.addresses().find((acc) => acc !== aeSdk.address);
assertNotNull(onAccount);
await aeSdk.aensUpdate(name, {}, { onAccount, blocks: 1 }).should.eventually.be.rejected;
const promise = aeSdk.aensUpdate(name, {}, { onAccount, blocks: 1 });
await expect(promise)
.to.be.rejectedWith(/Giving up after 1 blocks mined, transaction hash:|error: Transaction not found/);

const { rawTx } = await promise.catch((e) => e);
const { encodedTx } = unpackTx(rawTx, Tag.SignedTx);
ensureEqual(encodedTx.tag, Tag.NameUpdateTx);
await aeSdk.spend(0, aeSdk.address, { nonce: encodedTx.nonce, onAccount });
const txHash = buildTxHash(rawTx);
await expect(aeSdk.poll(txHash))
.to.be.rejectedWith(new RegExp(`v3/transactions/${txHash} error: (Transaction not found|412 status code)`));
});

it('updates extending pointers', async () => {
Expand Down Expand Up @@ -253,7 +261,7 @@ describe('Aens', () => {
preclaim.tx.accountId.should.be.equal(onAccount);
});

describe('name auctions', () => {
(isLimitedCoins ? describe.skip : describe)('name auctions', () => {
it('claims a name', async () => {
const onAccount = aeSdk.addresses().find((acc) => acc !== aeSdk.address);
const nameShort = randomName(12);
Expand Down
15 changes: 4 additions & 11 deletions test/integration/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, before } from 'mocha';
import { expect } from 'chai';
import { getSdk } from '.';
import {
generateKeyPair, AeSdk, Tag, UnexpectedTsError, MemoryAccount, Encoded,
generateKeyPair, AeSdk, Tag, MemoryAccount, Encoded,
} from '../../src';
import { assertNotNull, bindRequestCounter } from '../utils';

Expand Down Expand Up @@ -82,16 +82,9 @@ describe('Node Chain', () => {
});

it('Wait for transaction confirmation', async () => {
const txData = await aeSdk.spend(1000, aeSdk.address, { confirm: true });
if (txData.blockHeight == null) throw new UnexpectedTsError();
const isConfirmed = (await aeSdk.getHeight()) >= txData.blockHeight + 3;

isConfirmed.should.be.equal(true);

const txData2 = await aeSdk.spend(1000, aeSdk.address, { confirm: 4 });
if (txData2.blockHeight == null) throw new UnexpectedTsError();
const isConfirmed2 = (await aeSdk.getHeight()) >= txData2.blockHeight + 4;
isConfirmed2.should.be.equal(true);
const res = await aeSdk.spend(1000, aeSdk.address, { confirm: 1 });
assertNotNull(res.blockHeight);
expect(await aeSdk.getHeight() >= res.blockHeight + 1).to.be.equal(true);
});

it('doesn\'t make extra requests', async () => {
Expand Down
4 changes: 2 additions & 2 deletions test/integration/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
import { expect } from 'chai';
import * as sinon from 'sinon';
import BigNumber from 'bignumber.js';
import { getSdk, channelUrl } from '.';
import { getSdk, networkId, channelUrl } from '.';
import {
unpackTx,
buildTxHash,
Expand Down Expand Up @@ -50,7 +50,7 @@ async function waitForChannel(channel: Channel): Promise<void> {
});
}

describe('Channel', () => {
(networkId === 'ae_devnet' ? describe : describe.skip)('Channel', () => {
let aeSdkInitiatior: AeSdk;
let aeSdkResponder: AeSdk;
let initiatorCh: Channel;
Expand Down
2 changes: 1 addition & 1 deletion test/integration/contract-aci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ contract StateContract =
const fileSystem = {
testLib: libContractSource,
};
const notExistingContractAddress = 'ct_ptREMvyDbSh1d38t4WgYgac5oLsa2v9xwYFnG7eUWR8Er5cmT';
const notExistingContractAddress = 'ct_ptREMvyDbSh1d38t4WgYgac5oLsa2v9xwYFnG7eUWR88Regxm';

type DateUnit = { Year: [] } | { Month: [] } | { Day: [] };
type OneOrBoth<First, Second> = { Left: [First] } | { Both: [First, Second] } | { Right: [Second] };
Expand Down
2 changes: 1 addition & 1 deletion test/integration/delegation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ contract DelegateTest =
const { result } = await contract.signedPreclaim(owner, commitmentIdDecoded, preclaimSig);
assertNotNull(result);
result.returnType.should.be.equal('ok');
await aeSdk.awaitHeight(2 + await aeSdk.getHeight());
// signature for any other name related operations
delegationSignature = await aeSdk.createDelegationSignature(contractAddress, [name]);
});

it('claims', async () => {
await aeSdk.awaitHeight(1 + await aeSdk.getHeight());
const { result } = await contract
.signedClaim(owner, name, salt, nameFee, delegationSignature);
assertNotNull(result);
Expand Down
90 changes: 80 additions & 10 deletions test/integration/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,67 @@
import { after } from 'mocha';
import {
AeSdk, CompilerHttpNode, MemoryAccount, Node, Encoded, ConsensusProtocolVersion,
} from '../../src';
import '..';

export const url = process.env.TEST_URL ?? 'http://localhost:3013';
export const compilerUrl = process.env.COMPILER_URL ?? 'http://localhost:3080';
export const compilerUrl7 = process.env.COMPILER_7_URL ?? 'http://localhost:3081';
export const channelUrl = process.env.CHANNEL_URL ?? 'ws://localhost:3014/channel';
const secretKey = process.env.SECRET_KEY ?? '9ebd7beda0c79af72a42ece3821a56eff16359b6df376cf049aee995565f022f840c974b97164776454ba119d84edc4d6058a8dec92b6edc578ab2d30b4c4200';
export const networkId = process.env.TEST_NETWORK_ID ?? 'ae_devnet';
const genesisAccount = new MemoryAccount(secretKey);
const network = process.env.NETWORK;

const configuration = {
mainnet: {
networkId: 'ae_mainnet',
url: 'https://mainnet.aeternity.io',
channelUrl: 'wss://mainnet.aeternity.io/channel',
// TODO: deploy v8 compiler and v7.4.1
compilerUrl: 'http://localhost:3080',
compilerUrl7: 'http://localhost:3081',
getGenesisAccount: () => {
if (process.env.MAINNET_SECRET_KEY == null) throw new Error('MAINNET_SECRET_KEY is not set');
return new MemoryAccount(process.env.MAINNET_SECRET_KEY);
},
sdkOptions: {
blocks: 2,
},
},
testnet: {
networkId: 'ae_uat',
url: 'https://testnet.aeternity.io',
channelUrl: 'wss://testnet.aeternity.io/channel',
// TODO: deploy v8 compiler and v7.4.1
compilerUrl: 'http://localhost:3080',
compilerUrl7: 'http://localhost:3081',
getGenesisAccount: async () => {
const account = MemoryAccount.generate();
const { status } = await fetch(
`https://faucet.aepps.com/account/${account.address}`,
{ method: 'POST' },
);
console.assert([200, 425].includes(status), 'Invalid faucet response code', status);
return account;
},
sdkOptions: {
blocks: 2,
},
},
'': {
networkId: 'ae_devnet',
url: 'http://localhost:3013',
channelUrl: 'ws://localhost:3014/channel',
compilerUrl: 'http://localhost:3080',
compilerUrl7: 'http://localhost:3081',
getGenesisAccount: () => new MemoryAccount(
'9ebd7beda0c79af72a42ece3821a56eff16359b6df376cf049aee995565f022f840c974b97164776454ba119d84edc4d6058a8dec92b6edc578ab2d30b4c4200',
),
sdkOptions: {
_expectedMineRate: 1000,
_microBlockCycle: 300,
},
},
}[network ?? ''];
if (configuration == null) throw new Error(`Unknown network: ${network}`);
export const {
networkId, url, channelUrl, compilerUrl, compilerUrl7,
} = configuration;
const { sdkOptions } = configuration;

type TransactionHandler = (tx: Encoded.Transaction) => unknown;
const transactionHandlers: TransactionHandler[] = [];
Expand All @@ -28,21 +80,39 @@ class NodeHandleTx extends Node {
}
}

const genesisAccountPromise = configuration.getGenesisAccount();
export const isLimitedCoins = network != null;

export async function getSdk(accountCount = 1): Promise<AeSdk> {
const accounts = new Array(accountCount).fill(null).map(() => MemoryAccount.generate());
const sdk = new AeSdk({
onCompiler: new CompilerHttpNode(compilerUrl),
nodes: [{ name: 'test', instance: new NodeHandleTx(url) }],
accounts,
_expectedMineRate: 1000,
_microBlockCycle: 300,
...sdkOptions,
});

// TODO: remove after dropping aesophia@7
if ((await sdk.api.getNodeInfo()).consensusProtocolVersion === ConsensusProtocolVersion.Iris) {
sdk._options.onCompiler = new CompilerHttpNode(compilerUrl7);
}

const genesisAccount = await genesisAccountPromise;
for (let i = 0; i < accounts.length; i += 1) {
await sdk.spend(5e18, accounts[i].address, { onAccount: genesisAccount });
await sdk.spend(
isLimitedCoins ? 1e16 : 5e18,
accounts[i].address,
{ onAccount: genesisAccount },
);
}

if (networkId === 'ae_mainnet') {
after(async () => {
const promises = accounts
.map(async (onAccount) => sdk.transferFunds(1, genesisAccount.address, { onAccount }));
await Promise.allSettled(promises);
});
}

return sdk;
}
21 changes: 10 additions & 11 deletions test/integration/oracle.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { describe, it, before } from 'mocha';
import { expect } from 'chai';
import { RestError } from '@azure/core-rest-pipeline';
import { getSdk } from '.';
import { getSdk, networkId } from '.';
import {
AeSdk, UnexpectedTsError,
decode, encode, Encoding, Encoded,
registerOracle,
ORACLE_TTL_TYPES, RequestTimedOutError,
AeSdk, UnexpectedTsError, decode, encode, Encoding, Encoded, registerOracle, ORACLE_TTL_TYPES,
} from '../../src';

describe('Oracle', () => {
Expand Down Expand Up @@ -57,16 +54,18 @@ describe('Oracle', () => {
.then(() => oracle.postQuery('{"city": "Berlin4"}'));
});

const timeout = networkId === 'ae_devnet' ? 8000 : 600000;
it('Poll for response for query without response', async () => {
const query = await oracle.postQuery('{"city": "Berlin"}', { queryTtlValue: 2 });
await query.pollForResponse().should.be.rejectedWith(RequestTimedOutError);
});
const query = await oracle.postQuery('{"city": "Berlin"}', { queryTtlValue: 1 });
await query.pollForResponse()
.should.be.rejectedWith(/Giving up at height|error: Query not found/);
}).timeout(timeout);

it('Poll for response for query that is already expired without response', async () => {
const query = await oracle.postQuery('{"city": "Berlin"}', { queryTtlValue: 2 });
await aeSdk.awaitHeight(await aeSdk.getHeight() + 3);
const query = await oracle.postQuery('{"city": "Berlin"}', { queryTtlValue: 1 });
await aeSdk.awaitHeight(await aeSdk.getHeight() + 2);
await query.pollForResponse().should.be.rejectedWith(RestError, 'Query not found');
});
}).timeout(timeout);

it('Respond to query', async () => {
let query = await oracle.postQuery('{"city": "Berlin"}');
Expand Down
Loading

0 comments on commit f348a22

Please sign in to comment.