Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dcrwtest: Initial Version. #20

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ The following sub-modules are currently provided:

- [`dcrdtest`](./dcrdtest): Provides testing facilities to use
[`dcrd`](https://github.com/decred/dcrd) binaries in a simnet network.
- [`dcrwtest`](./dcrwtest): Provides automation facilities to use
[`dcrwallet`](https://github.com/decred/dcrwallet) binaries in testing or
other autmated scenarios.

## License

Expand Down
1 change: 1 addition & 0 deletions dcrtest.work
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
go 1.19

use ./dcrdtest
use ./dcrwtest
55 changes: 55 additions & 0 deletions dcrwtest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
dcrwtest
=======

[![Build Status](https://github.com/decred/dcrtest/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrtest/actions)
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrtest/dcrwtest)

Package dcrwtest provides a dcrwallet-specific automation and testing
harness. This allows creating, running and operating a decred wallet through its
JSON-RPC and gRPC interfaces.

This package was designed specifically to act as a testing harness for
`dcrwallet`. However, the constructs presented are general enough to be adapted
to any project wishing to programmatically drive a `dcrwallet` instance of its
systems/integration tests.

## Installation and Updating

```shell
$ go get github.com/decred/dcrtest/dcrwtest@latest
```

## Choice of dcrwallet Binary

This library requires a `dcrwallet` binary to be available for running and
driving its operations. The specific binary that is used can be selected in two
ways:

### Manually

Using the package-level `SetPathToDcrwallet()` function, users of `dcrwtest` can
specify a path to a pre-existing binary. This binary must exist and have
executable permissions for the current user.

### Automatically

When a path to an existing `dcrwallet` binary is not defined via
`SetPathToDcrwallet()`, then this package will attempt to build one in a
temporary directory. This requires the Go toolchain to be available for the
current user.

The version of the `dcrwallet` binary that will be built will be chosen
following the rules for the standard Go toolchain module version determination:

1. The version or replacement specified in the currently active [Go
Workspace](https://go.dev/ref/mod#workspaces).
2. The version or replacement specified in the main module (i.e. in the
`go.mod` of the project that imports this package).
3. The version specified in the [go.mod](./go.mod) of this package.

## License

Package dcrwtest is licensed under the [copyfree](http://copyfree.org) ISC
License.

128 changes: 128 additions & 0 deletions dcrwtest/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) 2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package dcrwtest

import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"sync"
)

var (
// pathToDcrwMtx protects the following fields.
pathToDcrwMtx sync.RWMutex

// pathToDcrw points to the test dcrwallet binary. It is supplied
// through NewWithDCRW or created on the first call to New and used
// throughout the life of this package.
pathToDcrw string

// isBuiltBinary tracks whether the dcrwallet binary pointed to by
// pathToDcrw was built by an invocation of globalPathToDcw().
isBuiltBinary bool

// dcrwMainPkg is the main dcrwallet package version.
//
// NOTE: this MUST have the same value as the one required in
// require.go.
dcrwMainPkg = "decred.org/dcrwallet/v3"
)

// SetPathToDcrwallet sets the package level dcrwallet executable. All calls to
// New will use the dcrwallet located there throughout their life. If not set
// upon the first call to New, a dcrwallet will be created in a temporary
// directory and pathToDCRW set automatically.
//
// NOTE: This function is safe for concurrent access, but care must be taken
// when setting different paths and using New, as whatever is at pathToDCRW at
// the time will be used to start that instance.
func SetPathToDcrwallet(path string) {
pathToDcrwMtx.Lock()
pathToDcrw = path
isBuiltBinary = false
pathToDcrwMtx.Unlock()
}

// SetDcrwalletMainPkg sets the version of the main dcrwallet package executable.
// Calls to New that require building a fresh dcrwallet instance will cause
// the specified package to be built.
//
// NOTE: This function is safe for concurrent access, but care must be taken
// when setting different packages and using New, as the value of the package
// set when New() is executed will be used.
func SetDcrwalletMainPkg(pkg string) {
pathToDcrwMtx.Lock()
dcrwMainPkg = pkg
pathToDcrw = ""
isBuiltBinary = false
pathToDcrwMtx.Unlock()
}

// buildDcrw builds a dcrwallet binary in a temp file and returns the path to
// the binary. This requires the Go toolchain to be installed and available in
// the machine. The version of the dcrwallet package built depends on the
// currently required version of the decred.org/dcrwallet module, which may be
// defined by either the go.mod file in this package, a main go.mod file (when
// this package is included as a library in a project) or the current
// workspace.
func buildDcrw(dcrwMainPkg string) (string, error) {
// NOTE: when updating this package, the dummy import in require.go
// MUST also be updated.
outDir, err := os.MkdirTemp("", "dcrwtestdcrwallet")
if err != nil {
return "", err
}

dcrwalletBin := "dcrwallet"
if runtime.GOOS == "windows" {
dcrwalletBin += ".exe"
}

dcrwPath := filepath.Join(outDir, dcrwalletBin)
log.Debugf("Building dcrwallet pkg %s in %s", dcrwMainPkg, dcrwPath)
cmd := exec.Command("go", "build", "-o", dcrwPath, dcrwMainPkg)
output, err := cmd.CombinedOutput()
if err != nil {
log.Error(string(output))
return "", fmt.Errorf("failed to build dcrwallet: %w", err)
}

return dcrwPath, nil
}

// globalPathToDcrw returns the global path to the binary dcrwallet instance.
// If needed, this will attempt to build a test instance of dcrwallet.
func globalPathToDcrw() (string, error) {
pathToDcrwMtx.Lock()
defer pathToDcrwMtx.Unlock()
if pathToDcrw != "" {
return pathToDcrw, nil
}

newPath, err := buildDcrw(dcrwMainPkg)
if err != nil {
return "", err
}
pathToDcrw = newPath
isBuiltBinary = true
return newPath, nil
}

// CleanBuiltDcrwallet cleans the currently used dcrwallet binary dir if it was
// built by this package.
func CleanBuiltDcrwallet() error {
var err error
pathToDcrwMtx.Lock()
if isBuiltBinary && pathToDcrw != "" {
isBuiltBinary = false
err = os.RemoveAll(filepath.Dir(pathToDcrw))
pathToDcrw = ""
}
pathToDcrwMtx.Unlock()
return err

}
34 changes: 34 additions & 0 deletions dcrwtest/builder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package dcrwtest

import (
"os"
"os/exec"
"path/filepath"
"testing"
)

// TestBuilder tests that we can build a new dcrwallet binary.
func TestBuilder(t *testing.T) {
path, err := buildDcrw(dcrwMainPkg)
if err != nil {
t.Fatalf("Unable to build dcrwallet: %v", err)
}

t.Logf("Built dcrwallet at %s", path)

cmd := exec.Command(path, "--version")
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("Unable to fetch dcrwallet output: %v", err)
}

t.Logf("dcrwallet version: %s", string(output))

err = os.RemoveAll(filepath.Dir(path))
if err != nil {
t.Fatal(err)
}
}
64 changes: 64 additions & 0 deletions dcrwtest/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module github.com/decred/dcrtest/dcrwtest

go 1.19

// The following require defines the version of dcrwallet that is built for
// tests of this package and the minimum version used when this package is
// required by a client module (unless overridden in the main module or
// workspace).
require decred.org/dcrwallet/v3 v3.0.0

require (
github.com/decred/dcrd/chaincfg/v3 v3.2.0
github.com/decred/dcrd/dcrjson/v4 v4.0.1
github.com/decred/dcrd/rpcclient/v8 v8.0.0
github.com/decred/dcrd/wire v1.6.0
github.com/decred/slog v1.2.0
github.com/jrick/wsrpc/v2 v2.3.5
golang.org/x/net v0.9.0
golang.org/x/sync v0.5.0
google.golang.org/grpc v1.54.0
matheusd.com/testctx v0.1.0
)

require (
decred.org/cspp/v2 v2.1.0 // indirect
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a // indirect
github.com/dchest/siphash v1.2.3 // indirect
github.com/decred/base58 v1.0.5 // indirect
github.com/decred/dcrd/addrmgr/v2 v2.0.2 // indirect
github.com/decred/dcrd/blockchain/stake/v5 v5.0.0 // indirect
github.com/decred/dcrd/blockchain/standalone/v2 v2.2.0 // indirect
github.com/decred/dcrd/certgen v1.1.2 // indirect
github.com/decred/dcrd/chaincfg/chainhash v1.0.4 // indirect
github.com/decred/dcrd/connmgr/v3 v3.1.1 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect
github.com/decred/dcrd/database/v3 v3.0.1 // indirect
github.com/decred/dcrd/dcrec v1.0.1 // indirect
github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/decred/dcrd/dcrutil/v4 v4.0.1 // indirect
github.com/decred/dcrd/gcs/v4 v4.0.0 // indirect
github.com/decred/dcrd/hdkeychain/v3 v3.1.1 // indirect
github.com/decred/dcrd/rpc/jsonrpc/types/v4 v4.1.0 // indirect
github.com/decred/dcrd/txscript/v4 v4.1.0 // indirect
github.com/decred/go-socks v1.1.0 // indirect
github.com/decred/vspd/client/v2 v2.0.0 // indirect
github.com/decred/vspd/types/v2 v2.1.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/jessevdk/go-flags v1.5.0 // indirect
github.com/jrick/bitset v1.0.0 // indirect
github.com/jrick/logrotate v1.0.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/protobuf v1.30.0 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
)