@ -50,6 +50,38 @@ var (
}
}
)
)
// waitWatcherStarts waits up to 1s for the keystore watcher to start.
func waitWatcherStart ( ks * KeyStore ) bool {
// On systems where file watch is not supported, just return "ok".
if ! ks . cache . watcher . enabled ( ) {
return true
}
// The watcher should start, and then exit.
for t0 := time . Now ( ) ; time . Since ( t0 ) < 1 * time . Second ; time . Sleep ( 100 * time . Millisecond ) {
if ks . cache . watcherStarted ( ) {
return true
}
}
return false
}
func waitForAccounts ( wantAccounts [ ] accounts . Account , ks * KeyStore ) error {
var list [ ] accounts . Account
for t0 := time . Now ( ) ; time . Since ( t0 ) < 5 * time . Second ; time . Sleep ( 200 * time . Millisecond ) {
list = ks . Accounts ( )
if reflect . DeepEqual ( list , wantAccounts ) {
// ks should have also received change notifications
select {
case <- ks . changes :
default :
return fmt . Errorf ( "wasn't notified of new accounts" )
}
return nil
}
}
return fmt . Errorf ( "\ngot %v\nwant %v" , list , wantAccounts )
}
func TestWatchNewFile ( t * testing . T ) {
func TestWatchNewFile ( t * testing . T ) {
t . Parallel ( )
t . Parallel ( )
@ -57,8 +89,9 @@ func TestWatchNewFile(t *testing.T) {
// Ensure the watcher is started before adding any files.
// Ensure the watcher is started before adding any files.
ks . Accounts ( )
ks . Accounts ( )
time . Sleep ( 1000 * time . Millisecond )
if ! waitWatcherStart ( ks ) {
t . Fatal ( "keystore watcher didn't start in time" )
}
// Move in the files.
// Move in the files.
wantAccounts := make ( [ ] accounts . Account , len ( cachetestAccounts ) )
wantAccounts := make ( [ ] accounts . Account , len ( cachetestAccounts ) )
for i := range cachetestAccounts {
for i := range cachetestAccounts {
@ -72,37 +105,25 @@ func TestWatchNewFile(t *testing.T) {
}
}
// ks should see the accounts.
// ks should see the accounts.
var list [ ] accounts . Account
if err := waitForAccounts ( wantAccounts , ks ) ; err != nil {
for d := 200 * time . Millisecond ; d < 5 * time . Second ; d *= 2 {
t . Error ( err )
list = ks . Accounts ( )
if reflect . DeepEqual ( list , wantAccounts ) {
// ks should have also received change notifications
select {
case <- ks . changes :
default :
t . Fatalf ( "wasn't notified of new accounts" )
}
return
}
time . Sleep ( d )
}
}
t . Errorf ( "got %s, want %s" , spew . Sdump ( list ) , spew . Sdump ( wantAccounts ) )
}
}
func TestWatchNoDir ( t * testing . T ) {
func TestWatchNoDir ( t * testing . T ) {
t . Parallel ( )
t . Parallel ( )
// Create ks but not the directory that it watches.
// Create ks but not the directory that it watches.
rand . Seed ( time . Now ( ) . UnixNano ( ) )
rand . Seed ( time . Now ( ) . UnixNano ( ) )
dir := filepath . Join ( os . TempDir ( ) , fmt . Sprintf ( "eth-keystore-watchnodir-test-%d-%d" , os . Getpid ( ) , rand . Int ( ) ) )
dir := filepath . Join ( os . TempDir ( ) , fmt . Sprintf ( "eth-keystore-watchnodir-test-%d-%d" , os . Getpid ( ) , rand . Int ( ) ) )
ks := NewKeyStore ( dir , LightScryptN , LightScryptP )
ks := NewKeyStore ( dir , LightScryptN , LightScryptP )
list := ks . Accounts ( )
list := ks . Accounts ( )
if len ( list ) > 0 {
if len ( list ) > 0 {
t . Error ( "initial account list not empty:" , list )
t . Error ( "initial account list not empty:" , list )
}
}
time . Sleep ( 100 * time . Millisecond )
// The watcher should start, and then exit.
if ! waitWatcherStart ( ks ) {
t . Fatal ( "keystore watcher didn't start in time" )
}
// Create the directory and copy a key file into it.
// Create the directory and copy a key file into it.
os . MkdirAll ( dir , 0700 )
os . MkdirAll ( dir , 0700 )
defer os . RemoveAll ( dir )
defer os . RemoveAll ( dir )
@ -295,24 +316,6 @@ func TestCacheFind(t *testing.T) {
}
}
}
}
func waitForAccounts ( wantAccounts [ ] accounts . Account , ks * KeyStore ) error {
var list [ ] accounts . Account
for d := 200 * time . Millisecond ; d < 8 * time . Second ; d *= 2 {
list = ks . Accounts ( )
if reflect . DeepEqual ( list , wantAccounts ) {
// ks should have also received change notifications
select {
case <- ks . changes :
default :
return fmt . Errorf ( "wasn't notified of new accounts" )
}
return nil
}
time . Sleep ( d )
}
return fmt . Errorf ( "\ngot %v\nwant %v" , list , wantAccounts )
}
// TestUpdatedKeyfileContents tests that updating the contents of a keystore file
// TestUpdatedKeyfileContents tests that updating the contents of a keystore file
// is noticed by the watcher, and the account cache is updated accordingly
// is noticed by the watcher, and the account cache is updated accordingly
func TestUpdatedKeyfileContents ( t * testing . T ) {
func TestUpdatedKeyfileContents ( t * testing . T ) {
@ -327,8 +330,9 @@ func TestUpdatedKeyfileContents(t *testing.T) {
if len ( list ) > 0 {
if len ( list ) > 0 {
t . Error ( "initial account list not empty:" , list )
t . Error ( "initial account list not empty:" , list )
}
}
time . Sleep ( 100 * time . Millisecond )
if ! waitWatcherStart ( ks ) {
t . Fatal ( "keystore watcher didn't start in time" )
}
// Create the directory and copy a key file into it.
// Create the directory and copy a key file into it.
os . MkdirAll ( dir , 0700 )
os . MkdirAll ( dir , 0700 )
defer os . RemoveAll ( dir )
defer os . RemoveAll ( dir )
@ -346,9 +350,8 @@ func TestUpdatedKeyfileContents(t *testing.T) {
t . Error ( err )
t . Error ( err )
return
return
}
}
// needed so that modTime of `file` is different to its current value after forceCopyFile
// needed so that modTime of `file` is different to its current value after forceCopyFile
time . Sleep ( 1000 * time . Millis econd)
time . Sleep ( time . S econd)
// Now replace file contents
// Now replace file contents
if err := forceCopyFile ( file , cachetestAccounts [ 1 ] . URL . Path ) ; err != nil {
if err := forceCopyFile ( file , cachetestAccounts [ 1 ] . URL . Path ) ; err != nil {
@ -364,7 +367,7 @@ func TestUpdatedKeyfileContents(t *testing.T) {
}
}
// needed so that modTime of `file` is different to its current value after forceCopyFile
// needed so that modTime of `file` is different to its current value after forceCopyFile
time . Sleep ( 1000 * time . Millis econd)
time . Sleep ( time . S econd)
// Now replace file contents again
// Now replace file contents again
if err := forceCopyFile ( file , cachetestAccounts [ 2 ] . URL . Path ) ; err != nil {
if err := forceCopyFile ( file , cachetestAccounts [ 2 ] . URL . Path ) ; err != nil {
@ -380,7 +383,7 @@ func TestUpdatedKeyfileContents(t *testing.T) {
}
}
// needed so that modTime of `file` is different to its current value after os.WriteFile
// needed so that modTime of `file` is different to its current value after os.WriteFile
time . Sleep ( 1000 * time . Millis econd)
time . Sleep ( time . S econd)
// Now replace file contents with crap
// Now replace file contents with crap
if err := os . WriteFile ( file , [ ] byte ( "foo" ) , 0600 ) ; err != nil {
if err := os . WriteFile ( file , [ ] byte ( "foo" ) , 0600 ) ; err != nil {