diff --git a/core/integration/test_wrapper.go b/core/integration/test_wrapper.go new file mode 100644 index 0000000000000000000000000000000000000000..b532e4e1021b1171e5ae9f156468bb569a3bac79 --- /dev/null +++ b/core/integration/test_wrapper.go @@ -0,0 +1,128 @@ +// +build integration + +// Space above here matters +// Copyright 2017 Monax Industries Limited +// +// 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. + +package integration + +import ( + "context" + "fmt" + "os" + "strconv" + "time" + + acm "github.com/hyperledger/burrow/account" + "github.com/hyperledger/burrow/consensus/tendermint/validator" + "github.com/hyperledger/burrow/core" + "github.com/hyperledger/burrow/genesis" + "github.com/hyperledger/burrow/keys/mock" + "github.com/hyperledger/burrow/logging" + "github.com/hyperledger/burrow/logging/config" + "github.com/hyperledger/burrow/logging/lifecycle" + "github.com/hyperledger/burrow/permission" + "github.com/hyperledger/burrow/rpc" + tm_config "github.com/tendermint/tendermint/config" +) + +const ( + chainName = "Integration_Test_Chain" + testDir = "./test_scratch/tm_test" +) + +// Enable logger output during tests +var debugLogging = false + +// We use this to wrap tests +func TestWrapper(privateAccounts []acm.PrivateAccount, genesisDoc *genesis.GenesisDoc, runner func() int) int { + fmt.Println("Running with integration TestWrapper (core/integration/test_wrapper.go)...") + + os.RemoveAll(testDir) + os.MkdirAll(testDir, 0777) + os.Chdir(testDir) + + tmConf := tm_config.DefaultConfig() + logger := logging.NewNoopLogger() + if debugLogging { + var err error + // Change config as needed + logger, err = lifecycle.NewLoggerFromLoggingConfig(&config.LoggingConfig{ + RootSink: config.Sink(). + SetTransform(config.FilterTransform(config.IncludeWhenAnyMatches, + //"","", + "method", "GetAccount", + "method", "BroadcastTx", + "tag", "sequence", + "tag", "Commit", + "tag", "CheckTx", + "tag", "DeliverTx", + )). + //AddSinks(config.Sink().SetTransform(config.FilterTransform(config.ExcludeWhenAnyMatches, "run_call", "false")). + AddSinks(config.Sink().SetTransform(config.PruneTransform("log_channel", "trace", "scope", "returns", "run_id", "args")). + AddSinks(config.Sink().SetTransform(config.SortTransform("tx_hash", "time", "message", "method")). + SetOutput(config.StdoutOutput()))), + }) + if err != nil { + panic(err) + } + } + + validatorAccount := privateAccounts[0] + privValidator := validator.NewPrivValidatorMemory(validatorAccount, validatorAccount) + keyClient := mock.NewMockKeyClient(privateAccounts...) + kernel, err := core.NewKernel(context.Background(), keyClient, privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), + nil, logger) + if err != nil { + panic(err) + } + // Sometimes better to not shutdown as logging errors on shutdown may obscure real issue + defer func() { + //kernel.Shutdown(context.Background()) + }() + + err = kernel.Boot() + if err != nil { + panic(err) + } + + return runner() +} + +func TestGenesisDoc(addressables []acm.PrivateAccount) *genesis.GenesisDoc { + accounts := make(map[string]acm.Account, len(addressables)) + for i, pa := range addressables { + account := acm.FromAddressable(pa) + account.AddToBalance(1 << 32) + account.SetPermissions(permission.AllAccountPermissions.Clone()) + accounts[fmt.Sprintf("user_%v", i)] = account + } + genesisTime, err := time.Parse("02-01-2006", "27-10-2017") + if err != nil { + panic("could not parse test genesis time") + } + return genesis.MakeGenesisDocFromAccounts(chainName, nil, genesisTime, accounts, + map[string]acm.Validator{ + "genesis_validator": acm.AsValidator(accounts["user_0"]), + }) +} + +// Deterministic account generation helper. Pass number of accounts to make +func MakePrivateAccounts(n int) []acm.PrivateAccount { + accounts := make([]acm.PrivateAccount, n) + for i := 0; i < n; i++ { + accounts[i] = acm.GeneratePrivateAccountFromSecret("mysecret" + strconv.Itoa(i)) + } + return accounts +} diff --git a/genesis/deterministic_genesis.go b/genesis/deterministic_genesis.go index eeac035ed1ed25489c5b05d7c055b7ede8884a43..de80e258883a9598a7ab32ce5310952d6d9ad95b 100644 --- a/genesis/deterministic_genesis.go +++ b/genesis/deterministic_genesis.go @@ -21,10 +21,10 @@ func NewDeterministicGenesis(seed int64) *deterministicGenesis { } func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, minBalance uint64, numValidators int, - randBonded bool, minBonded int64) (*GenesisDoc, []acm.SigningAccount, []acm.SigningAccount) { + randBonded bool, minBonded int64) (*GenesisDoc, []acm.AddressableSigner, []acm.AddressableSigner) { accounts := make([]Account, numAccounts) - privAccounts := make([]acm.SigningAccount, numAccounts) + privAccounts := make([]acm.AddressableSigner, numAccounts) defaultPerms := permission.DefaultAccountPermissions for i := 0; i < numAccounts; i++ { account, privAccount := dg.Account(randBalance, minBalance) @@ -38,7 +38,7 @@ func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, mi privAccounts[i] = privAccount } validators := make([]Validator, numValidators) - privValidators := make([]acm.SigningAccount, numValidators) + privValidators := make([]acm.AddressableSigner, numValidators) for i := 0; i < numValidators; i++ { validator := acm.GeneratePrivateAccountFromSecret(fmt.Sprintf("val_%v", i)) privValidators[i] = validator @@ -65,7 +65,7 @@ func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, mi } -func (dg *deterministicGenesis) Account(randBalance bool, minBalance uint64) (acm.Account, acm.SigningAccount) { +func (dg *deterministicGenesis) Account(randBalance bool, minBalance uint64) (acm.Account, acm.AddressableSigner) { privateKey, err := acm.GeneratePrivateKey(dg.random) if err != nil { panic(fmt.Errorf("could not generate private key deterministically")) diff --git a/keys/mock/key_client_mock.go b/keys/mock/key_client_mock.go index 2254c1105c7577c8dfef4e3f98068ce841c03e5a..96a614cac83ebe8367a84e76fad91563a1198375 100644 --- a/keys/mock/key_client_mock.go +++ b/keys/mock/key_client_mock.go @@ -59,6 +59,19 @@ func newMockKey() (*MockKey, error) { return key, nil } +func mockKeyFromPrivateAccount(privateAccount acm.PrivateAccount) *MockKey { + _, ok := privateAccount.PrivateKey().Unwrap().(crypto.PrivKeyEd25519) + if !ok { + panic(fmt.Errorf("mock key client only supports ed25519 private keys at present")) + } + key := &MockKey{ + Address: privateAccount.Address(), + PublicKey: privateAccount.PublicKey().RawBytes(), + } + copy(key.PrivateKey[:], privateAccount.PrivateKey().RawBytes()) + return key +} + func (mockKey *MockKey) Sign(message []byte) (acm.Signature, error) { return acm.SignatureFromBytes(ed25519.Sign(&mockKey.PrivateKey, message)[:]) } @@ -73,10 +86,14 @@ type MockKeyClient struct { knownKeys map[acm.Address]*MockKey } -func NewMockKeyClient() *MockKeyClient { - return &MockKeyClient{ +func NewMockKeyClient(privateAccounts ...acm.PrivateAccount) *MockKeyClient { + client := &MockKeyClient{ knownKeys: make(map[acm.Address]*MockKey), } + for _, pa := range privateAccounts { + client.knownKeys[pa.Address()] = mockKeyFromPrivateAccount(pa) + } + return client } func (mock *MockKeyClient) NewKey() acm.Address { diff --git a/rpc/tm/integration/shared.go b/rpc/tm/integration/shared.go index bd7fb72e49b059a99330b59efe5a867fd3b56a00..0f4ba18a5091a7d251fe6ba49472a3d8e1fe6c90 100644 --- a/rpc/tm/integration/shared.go +++ b/rpc/tm/integration/shared.go @@ -19,48 +19,29 @@ package integration import ( "bytes" - "context" - "fmt" "hash/fnv" - "strconv" "testing" - "os" - - "time" - acm "github.com/hyperledger/burrow/account" "github.com/hyperledger/burrow/binary" - "github.com/hyperledger/burrow/consensus/tendermint/validator" - "github.com/hyperledger/burrow/core" + "github.com/hyperledger/burrow/core/integration" "github.com/hyperledger/burrow/execution" - "github.com/hyperledger/burrow/genesis" - "github.com/hyperledger/burrow/logging" - "github.com/hyperledger/burrow/logging/config" - "github.com/hyperledger/burrow/logging/lifecycle" - "github.com/hyperledger/burrow/permission" "github.com/hyperledger/burrow/rpc" tm_client "github.com/hyperledger/burrow/rpc/tm/client" "github.com/hyperledger/burrow/txs" "github.com/stretchr/testify/require" - tm_config "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/rpc/lib/client" ) const ( - chainName = "RPC_Test_Chain" rpcAddr = "0.0.0.0:46657" websocketAddr = rpcAddr websocketEndpoint = "/websocket" - testDir = "./test_scratch/tm_test" ) -// Enable logger output during tests -var debugLogging = false - // global variables for use across all tests var ( - privateAccounts = makePrivateAccounts(5) // make keys + privateAccounts = integration.MakePrivateAccounts(5) // make keys jsonRpcClient = rpcclient.NewJSONRPCClient(rpcAddr) httpClient = rpcclient.NewURIClient(rpcAddr) clients = map[string]tm_client.RPCClient{ @@ -68,90 +49,9 @@ var ( "HTTP": httpClient, } // Initialised in initGlobalVariables - genesisDoc = new(genesis.GenesisDoc) + genesisDoc = integration.TestGenesisDoc(privateAccounts) ) -// We use this to wrap tests -func TestWrapper(runner func() int) int { - fmt.Println("Running with integration TestWrapper (rpc/tm/integration/shared.go)...") - - os.RemoveAll(testDir) - os.MkdirAll(testDir, 0777) - os.Chdir(testDir) - - tmConf := tm_config.DefaultConfig() - logger := logging.NewNoopLogger() - if debugLogging { - var err error - // Change config as needed - logger, err = lifecycle.NewLoggerFromLoggingConfig(&config.LoggingConfig{ - RootSink: config.Sink(). - SetTransform(config.FilterTransform(config.IncludeWhenAnyMatches, - //"","", - "method", "GetAccount", - "method", "BroadcastTx", - "tag", "sequence", - "tag", "Commit", - "tag", "CheckTx", - "tag", "DeliverTx", - )). - //AddSinks(config.Sink().SetTransform(config.FilterTransform(config.ExcludeWhenAnyMatches, "run_call", "false")). - AddSinks(config.Sink().SetTransform(config.PruneTransform("log_channel", "trace", "scope", "returns", "run_id", "args")). - AddSinks(config.Sink().SetTransform(config.SortTransform("tx_hash", "time", "message", "method")). - SetOutput(config.StdoutOutput()))), - }) - if err != nil { - panic(err) - } - } - - privValidator := validator.NewPrivValidatorMemory(privateAccounts[0], privateAccounts[0]) - genesisDoc = testGenesisDoc() - kernel, err := core.NewKernel(context.Background(), privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), - nil, logger) - if err != nil { - panic(err) - } - // Sometimes better to not shutdown as logging errors on shutdown may obscure real issue - defer func() { - //kernel.Shutdown(context.Background()) - }() - - err = kernel.Boot() - if err != nil { - panic(err) - } - - return runner() -} - -func testGenesisDoc() *genesis.GenesisDoc { - accounts := make(map[string]acm.Account, len(privateAccounts)) - for i, pa := range privateAccounts { - account := acm.FromAddressable(pa) - account.AddToBalance(1 << 32) - account.SetPermissions(permission.AllAccountPermissions.Clone()) - accounts[fmt.Sprintf("user_%v", i)] = account - } - genesisTime, err := time.Parse("02-01-2006", "27-10-2017") - if err != nil { - panic("could not parse test genesis time") - } - return genesis.MakeGenesisDocFromAccounts(chainName, nil, genesisTime, accounts, - map[string]acm.Validator{ - "genesis_validator": acm.AsValidator(accounts["user_0"]), - }) -} - -// Deterministic account generation helper. Pass number of accounts to make -func makePrivateAccounts(n int) []acm.SigningAccount { - accounts := make([]acm.SigningAccount, n) - for i := 0; i < n; i++ { - accounts[i] = acm.GeneratePrivateAccountFromSecret("mysecret" + strconv.Itoa(i)) - } - return accounts -} - //------------------------------------------------------------------------------- // some default transaction functions diff --git a/rpc/tm/integration/shared_test.go b/rpc/tm/integration/shared_test.go index 9e8f1d17d1dc0d498b145a7dbe9767c6549eb643..55a2a5b0b4e99955bae50b118c1529d8ba438981 100644 --- a/rpc/tm/integration/shared_test.go +++ b/rpc/tm/integration/shared_test.go @@ -21,11 +21,13 @@ import ( "os" "testing" "time" + + "github.com/hyperledger/burrow/core/integration" ) // Needs to be in a _test.go file to be picked up func TestMain(m *testing.M) { - returnValue := TestWrapper(func() int { + returnValue := integration.TestWrapper(privateAccounts, genesisDoc, func() int { return m.Run() })