diff --git a/.gitignore b/.gitignore index 485dee64..edb96870 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +test_data_dir/ diff --git a/.private_blockchain_password b/.private_blockchain_password new file mode 100644 index 00000000..81c545ef --- /dev/null +++ b/.private_blockchain_password @@ -0,0 +1 @@ +1234 diff --git a/.travis.yml b/.travis.yml index a60dc314..1d93167d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: go go: - 1.9 +script: + - go test -v ./core/... diff --git a/README.md b/README.md index 6f694ad6..dd5f9044 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,15 @@ By default, `go get` does not work for private GitHub repos. This will fix that. ## Running the Tests -`go test ./...` +### Integration Test + +In order to run the integration tests, you will need to run them against a real blockchain. Here are steps to create a local, private blockchain. + +1. Run `./scripts/setup` to create a private blockchain with a new account. + * This will result in a warning. +2. Run `./scripts/start_private_blockchain` as a separate process. +3. `go test ./...` + +### Unit Tests + +`go test ./core` \ No newline at end of file diff --git a/core/fake_blockchain_test.go b/core/fake_blockchain_test.go index 6484d83e..64116e12 100644 --- a/core/fake_blockchain_test.go +++ b/core/fake_blockchain_test.go @@ -46,8 +46,8 @@ var _ = Describe("The fake blockchain", func() { blockchain.AddBlock(core.Block{Number: big.NewInt(123)}) - Expect(blockchainObserver.LastAddedBlock.Number).ShouldNot(BeNil()) - Expect(blockchainObserver.LastAddedBlock.Number).Should(Equal(big.NewInt(123))) + Expect(blockchainObserver.LastAddedBlock().Number).ShouldNot(BeNil()) + Expect(blockchainObserver.LastAddedBlock().Number).Should(Equal(big.NewInt(123))) }) }) diff --git a/core/geth_blockchain.go b/core/geth_blockchain.go index 986579d8..84a6ca1b 100644 --- a/core/geth_blockchain.go +++ b/core/geth_blockchain.go @@ -2,6 +2,7 @@ package core import ( "fmt" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "golang.org/x/net/context" @@ -9,8 +10,9 @@ import ( ) type GethBlockchain struct { - client *ethclient.Client - observers []BlockchainObserver + client *ethclient.Client + observers []BlockchainObserver + subscription ethereum.Subscription } func NewGethBlockchain(ipcPath string) *GethBlockchain { @@ -21,12 +23,14 @@ func NewGethBlockchain(ipcPath string) *GethBlockchain { blockchain.client = client return &blockchain } + func (blockchain GethBlockchain) notifyObservers(getBlock *types.Block) { block := convertBlock(getBlock) for _, observer := range blockchain.observers { observer.NotifyBlockAdded(block) } } + func convertBlock(gethBlock *types.Block) Block { return Block{ Number: gethBlock.Number(), @@ -42,7 +46,8 @@ func (blockchain *GethBlockchain) RegisterObserver(observer BlockchainObserver) func (blockchain *GethBlockchain) SubscribeToEvents() { headers := make(chan *types.Header, 10) myContext := context.Background() - blockchain.client.SubscribeNewHead(myContext, headers) + sub, _ := blockchain.client.SubscribeNewHead(myContext, headers) + blockchain.subscription = sub for header := range headers { gethBlock, _ := blockchain.client.BlockByNumber(myContext, header.Number) blockchain.notifyObservers(gethBlock) diff --git a/fakes/blockchain.go b/fakes/blockchain.go index 633f4d55..f88a3c31 100644 --- a/fakes/blockchain.go +++ b/fakes/blockchain.go @@ -18,5 +18,4 @@ func (blockchain *Blockchain) AddBlock(block core.Block) { } } -func (_ *Blockchain) SubscribeToEvents() { -} +func (_ *Blockchain) SubscribeToEvents() {} diff --git a/fakes/blockchain_observer.go b/fakes/blockchain_observer.go index 386e699d..461d6484 100644 --- a/fakes/blockchain_observer.go +++ b/fakes/blockchain_observer.go @@ -6,7 +6,7 @@ import ( type BlockchainObserver struct { wasToldBlockAdded bool - LastAddedBlock core.Block + blocks []core.Block } func (blockchainObserver *BlockchainObserver) WasToldBlockAdded() bool { @@ -14,6 +14,10 @@ func (blockchainObserver *BlockchainObserver) WasToldBlockAdded() bool { } func (blockchainObserver *BlockchainObserver) NotifyBlockAdded(block core.Block) { - blockchainObserver.LastAddedBlock = block + blockchainObserver.blocks = append(blockchainObserver.blocks, block) blockchainObserver.wasToldBlockAdded = true } + +func (observer *BlockchainObserver) LastAddedBlock() core.Block { + return observer.blocks[len(observer.blocks)-1] +} diff --git a/integration_test/geth_blockchain_test.go b/integration_test/geth_blockchain_test.go new file mode 100644 index 00000000..2cdf2985 --- /dev/null +++ b/integration_test/geth_blockchain_test.go @@ -0,0 +1,51 @@ +package integration_test + +import ( + "fmt" + "github.com/8thlight/vulcanizedb/core" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "math/big" + "path" + "path/filepath" + "runtime" +) + +var ( + _, filename, _, _ = runtime.Caller(0) + basepath = filepath.Dir(filename) +) + +func RunTimePath() string { + return path.Join(path.Dir(filename), "../") +} + +type ObserverWithChannel struct { + blocks chan core.Block +} + +func (observer *ObserverWithChannel) NotifyBlockAdded(block core.Block) { + fmt.Println("Block: ", block.Number) + observer.blocks <- block +} + +var _ = Describe("Reading from the Geth blockchain", func() { + + It("reads two blocks with incrementing numbers", func(done Done) { + addedBlock := make(chan core.Block, 10) + observer := &ObserverWithChannel{addedBlock} + + var blockchain core.Blockchain = core.NewGethBlockchain(RunTimePath() + "/test_data_dir/geth.ipc") + blockchain.RegisterObserver(observer) + + go blockchain.SubscribeToEvents() + + firstBlock := <-addedBlock + Expect(firstBlock).ShouldNot(BeNil()) + secondBlock := <-addedBlock + Expect(firstBlock.Number.Add(firstBlock.Number, big.NewInt(1))).Should(Equal(secondBlock.Number)) + + close(done) + }, 30) + +}) diff --git a/integration_test/integration_test_suite_test.go b/integration_test/integration_test_suite_test.go new file mode 100644 index 00000000..b9c75608 --- /dev/null +++ b/integration_test/integration_test_suite_test.go @@ -0,0 +1,13 @@ +package integration_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestIntegrationTest(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "IntegrationTest Suite") +} diff --git a/scripts/setup b/scripts/setup new file mode 100755 index 00000000..d0480bdb --- /dev/null +++ b/scripts/setup @@ -0,0 +1,6 @@ +#!/bin/bash +echo "Deleting test blockchain" +rm -rf test_data_dir +echo "Creating test blockchain with a new account" +mkdir test_data_dir +geth --datadir test_data_dir --password .private_blockchain_password account new diff --git a/scripts/start_private_blockchain b/scripts/start_private_blockchain new file mode 100755 index 00000000..19ed69af --- /dev/null +++ b/scripts/start_private_blockchain @@ -0,0 +1,2 @@ +#!/bin/bash +geth --datadir test_data_dir --dev --nodiscover --mine --minerthreads 1 --maxpeers 0 --verbosity 3 --unlock 0 --password .private_blockchain_password --rpc