From 767d32b2b77ae38adfa79e25ace532da3d76076b Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Fri, 8 Sep 2023 10:11:39 +0300 Subject: [PATCH 1/2] Utilize flow.MonotonicEmulator chain for integration tests This will guarantee that the addresses of created accounts will be sequential and start from 0x01. Thus, allowing developers to safely import types of deployed contracts. --- test/emulator_backend.go | 22 +++++++++------- test/test_framework_test.go | 51 ++++++++++++++++++++----------------- test/test_runner.go | 3 ++- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/test/emulator_backend.go b/test/emulator_backend.go index 69024d4e..8f4fc04e 100644 --- a/test/emulator_backend.go +++ b/test/emulator_backend.go @@ -107,14 +107,17 @@ type keyInfo struct { signer crypto.Signer } +var Chain = flow.MonotonicEmulator.Chain() + +var CommonContracts = emulator.NewCommonContracts(Chain) + var systemContracts = func() []common.AddressLocation { - chain := flow.Emulator.Chain() - serviceAddress := chain.ServiceAddress().HexWithPrefix() + serviceAddress := Chain.ServiceAddress().HexWithPrefix() contracts := map[string]string{ "FlowServiceAccount": serviceAddress, - "FlowToken": fvm.FlowTokenAddress(chain).HexWithPrefix(), - "FungibleToken": fvm.FungibleTokenAddress(chain).HexWithPrefix(), - "FlowFees": environment.FlowFeesAddress(chain).HexWithPrefix(), + "FlowToken": fvm.FlowTokenAddress(Chain).HexWithPrefix(), + "FungibleToken": fvm.FungibleTokenAddress(Chain).HexWithPrefix(), + "FlowFees": environment.FlowFeesAddress(Chain).HexWithPrefix(), "FlowStorageFees": serviceAddress, "FlowClusterQC": serviceAddress, "FlowDKG": serviceAddress, @@ -536,7 +539,8 @@ func newBlockchain( []emulator.Option{ emulator.WithStorageLimitEnabled(false), emulator.WithServerLogger(logger), - emulator.Contracts(emulator.CommonContracts), + emulator.Contracts(CommonContracts), + emulator.WithChainID(Chain.ChainID()), }, opts..., )..., @@ -711,7 +715,7 @@ func excludeCommonLocations(coverageReport *runtime.CoverageReport) { for _, location := range systemContracts { coverageReport.ExcludeLocation(location) } - for _, contract := range emulator.CommonContracts { + for _, contract := range CommonContracts { address, _ := common.HexToAddress(contract.Address.String()) location := common.AddressLocation{ Address: address, @@ -725,7 +729,7 @@ func excludeCommonLocations(coverageReport *runtime.CoverageReport) { // address mappings for system/common contracts. func baseConfiguration() *stdlib.Configuration { addresses := make(map[string]common.Address, 0) - serviceAddress, _ := common.HexToAddress("0xf8d6e0586b0a20c7") + serviceAddress := common.Address(Chain.ServiceAddress()) addresses["NonFungibleToken"] = serviceAddress addresses["MetadataViews"] = serviceAddress addresses["ViewResolver"] = serviceAddress @@ -734,7 +738,7 @@ func baseConfiguration() *stdlib.Configuration { address := common.Address(addressLocation.Address) addresses[contract] = address } - for _, contractDescription := range emulator.CommonContracts { + for _, contractDescription := range CommonContracts { contract := contractDescription.Name address := common.Address(contractDescription.Address) addresses[contract] = address diff --git a/test/test_framework_test.go b/test/test_framework_test.go index 863b16b8..149043b1 100644 --- a/test/test_framework_test.go +++ b/test/test_framework_test.go @@ -2957,7 +2957,7 @@ func TestServiceAccount(t *testing.T) { require.NoError(t, err) assert.Equal( t, - "0xf8d6e0586b0a20c7", + "0x0000000000000001", serviceAccount.Address.HexWithPrefix(), ) }) @@ -2977,7 +2977,7 @@ func TestServiceAccount(t *testing.T) { // Assert Test.assertEqual(Type
(), account.address.getType()) Test.assertEqual(Type(), account.publicKey.getType()) - Test.assertEqual(Address(0xf8d6e0586b0a20c7), account.address) + Test.assertEqual(Address(0x0000000000000001), account.address) } ` @@ -3377,7 +3377,7 @@ func TestCoverageReportForIntegrationTests(t *testing.T) { assert.Equal(t, result2.TestName, "testAddSpecialNumber") require.NoError(t, result2.Error) - address, err := common.HexToAddress("0x01cf0e2f2f715450") + address, err := common.HexToAddress("0x0000000000000005") require.NoError(t, err) location := common.AddressLocation{ Address: address, @@ -3400,25 +3400,25 @@ func TestCoverageReportForIntegrationTests(t *testing.T) { assert.ElementsMatch( t, []string{ - "A.0ae53cb6e3f42a79.FlowToken", - "A.ee82856bf20e2aa6.FungibleToken", - "A.e5a8b7f23e8b548f.FlowFees", - "A.f8d6e0586b0a20c7.FlowStorageFees", - "A.f8d6e0586b0a20c7.FlowServiceAccount", - "A.f8d6e0586b0a20c7.FlowClusterQC", - "A.f8d6e0586b0a20c7.FlowDKG", - "A.f8d6e0586b0a20c7.FlowEpoch", - "A.f8d6e0586b0a20c7.FlowIDTableStaking", - "A.f8d6e0586b0a20c7.FlowStakingCollection", - "A.f8d6e0586b0a20c7.LockedTokens", - "A.f8d6e0586b0a20c7.NodeVersionBeacon", - "A.f8d6e0586b0a20c7.StakingProxy", + "A.0000000000000003.FlowToken", + "A.0000000000000002.FungibleToken", + "A.0000000000000004.FlowFees", + "A.0000000000000001.FlowStorageFees", + "A.0000000000000001.FlowServiceAccount", + "A.0000000000000001.FlowClusterQC", + "A.0000000000000001.FlowDKG", + "A.0000000000000001.FlowEpoch", + "A.0000000000000001.FlowIDTableStaking", + "A.0000000000000001.FlowStakingCollection", + "A.0000000000000001.LockedTokens", + "A.0000000000000001.NodeVersionBeacon", + "A.0000000000000001.StakingProxy", "s.7465737400000000000000000000000000000000000000000000000000000000", "I.Crypto", "I.Test", - "A.f8d6e0586b0a20c7.ExampleNFT", - "A.f8d6e0586b0a20c7.NFTStorefrontV2", - "A.f8d6e0586b0a20c7.NFTStorefront", + "A.0000000000000001.ExampleNFT", + "A.0000000000000001.NFTStorefrontV2", + "A.0000000000000001.NFTStorefront", }, coverageReport.ExcludedLocationIDs(), ) @@ -3889,6 +3889,7 @@ func TestGetEventsFromIntegrationTests(t *testing.T) { const testCode = ` import Test + import FooContract from 0x0000000000000005 pub let blockchain = Test.newEmulatorBlockchain() pub let account = blockchain.createAccount() @@ -3916,7 +3917,7 @@ func TestGetEventsFromIntegrationTests(t *testing.T) { Test.expect(result, Test.beSucceeded()) Test.assert(result.returnValue! as! Bool) - let typ = CompositeType("A.01cf0e2f2f715450.FooContract.ContractInitialized")! + let typ = Type() let events = blockchain.eventsOfType(typ) Test.assertEqual(1, events.length) } @@ -3933,10 +3934,14 @@ func TestGetEventsFromIntegrationTests(t *testing.T) { let result = blockchain.executeTransaction(tx) Test.expect(result, Test.beSucceeded()) - let typ = CompositeType("A.01cf0e2f2f715450.FooContract.NumberAdded")! + let typ = Type() let events = blockchain.eventsOfType(typ) Test.assertEqual(1, events.length) + let event = events[0] as! FooContract.NumberAdded + Test.assertEqual(78557, event.n) + Test.assertEqual("Sierpinski", event.trait) + let evts = blockchain.events() Test.expect(evts.length, Test.beGreaterThan(1)) } @@ -4420,7 +4425,7 @@ func TestReferenceDeployedContractTypes(t *testing.T) { const testCode = ` import Test - import FooContract from 0x01cf0e2f2f715450 + import FooContract from 0x0000000000000005 pub let blockchain = Test.newEmulatorBlockchain() pub let account = blockchain.createAccount() @@ -4543,7 +4548,7 @@ func TestReferenceDeployedContractTypes(t *testing.T) { const testCode = ` import Test - import FooContract from 0x01cf0e2f2f715450 + import FooContract from 0x0000000000000005 pub let blockchain = Test.newEmulatorBlockchain() pub let account = blockchain.createAccount() diff --git a/test/test_runner.go b/test/test_runner.go index 33c1fb87..9e331f79 100644 --- a/test/test_runner.go +++ b/test/test_runner.go @@ -169,7 +169,8 @@ func NewTestRunner() *TestRunner { logger := zerolog.New(output).With().Timestamp().Logger().Hook(logCollectionHook) blockchain, err := emulator.New( emulator.WithStorageLimitEnabled(false), - emulator.Contracts(emulator.CommonContracts), + emulator.Contracts(CommonContracts), + emulator.WithChainID(Chain.ChainID()), ) if err != nil { panic(err) From b6814fa5cdf297ee802657a102a1c4a53aa959c7 Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Fri, 8 Sep 2023 20:04:30 +0300 Subject: [PATCH 2/2] Do not export unnecessary types and functions --- test/emulator_backend.go | 48 ++++++++++++++++++++-------------------- test/test_runner.go | 24 ++++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/test/emulator_backend.go b/test/emulator_backend.go index 8f4fc04e..ef304e2e 100644 --- a/test/emulator_backend.go +++ b/test/emulator_backend.go @@ -54,25 +54,25 @@ const helperFilePrefix = "\x00helper/" var _ stdlib.Blockchain = &EmulatorBackend{} -type SystemClock struct { +type systemClock struct { TimeDelta int64 } -func (sc SystemClock) Now() time.Time { +func (sc systemClock) Now() time.Time { return time.Now().Add(time.Second * time.Duration(sc.TimeDelta)).UTC() } -func NewSystemClock() *SystemClock { - return &SystemClock{} +func newSystemClock() *systemClock { + return &systemClock{} } -type DeployedContractConstructorInvocation struct { +type deployedContractConstructorInvocation struct { ConstructorArguments []interpreter.Value ArgumentTypes []sema.Type } -var ContractInvocations = make( - map[string]DeployedContractConstructorInvocation, +var contractInvocations = make( + map[string]deployedContractConstructorInvocation, 0, ) @@ -96,10 +96,10 @@ type EmulatorBackend struct { // logCollection is a hook attached in the server logger, in order // to aggregate and expose log messages from the blockchain. - logCollection *LogCollectionHook + logCollection *logCollectionHook // clock allows manipulating the blockchain's clock. - clock *SystemClock + clock *systemClock } type keyInfo struct { @@ -107,17 +107,17 @@ type keyInfo struct { signer crypto.Signer } -var Chain = flow.MonotonicEmulator.Chain() +var chain = flow.MonotonicEmulator.Chain() -var CommonContracts = emulator.NewCommonContracts(Chain) +var commonContracts = emulator.NewCommonContracts(chain) var systemContracts = func() []common.AddressLocation { - serviceAddress := Chain.ServiceAddress().HexWithPrefix() + serviceAddress := chain.ServiceAddress().HexWithPrefix() contracts := map[string]string{ "FlowServiceAccount": serviceAddress, - "FlowToken": fvm.FlowTokenAddress(Chain).HexWithPrefix(), - "FungibleToken": fvm.FungibleTokenAddress(Chain).HexWithPrefix(), - "FlowFees": environment.FlowFeesAddress(Chain).HexWithPrefix(), + "FlowToken": fvm.FlowTokenAddress(chain).HexWithPrefix(), + "FungibleToken": fvm.FungibleTokenAddress(chain).HexWithPrefix(), + "FlowFees": environment.FlowFeesAddress(chain).HexWithPrefix(), "FlowStorageFees": serviceAddress, "FlowClusterQC": serviceAddress, "FlowDKG": serviceAddress, @@ -146,7 +146,7 @@ func NewEmulatorBackend( stdlibHandler stdlib.StandardLibraryHandler, coverageReport *runtime.CoverageReport, ) *EmulatorBackend { - logCollectionHook := NewLogCollectionHook() + logCollectionHook := newLogCollectionHook() var blockchain *emulator.Blockchain if coverageReport != nil { excludeCommonLocations(coverageReport) @@ -157,7 +157,7 @@ func NewEmulatorBackend( } else { blockchain = newBlockchain(logCollectionHook) } - clock := NewSystemClock() + clock := newSystemClock() blockchain.SetClock(clock) return &EmulatorBackend{ @@ -512,7 +512,7 @@ func (e *EmulatorBackend) DeployContract( } argTypes = append(argTypes, argType) } - ContractInvocations[name] = DeployedContractConstructorInvocation{ + contractInvocations[name] = deployedContractConstructorInvocation{ ConstructorArguments: args, ArgumentTypes: argTypes, } @@ -527,7 +527,7 @@ func (e *EmulatorBackend) Logs() []string { // newBlockchain returns an emulator blockchain for testing. func newBlockchain( - hook *LogCollectionHook, + hook *logCollectionHook, opts ...emulator.Option, ) *emulator.Blockchain { output := zerolog.ConsoleWriter{Out: os.Stdout} @@ -539,8 +539,8 @@ func newBlockchain( []emulator.Option{ emulator.WithStorageLimitEnabled(false), emulator.WithServerLogger(logger), - emulator.Contracts(CommonContracts), - emulator.WithChainID(Chain.ChainID()), + emulator.Contracts(commonContracts), + emulator.WithChainID(chain.ChainID()), }, opts..., )..., @@ -715,7 +715,7 @@ func excludeCommonLocations(coverageReport *runtime.CoverageReport) { for _, location := range systemContracts { coverageReport.ExcludeLocation(location) } - for _, contract := range CommonContracts { + for _, contract := range commonContracts { address, _ := common.HexToAddress(contract.Address.String()) location := common.AddressLocation{ Address: address, @@ -729,7 +729,7 @@ func excludeCommonLocations(coverageReport *runtime.CoverageReport) { // address mappings for system/common contracts. func baseConfiguration() *stdlib.Configuration { addresses := make(map[string]common.Address, 0) - serviceAddress := common.Address(Chain.ServiceAddress()) + serviceAddress := common.Address(chain.ServiceAddress()) addresses["NonFungibleToken"] = serviceAddress addresses["MetadataViews"] = serviceAddress addresses["ViewResolver"] = serviceAddress @@ -738,7 +738,7 @@ func baseConfiguration() *stdlib.Configuration { address := common.Address(addressLocation.Address) addresses[contract] = address } - for _, contractDescription := range CommonContracts { + for _, contractDescription := range commonContracts { contract := contractDescription.Name address := common.Address(contractDescription.Address) addresses[contract] = address diff --git a/test/test_runner.go b/test/test_runner.go index 9e331f79..ab2b94cb 100644 --- a/test/test_runner.go +++ b/test/test_runner.go @@ -74,23 +74,23 @@ type Result struct { Error error } -// LogCollectionHook can be attached to zerolog.Logger objects, in order +// logCollectionHook can be attached to zerolog.Logger objects, in order // to aggregate the log messages in a string slice, containing only the // string message. -type LogCollectionHook struct { +type logCollectionHook struct { Logs []string } -var _ zerolog.Hook = &LogCollectionHook{} +var _ zerolog.Hook = &logCollectionHook{} -// NewLogCollectionHook initializes and returns a *LogCollectionHook -func NewLogCollectionHook() *LogCollectionHook { - return &LogCollectionHook{ +// newLogCollectionHook initializes and returns a *LogCollectionHook +func newLogCollectionHook() *logCollectionHook { + return &logCollectionHook{ Logs: make([]string, 0), } } -func (h *LogCollectionHook) Run(e *zerolog.Event, level zerolog.Level, msg string) { +func (h *logCollectionHook) Run(e *zerolog.Event, level zerolog.Level, msg string) { if level != zerolog.NoLevel { logMsg := strings.Replace( msg, @@ -144,7 +144,7 @@ type TestRunner struct { // logCollection is a hook attached in the program logger of // the script environment, in order to aggregate and expose // log messages from test cases and contracts. - logCollection *LogCollectionHook + logCollection *logCollectionHook // randomSeed is used for randomized test case execution. randomSeed int64 @@ -155,7 +155,7 @@ type TestRunner struct { } func NewTestRunner() *TestRunner { - logCollectionHook := NewLogCollectionHook() + logCollectionHook := newLogCollectionHook() output := zerolog.ConsoleWriter{Out: os.Stdout} output.FormatMessage = func(i interface{}) string { msg := i.(string) @@ -169,8 +169,8 @@ func NewTestRunner() *TestRunner { logger := zerolog.New(output).With().Timestamp().Logger().Hook(logCollectionHook) blockchain, err := emulator.New( emulator.WithStorageLimitEnabled(false), - emulator.Contracts(CommonContracts), - emulator.WithChainID(Chain.ChainID()), + emulator.Contracts(commonContracts), + emulator.WithChainID(chain.ChainID()), ) if err != nil { panic(err) @@ -580,7 +580,7 @@ func (r *TestRunner) interpreterContractValueHandler( default: if _, ok := compositeType.Location.(common.AddressLocation); ok { - invocation, found := ContractInvocations[compositeType.Identifier] + invocation, found := contractInvocations[compositeType.Identifier] if !found { panic(fmt.Errorf("contract invocation not found")) }