diff --git a/integration/rpctest/btcd.go b/integration/rpctest/btcd.go new file mode 100644 index 00000000..3c875197 --- /dev/null +++ b/integration/rpctest/btcd.go @@ -0,0 +1,73 @@ +// Copyright (c) 2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package rpctest + +import ( + "fmt" + "go/build" + "os/exec" + "path/filepath" + "runtime" + "sync" +) + +var ( + // compileMtx guards access to the executable path so that the project is + // only compiled once. + compileMtx sync.Mutex + + // executablePath is the path to the compiled executable. This is the empty + // string until btcd is compiled. This should not be accessed directly; + // instead use the function btcdExecutablePath(). + executablePath string +) + +// btcdExecutablePath returns a path to the btcd executable to be used by +// rpctests. To ensure the code tests against the most up-to-date version of +// btcd, this method compiles btcd the first time it is called. After that, the +// generated binary is used for subsequent test harnesses. The executable file +// is not cleaned up, but since it lives at a static path in a temp directory, +// it is not a big deal. +func btcdExecutablePath() (string, error) { + compileMtx.Lock() + defer compileMtx.Unlock() + + // If btcd has already been compiled, just use that. + if len(executablePath) != 0 { + return executablePath, nil + } + + testDir, err := baseDir() + if err != nil { + return "", err + } + + // Determine import path of this package. Not necessarily btcsuite/btcd if + // this is a forked repo. + _, rpctestDir, _, ok := runtime.Caller(1) + if !ok { + return "", fmt.Errorf("Cannot get path to btcd source code") + } + btcdPkgPath := filepath.Join(rpctestDir, "..", "..", "..") + btcdPkg, err := build.ImportDir(btcdPkgPath, build.FindOnly) + if err != nil { + return "", fmt.Errorf("Failed to build btcd: %v", err) + } + + // Build btcd and output an executable in a static temp path. + outputPath := filepath.Join(testDir, "btcd") + if runtime.GOOS == "windows" { + outputPath += ".exe" + } + cmd := exec.Command("go", "build", "-o", outputPath, btcdPkg.ImportPath) + err = cmd.Run() + if err != nil { + return "", fmt.Errorf("Failed to build btcd: %v", err) + } + + // Save executable path so future calls do not recompile. + executablePath = outputPath + return executablePath, nil +} diff --git a/integration/rpctest/node.go b/integration/rpctest/node.go index f56a088a..4d224130 100644 --- a/integration/rpctest/node.go +++ b/integration/rpctest/node.go @@ -42,6 +42,11 @@ type nodeConfig struct { // newConfig returns a newConfig with all default values. func newConfig(prefix, certFile, keyFile string, extra []string) (*nodeConfig, error) { + btcdPath, err := btcdExecutablePath() + if err != nil { + return nil, err + } + a := &nodeConfig{ listen: "127.0.0.1:18555", rpcListen: "127.0.0.1:18556", @@ -49,11 +54,10 @@ func newConfig(prefix, certFile, keyFile string, extra []string) (*nodeConfig, e rpcPass: "pass", extra: extra, prefix: prefix, - - exe: "btcd", - endpoint: "ws", - certFile: certFile, - keyFile: keyFile, + exe: btcdPath, + endpoint: "ws", + certFile: certFile, + keyFile: keyFile, } if err := a.setDefaults(); err != nil { return nil, err diff --git a/integration/rpctest/rpc_harness.go b/integration/rpctest/rpc_harness.go index 145c2938..653a3782 100644 --- a/integration/rpctest/rpc_harness.go +++ b/integration/rpctest/rpc_harness.go @@ -119,8 +119,13 @@ func New(activeNet *chaincfg.Params, handlers *rpcclient.NotificationHandlers, "of the supported chain networks") } + testDir, err := baseDir() + if err != nil { + return nil, err + } + harnessID := strconv.Itoa(numTestInstances) - nodeTestData, err := ioutil.TempDir("", "rpctest-"+harnessID) + nodeTestData, err := ioutil.TempDir(testDir, "harness-"+harnessID) if err != nil { return nil, err } @@ -453,3 +458,10 @@ func generateListeningAddresses() (string, string) { rpc := net.JoinHostPort(localhost, portString(minRPCPort, maxRPCPort)) return p2p, rpc } + +// baseDir is the directory path of the temp directory for all rpctest files. +func baseDir() (string, error) { + dirPath := filepath.Join(os.TempDir(), "btcd", "rpctest") + err := os.MkdirAll(dirPath, 0755) + return dirPath, err +}