Skip to content

Commit

Permalink
Split up DockerTestFramework into several files
Browse files Browse the repository at this point in the history
  • Loading branch information
muXxer committed May 6, 2024
1 parent 66f8fcd commit f91386d
Show file tree
Hide file tree
Showing 18 changed files with 1,130 additions and 1,000 deletions.
6 changes: 3 additions & 3 deletions tools/docker-network/tests/accounttransition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ func Test_AccountTransitions(t *testing.T) {

// create account1
fmt.Println("Creating account1")
wallet1, _ := d.CreateAccount()
wallet1, _ := d.CreateAccountFromFaucet()

// create account2
fmt.Println("Creating account2")
wallet2, _ := d.CreateAccount()
wallet2, _ := d.CreateAccountFromFaucet()

// allot 1000 mana from account1 to account2
fmt.Println("Allotting mana from account1 to account2")
d.AllotManaTo(wallet1, wallet2.BlockIssuer.AccountData, 1000)
d.RequestFaucetFundsAndAllotManaTo(wallet1, wallet2.BlockIssuer.AccountData, 1000)

// create native token
fmt.Println("Creating native token")
Expand Down
13 changes: 9 additions & 4 deletions tools/docker-network/tests/api_core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func prepareAssets(d *dockertestframework.DockerTestFramework, totalAssetsNum in

for i := 0; i < totalAssetsNum; i++ {
// account
wallet, account := d.CreateAccount()
wallet, account := d.CreateAccountFromFaucet()
assets.setupAssetsForSlot(account.OutputID.Slot())
assets[account.OutputID.Slot()].accountAddress = account.Address

Expand Down Expand Up @@ -301,7 +301,12 @@ func Test_ValidatorsAPI(t *testing.T) {
wallet, implicitAccountOutputData := d.CreateImplicitAccount(ctx)

// create account with staking feature for every validator
accountData := d.CreateAccountFromImplicitAccount(wallet, implicitAccountOutputData, wallet.GetNewBlockIssuanceResponse(), dockertestframework.WithStakingFeature(100, 1, currentEpoch))
accountData := d.CreateAccountFromImplicitAccount(wallet,
implicitAccountOutputData,
wallet.GetNewBlockIssuanceResponse(),
dockertestframework.WithStakingFeature(100, 1, currentEpoch),
)

expectedValidators = append(expectedValidators, accountData.Address.Bech32(hrp))

// issue candidacy payload in the next epoch (currentEpoch + 1), in order to issue it before epochNearingThreshold
Expand Down Expand Up @@ -660,7 +665,7 @@ func Test_CoreAPI(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
d.RequestFromClients(test.testFunc)
d.RequestFromNodes(test.testFunc)
})
}

Expand Down Expand Up @@ -887,7 +892,7 @@ func Test_CoreAPI_BadRequests(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
d.RequestFromClients(test.testFunc)
d.RequestFromNodes(test.testFunc)
})
}
}
Expand Down
8 changes: 6 additions & 2 deletions tools/docker-network/tests/committeerotation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,11 @@ func Test_Staking(t *testing.T) {
wallet, implicitAccountOutputData := d.CreateImplicitAccount(ctx)

// create account with staking feature for the validator
accountData := d.CreateAccountFromImplicitAccount(wallet, implicitAccountOutputData, wallet.GetNewBlockIssuanceResponse(), dockertestframework.WithStakingFeature(100, 1, 0))
accountData := d.CreateAccountFromImplicitAccount(wallet,
implicitAccountOutputData,
wallet.GetNewBlockIssuanceResponse(),
dockertestframework.WithStakingFeature(100, 1, 0),
)

d.AssertValidatorExists(accountData.Address)
}
Expand Down Expand Up @@ -251,7 +255,7 @@ func Test_Delegation(t *testing.T) {
d.WaitUntilNetworkReady()

// create an account to perform delegation
wallet, _ := d.CreateAccount()
wallet, _ := d.CreateAccountFromFaucet()

// delegate all faucet funds to V2, V2 should replace V3
//nolint:forcetypeassert
Expand Down
177 changes: 177 additions & 0 deletions tools/docker-network/tests/dockertestframework/accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
//go:build dockertests

package dockertestframework

import (
"context"
"fmt"

"github.com/stretchr/testify/require"

"github.com/iotaledger/hive.go/runtime/options"
"github.com/iotaledger/iota-core/pkg/testsuite/mock"
iotago "github.com/iotaledger/iota.go/v4"
"github.com/iotaledger/iota.go/v4/api"
"github.com/iotaledger/iota.go/v4/builder"
)

func (d *DockerTestFramework) AccountsFromNodes(nodes ...*Node) []string {
var accounts []string
for _, node := range nodes {
if node.AccountAddressBech32 != "" {
accounts = append(accounts, node.AccountAddressBech32)
}
}

return accounts
}

func (d *DockerTestFramework) CheckAccountStatus(ctx context.Context, blkID iotago.BlockID, txID iotago.TransactionID, creationOutputID iotago.OutputID, accountAddress *iotago.AccountAddress, checkIndexer ...bool) {
// request by blockID if provided, otherwise use txID
// we take the slot from the blockID in case the tx is created earlier than the block.
clt := d.defaultWallet.Client
slot := blkID.Slot()

if blkID == iotago.EmptyBlockID {
blkMetadata, err := clt.TransactionIncludedBlockMetadata(ctx, txID)
require.NoError(d.Testing, err)

blkID = blkMetadata.BlockID
slot = blkMetadata.BlockID.Slot()
}

d.AwaitTransactionPayloadAccepted(ctx, txID)

// wait for the account to be committed
d.AwaitCommitment(slot)

// Check the indexer
if len(checkIndexer) > 0 && checkIndexer[0] {
indexerClt, err := d.defaultWallet.Client.Indexer(ctx)
require.NoError(d.Testing, err)

_, _, _, err = indexerClt.Account(ctx, accountAddress)
require.NoError(d.Testing, err)
}

// check if the creation output exists
_, err := clt.OutputByID(ctx, creationOutputID)
require.NoError(d.Testing, err)
}

// CreateImplicitAccount requests faucet funds and creates an implicit account. It already wait until the transaction is committed and the created account is useable.
func (d *DockerTestFramework) CreateImplicitAccount(ctx context.Context) (*mock.Wallet, *mock.OutputData) {
newWallet := mock.NewWallet(d.Testing, "", d.defaultWallet.Client, &DockerWalletClock{client: d.defaultWallet.Client})
implicitAccountOutputData := d.RequestFaucetFunds(ctx, newWallet, iotago.AddressImplicitAccountCreation)

accountID := iotago.AccountIDFromOutputID(implicitAccountOutputData.ID)
accountAddress, ok := accountID.ToAddress().(*iotago.AccountAddress)
require.True(d.Testing, ok)

// make sure an implicit account is committed
d.CheckAccountStatus(ctx, iotago.EmptyBlockID, implicitAccountOutputData.ID.TransactionID(), implicitAccountOutputData.ID, accountAddress)

// update the wallet with the new account data
newWallet.SetBlockIssuer(&mock.AccountData{
ID: accountID,
Address: accountAddress,
OutputID: implicitAccountOutputData.ID,
AddressIndex: implicitAccountOutputData.AddressIndex,
})

return newWallet, implicitAccountOutputData
}

// TransitionImplicitAccountToAccountOutputBlock consumes the given implicit account, then build the account transition block with the given account output options.
func (d *DockerTestFramework) TransitionImplicitAccountToAccountOutputBlock(accountWallet *mock.Wallet, implicitAccountOutputData *mock.OutputData, blockIssuance *api.IssuanceBlockHeaderResponse, opts ...options.Option[builder.AccountOutputBuilder]) (*mock.AccountData, *iotago.SignedTransaction, *iotago.Block) {
ctx := context.TODO()

var implicitBlockIssuerKey iotago.BlockIssuerKey = iotago.Ed25519PublicKeyHashBlockIssuerKeyFromImplicitAccountCreationAddress(accountWallet.ImplicitAccountCreationAddress())
opts = append(opts, mock.WithBlockIssuerFeature(
iotago.NewBlockIssuerKeys(implicitBlockIssuerKey),
iotago.MaxSlotIndex,
))

signedTx := accountWallet.TransitionImplicitAccountToAccountOutputWithBlockIssuance("", []*mock.OutputData{implicitAccountOutputData}, blockIssuance, opts...)

// The account transition block should be issued by the implicit account block issuer key.
block, err := accountWallet.CreateBasicBlock(ctx, "", mock.WithPayload(signedTx))
require.NoError(d.Testing, err)
accOutputID := iotago.OutputIDFromTransactionIDAndIndex(signedTx.Transaction.MustID(), 0)
accOutput := signedTx.Transaction.Outputs[0].(*iotago.AccountOutput)
accAddress := (accOutput.AccountID).ToAddress().(*iotago.AccountAddress)

accountOutputData := &mock.AccountData{
ID: accOutput.AccountID,
Address: accAddress,
Output: accOutput,
OutputID: accOutputID,
AddressIndex: implicitAccountOutputData.AddressIndex,
}

return accountOutputData, signedTx, block.ProtocolBlock()
}

// CreateAccountFromImplicitAccount transitions an account from the given implicit one to full one, it already wait until the transaction is committed and the created account is useable.
func (d *DockerTestFramework) CreateAccountFromImplicitAccount(accountWallet *mock.Wallet, implicitAccountOutputData *mock.OutputData, blockIssuance *api.IssuanceBlockHeaderResponse, opts ...options.Option[builder.AccountOutputBuilder]) *mock.AccountData {
ctx := context.TODO()

accountData, signedTx, block := d.TransitionImplicitAccountToAccountOutputBlock(accountWallet, implicitAccountOutputData, blockIssuance, opts...)

d.SubmitBlock(ctx, block)
d.CheckAccountStatus(ctx, block.MustID(), signedTx.Transaction.MustID(), accountData.OutputID, accountData.Address, true)

// update the wallet with the new account data
accountWallet.SetBlockIssuer(accountData)

fmt.Printf("Account created, Bech addr: %s\n", accountData.Address.Bech32(accountWallet.Client.CommittedAPI().ProtocolParameters().Bech32HRP()))

return accountWallet.Account(accountData.ID)
}

// CreateAccountFromFaucet creates a new account by requesting faucet funds to an implicit account address and then transitioning the new output to a full account output.
// It already waits until the transaction is committed and the created account is useable.
func (d *DockerTestFramework) CreateAccountFromFaucet() (*mock.Wallet, *mock.AccountData) {
ctx := context.TODO()

newWallet, implicitAccountOutputData := d.CreateImplicitAccount(ctx)

accountData, signedTx, block := d.TransitionImplicitAccountToAccountOutputBlock(newWallet, implicitAccountOutputData, d.defaultWallet.GetNewBlockIssuanceResponse())

d.SubmitBlock(ctx, block)
d.CheckAccountStatus(ctx, block.MustID(), signedTx.Transaction.MustID(), accountData.OutputID, accountData.Address, true)

// update the wallet with the new account data
newWallet.SetBlockIssuer(accountData)

fmt.Printf("Account created, Bech addr: %s\n", accountData.Address.Bech32(newWallet.Client.CommittedAPI().ProtocolParameters().Bech32HRP()))

return newWallet, newWallet.Account(accountData.ID)
}

// CreateNativeToken request faucet funds then use it to create native token for the account, and returns the updated Account.
func (d *DockerTestFramework) CreateNativeToken(fromWallet *mock.Wallet, mintedAmount iotago.BaseToken, maxSupply iotago.BaseToken) {
require.GreaterOrEqual(d.Testing, maxSupply, mintedAmount)

ctx := context.TODO()

// requesting faucet funds for native token creation
fundsOutputData := d.RequestFaucetFunds(ctx, fromWallet, iotago.AddressEd25519)

signedTx := fromWallet.CreateFoundryAndNativeTokensFromInput(fundsOutputData, mintedAmount, maxSupply)

block, err := fromWallet.CreateAndSubmitBasicBlock(ctx, "native_token", mock.WithPayload(signedTx))
require.NoError(d.Testing, err)

txID := signedTx.Transaction.MustID()
d.AwaitTransactionPayloadAccepted(ctx, txID)

fmt.Println("Create native tokens transaction sent, blkID:", block.ID().ToHex(), ", txID:", signedTx.Transaction.MustID().ToHex(), ", slot:", block.ID().Slot())

// wait for the account to be committed
d.AwaitCommitment(block.ID().Slot())

d.AssertIndexerAccount(fromWallet.BlockIssuer.AccountData)
//nolint:forcetypeassert
d.AssertIndexerFoundry(signedTx.Transaction.Outputs[1].(*iotago.FoundryOutput).MustFoundryID())
}
121 changes: 121 additions & 0 deletions tools/docker-network/tests/dockertestframework/asserts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//go:build dockertests

package dockertestframework

import (
"context"
"fmt"
"sort"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/hive.go/lo"
"github.com/iotaledger/iota-core/pkg/testsuite/mock"
iotago "github.com/iotaledger/iota.go/v4"
)

func (d *DockerTestFramework) AssertIndexerAccount(account *mock.AccountData) {
d.Eventually(func() error {
ctx := context.TODO()
indexerClt, err := d.defaultWallet.Client.Indexer(ctx)
if err != nil {
return err
}

outputID, output, _, err := indexerClt.Account(ctx, account.Address)
if err != nil {
return err
}

assert.EqualValues(d.fakeTesting, account.OutputID, *outputID)
assert.EqualValues(d.fakeTesting, account.Output, output)

return nil
})
}

func (d *DockerTestFramework) AssertIndexerFoundry(foundryID iotago.FoundryID) {
d.Eventually(func() error {
ctx := context.TODO()
indexerClt, err := d.defaultWallet.Client.Indexer(ctx)
if err != nil {
return err
}

_, _, _, err = indexerClt.Foundry(ctx, foundryID)
if err != nil {
return err
}

return nil
})
}

func (d *DockerTestFramework) AssertValidatorExists(accountAddr *iotago.AccountAddress) {
d.Eventually(func() error {
for _, node := range d.Nodes() {
_, err := d.Client(node.Name).Validator(context.TODO(), accountAddr)
if err != nil {
return err
}
}

return nil
})
}

func (d *DockerTestFramework) AssertCommittee(expectedEpoch iotago.EpochIndex, expectedCommitteeMember []string) {
fmt.Println("Wait for committee selection..., expected epoch: ", expectedEpoch, ", expected committee size: ", len(expectedCommitteeMember))
defer fmt.Println("Wait for committee selection......done")

sort.Strings(expectedCommitteeMember)

status := d.NodeStatus("V1")
testAPI := d.defaultWallet.Client.CommittedAPI()
expectedSlotStart := testAPI.TimeProvider().EpochStart(expectedEpoch)
require.Greater(d.Testing, expectedSlotStart, status.LatestAcceptedBlockSlot)

if status.LatestAcceptedBlockSlot < expectedSlotStart {
slotToWait := expectedSlotStart - status.LatestAcceptedBlockSlot
secToWait := time.Duration(slotToWait) * time.Duration(testAPI.ProtocolParameters().SlotDurationInSeconds()) * time.Second
fmt.Println("Wait for ", secToWait, "until expected epoch: ", expectedEpoch)
time.Sleep(secToWait)
}

d.Eventually(func() error {
for _, node := range d.Nodes() {
resp, err := d.Client(node.Name).Committee(context.TODO())
if err != nil {
return err
}

if resp.Epoch == expectedEpoch {
members := make([]string, len(resp.Committee))
for i, member := range resp.Committee {
members[i] = member.AddressBech32
}

sort.Strings(members)
if match := lo.Equal(expectedCommitteeMember, members); match {
return nil
}

return ierrors.Errorf("committee members does not match as expected, expected: %v, actual: %v", expectedCommitteeMember, members)
}
}

return nil
})
}

func (d *DockerTestFramework) AssertFinalizedSlot(condition func(iotago.SlotIndex) error) {
for _, node := range d.Nodes() {
status := d.NodeStatus(node.Name)

err := condition(status.LatestFinalizedSlot)
require.NoError(d.Testing, err)
}
}
Loading

0 comments on commit f91386d

Please sign in to comment.