Skip to content

Comments

add ability to mock zcashd rpc calls for testing, add tests#164

Merged
LarryRuane merged 1 commit intomasterfrom
more-test-coverage
Jan 31, 2020
Merged

add ability to mock zcashd rpc calls for testing, add tests#164
LarryRuane merged 1 commit intomasterfrom
more-test-coverage

Conversation

@LarryRuane
Copy link
Collaborator

Fixes #146. Small block caching test improvement, but also make the zcashd RPC calls mockable, so tests can generate fake replies, to increase test coverage.

Copy link
Collaborator Author

@LarryRuane LarryRuane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main changes here are to allow calls to zcashd RPCs to be stubbed out. There are a few more instances to do, but this is a start.

defer output.Close()
logger.SetOutput(output)
logger.SetFormatter(&logrus.JSONFormatter{})
}
Copy link
Collaborator Author

@LarryRuane LarryRuane Jan 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is moved, makes sense to open the log file as soon as possible. Slight change (improvement) in behavior -- if you specify -log-file '', the process will log to stdout. (Without these changes, it's not possible to log to stdout.)

common/cache.go Outdated

// Detect reorg, ingestor needs to handle it
if height > c.firstBlock && !bytes.Equal(block.PrevHash, c.m[height-1].hash) {
if block != nil && height > c.firstBlock && !bytes.Equal(block.PrevHash, c.m[height-1].hash) {
Copy link
Collaborator Author

@LarryRuane LarryRuane Jan 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new nil check allows the unit test to force an error below, on the call to proto.Marshal(). I don't love modifying production code just for testing, but I think in this case it's okay, it really is caught below. (This is the only instance of that.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's worth adding a comment in the code to explain this.

retryCount := 0
for {
block, err := getBlockFromRPC(rpcClient, height)
for i := 0; rep == 0 || i < rep; i++ {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rep variable prevents this function from infinite-looping during unit testing (it will, correctly, infinite loop during production).

@LarryRuane LarryRuane changed the title [WIP] add ability to mock zcashd rpc calls for testing add ability to mock zcashd rpc calls for testing, add tests Jan 27, 2020
@LarryRuane LarryRuane closed this Jan 27, 2020
@defuse
Copy link
Contributor

defuse commented Jan 29, 2020

Interesting, github says this PR was closed but it was actually merged. I guess it does that when the branch gets merged differently to how GitHub expects?

@LarryRuane
Copy link
Collaborator Author

I closed this by mistake, reopening

@LarryRuane LarryRuane reopened this Jan 29, 2020
# Lint golang files
lint:
@golint -set_exit_status
golint -set_exit_status
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it much more helpful to see what's actually happening

# Run unittests
test:
@go test -v -coverprofile=coverage.txt -covermode=atomic ./...
go test -v ./...
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no need for atomic, and there's a separate make target for coverage

coverage:
@go test -coverprofile=coverage.out -covermode=atomic ./...
go test -coverprofile=coverage.out ./...
sed -i '/\.pb\.go/d' coverage.out
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the .pb. files are generated (protobuf), and their code coverage is not relevant

}

log = logger.WithFields(logrus.Fields{
common.Log = logger.WithFields(logrus.Fields{
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no reason the logging object can't be a global variable, and doing that simplifies many of the function signatures, and makes unit tests easier to write.

type blockCacheEntry struct {
data []byte
hash []byte
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identifiers that start with a capital letter are exported, but this type definition can remain private.

# apt-get update && apt-get install -y openssl

openssl req -x509 -nodes -newkey rsa:2048 -keyout ./cert.key -out ./cert.pem -days 3650 -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=lightwalletd.testnet.local" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:lightwalletd.testnet.local,DNS:127.0.0.1,DNS:localhost")) No newline at end of file
openssl req -x509 -nodes -newkey rsa:2048 -keyout ./cert.key -out ./cert.pem -days 3650 -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=lightwalletd.testnet.local" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:lightwalletd.testnet.local,DNS:127.0.0.1,DNS:localhost"))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing newline (confuses some tools)

"t123456789012345678901234567890123*", // invalid "*"
"s1234567890123456789012345678901234", // doesn't start with "t"
" t1234567890123456789012345678901234", // extra stuff before
"t1234567890123456789012345678901234 ", // extra stuff after
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test case addresses adityapk00#4

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test case for the newline thing would be "\nt1234567890123456789012345678901234".

rpcaddr := cfg.Section("").Key("rpcbind").String()
if rpcaddr == "" {
rpcaddr = "127.0.0.1"
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not be in this PR, but I ran into this while testing, so...

s.log.Errorf("Got error: %s", rpcErr.Error())
return nil
common.Log.Errorf("Got error: %s", rpcErr.Error())
return err
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (and a few similar cases below) was just broken, nil means no error by convention.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were these maybe intentional for some reason, like to hide the specific error message from the client or something? (I don't think so, it looks like it was just broken)


rawTxData[count] = txData
count++
rawTxData = append(rawTxData, txData)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a slight simplification, no functional change

Copy link
Collaborator Author

@LarryRuane LarryRuane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, github says this PR was closed but it was actually merged. I guess it does that when the branch gets merged differently to how GitHub expects?

I think GitHub noticed that the tip of this branch was equal to the tip of the target branch (master), so it concluded that the changes were merged... when in reality, there were no changes (because of my mistake of force-pushing my branch when it exactly matched master). And because the changes were "merged", it figured that the PR can be closed! Anyway, it's back in the correct state now.

Copy link
Contributor

@defuse defuse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested ACK. This is some awesome testing!! I left some comments, but none of them are blocking.

common/cache.go Outdated

// Detect reorg, ingestor needs to handle it
if height > c.firstBlock && !bytes.Equal(block.PrevHash, c.m[height-1].hash) {
if block != nil && height > c.firstBlock && !bytes.Equal(block.PrevHash, c.m[height-1].hash) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's worth adding a comment in the code to explain this.

s.log.Errorf("Got error: %s", rpcErr.Error())
return nil
common.Log.Errorf("Got error: %s", rpcErr.Error())
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were these maybe intentional for some reason, like to hide the specific error message from the client or something? (I don't think so, it looks like it was just broken)

"t123456789012345678901234567890123*", // invalid "*"
"s1234567890123456789012345678901234", // doesn't start with "t"
" t1234567890123456789012345678901234", // extra stuff before
"t1234567890123456789012345678901234 ", // extra stuff after
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test case for the newline thing would be "\nt1234567890123456789012345678901234".

func TestGenerateCerts(t *testing.T) {
if GenerateCerts() == nil {
t.Fatal("GenerateCerts returned nil")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened #181 so that we're less likely to mistakenly think GenerateCerts is fully tested when we look at the coverage (it'd be obvious if this code was broken because the certs wouldn't work so this is fine for now).

@LarryRuane LarryRuane merged commit a4f9688 into master Jan 31, 2020
@LarryRuane LarryRuane deleted the more-test-coverage branch January 31, 2020 23:36
@LarryRuane
Copy link
Collaborator Author

Force-pushed @defuse's review comment fixes (thanks!), merging now.

@LarryRuane LarryRuane mentioned this pull request Feb 3, 2020
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace SQL storage with in-memory cache testing

2 participants