Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
process testing flags from .meta/config.json (#70)
- Loading branch information
Showing
10 changed files
with
319 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"blurb": "...", | ||
"authors": [ | ||
"..." | ||
], | ||
"contributors": [ | ||
"..." | ||
], | ||
"files": { | ||
"solution": [ | ||
"passing.go" | ||
], | ||
"test": [ | ||
"passing_test.go" | ||
], | ||
"example": [ | ||
".meta/example.go" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"blurb": "Simulate a bank account supporting opening/closing, withdraws, and deposits of money. Watch out for concurrent transactions!", | ||
"authors": [ | ||
"soniakeys" | ||
], | ||
"contributors": [ | ||
"..." | ||
], | ||
"files": { | ||
"solution": [ | ||
"bank_account.go" | ||
], | ||
"test": [ | ||
"bank_account_test.go" | ||
], | ||
"example": [ | ||
".meta/example.go" | ||
] | ||
}, | ||
"custom": { | ||
"testingFlags": [ | ||
"-race" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package account | ||
|
||
import "sync" | ||
|
||
type Account struct { | ||
mu *sync.RWMutex | ||
open bool | ||
balance int64 | ||
} | ||
|
||
func Open(amt int64) *Account { | ||
if amt < 0 { | ||
return nil | ||
} | ||
return &Account{ | ||
open: true, | ||
balance: amt, | ||
mu: new(sync.RWMutex), | ||
} | ||
} | ||
|
||
func (a *Account) Balance() (bal int64, ok bool) { | ||
a.mu.RLock() | ||
bal, ok = a.balance, a.open | ||
a.mu.RUnlock() | ||
return | ||
} | ||
|
||
func (a *Account) Deposit(amt int64) (newBal int64, ok bool) { | ||
a.mu.Lock() | ||
defer a.mu.Unlock() | ||
if !a.open { | ||
return a.balance, false | ||
} | ||
if amt < 0 && a.balance+amt < 0 { | ||
return a.balance, false | ||
} | ||
a.balance += amt | ||
return a.balance, true | ||
} | ||
|
||
func (a *Account) Close() (pay int64, ok bool) { | ||
a.mu.Lock() | ||
defer a.mu.Unlock() | ||
if !a.open { | ||
return 0, false | ||
} | ||
a.open = false | ||
if a.balance < 0 { | ||
return 0, true | ||
} | ||
pay = a.balance | ||
a.balance = 0 | ||
return pay, true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package account | ||
|
||
import "sync" | ||
|
||
type Account struct { | ||
mu *sync.RWMutex | ||
open bool | ||
balance int64 | ||
} | ||
|
||
func Open(amt int64) *Account { | ||
if amt < 0 { | ||
return nil | ||
} | ||
return &Account{ | ||
open: true, | ||
balance: amt, | ||
mu: new(sync.RWMutex), | ||
} | ||
} | ||
|
||
func (a *Account) Balance() (bal int64, ok bool) { | ||
// Locking missing here. | ||
bal, ok = a.balance, a.open | ||
return | ||
} | ||
|
||
func (a *Account) Deposit(amt int64) (newBal int64, ok bool) { | ||
a.mu.Lock() | ||
defer a.mu.Unlock() | ||
if !a.open { | ||
return a.balance, false | ||
} | ||
if amt < 0 && a.balance+amt < 0 { | ||
return a.balance, false | ||
} | ||
a.balance += amt | ||
return a.balance, true | ||
} | ||
|
||
func (a *Account) Close() (pay int64, ok bool) { | ||
a.mu.Lock() | ||
defer a.mu.Unlock() | ||
if !a.open { | ||
return 0, false | ||
} | ||
a.open = false | ||
if a.balance < 0 { | ||
return 0, true | ||
} | ||
pay = a.balance | ||
a.balance = 0 | ||
return pay, true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package account | ||
|
||
import ( | ||
"runtime" | ||
"sync" | ||
"sync/atomic" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestConcDeposit(t *testing.T) { | ||
if runtime.NumCPU() < 2 { | ||
t.Skip("Multiple CPU cores required for concurrency tests.") | ||
} | ||
if runtime.GOMAXPROCS(0) < 2 { | ||
runtime.GOMAXPROCS(2) | ||
} | ||
a := Open(0) | ||
if a == nil { | ||
t.Fatal("Open(0) = nil, want non-nil *Account.") | ||
} | ||
const amt = 10 | ||
const c = 1000 | ||
var negBal int32 | ||
var start, g sync.WaitGroup | ||
start.Add(1) | ||
g.Add(3 * c) | ||
for i := 0; i < c; i++ { | ||
go func() { // deposit | ||
start.Wait() | ||
a.Deposit(amt) // ignore return values | ||
g.Done() | ||
}() | ||
go func() { // withdraw | ||
start.Wait() | ||
for { | ||
if _, ok := a.Deposit(-amt); ok { | ||
break | ||
} | ||
time.Sleep(time.Microsecond) // retry | ||
} | ||
g.Done() | ||
}() | ||
go func() { // watch that balance stays >= 0 | ||
start.Wait() | ||
if p, _ := a.Balance(); p < 0 { | ||
atomic.StoreInt32(&negBal, 1) | ||
} | ||
g.Done() | ||
}() | ||
} | ||
start.Done() | ||
g.Wait() | ||
if negBal == 1 { | ||
t.Fatal("Balance went negative with concurrent deposits and " + | ||
"withdrawals. Want balance always >= 0.") | ||
} | ||
if p, ok := a.Balance(); !ok || p != 0 { | ||
t.Fatalf("After equal concurrent deposits and withdrawals, "+ | ||
"a.Balance = %d, %t. Want 0, true", p, ok) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module account | ||
|
||
go 1.16 |