feat: implement confirmer

This commit is contained in:
James Houlahan
2020-07-23 13:38:06 +02:00
parent be20714842
commit c8f118a26b
5 changed files with 133 additions and 0 deletions

View File

@ -0,0 +1,44 @@
package confirmer
import (
"errors"
"sync"
"time"
)
type Confirmer struct {
requests map[string]*Request
locker sync.Locker
}
func New() *Confirmer {
return &Confirmer{
requests: make(map[string]*Request),
locker: &sync.Mutex{},
}
}
func (c *Confirmer) NewRequest(timeout time.Duration) *Request {
c.locker.Lock()
defer c.locker.Unlock()
req := newRequest(timeout)
c.requests[req.ID()] = req
return req
}
func (c *Confirmer) SetResponse(uuid string, value bool) error {
c.locker.Lock()
defer c.locker.Unlock()
req, ok := c.requests[uuid]
if !ok {
return errors.New("no such request")
}
req.value <- value
return nil
}

View File

@ -0,0 +1,50 @@
package confirmer
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestConfirmerYes(t *testing.T) {
c := New()
req := c.NewRequest(1 * time.Second)
go func() {
assert.NoError(t, c.SetResponse(req.ID(), true))
}()
res, err := req.Result()
assert.NoError(t, err)
assert.True(t, res)
}
func TestConfirmerNo(t *testing.T) {
c := New()
req := c.NewRequest(1 * time.Second)
go func() {
assert.NoError(t, c.SetResponse(req.ID(), false))
}()
res, err := req.Result()
assert.NoError(t, err)
assert.False(t, res)
}
func TestConfirmerTimeout(t *testing.T) {
c := New()
req := c.NewRequest(1 * time.Second)
go func() {
time.Sleep(2 * time.Second)
assert.NoError(t, c.SetResponse(req.ID(), true))
}()
_, err := req.Result()
assert.Error(t, err)
}

36
pkg/confirmer/request.go Normal file
View File

@ -0,0 +1,36 @@
package confirmer
import (
"errors"
"time"
"github.com/google/uuid"
)
type Request struct {
uuid string
value chan bool
timeout time.Duration
}
func newRequest(timeout time.Duration) *Request {
return &Request{
uuid: uuid.New().String(),
value: make(chan bool),
timeout: timeout,
}
}
func (r *Request) ID() string {
return r.uuid
}
func (r *Request) Result() (bool, error) {
select {
case res := <-r.value:
return res, nil
case <-time.After(r.timeout):
return false, errors.New("timed out waiting for result")
}
}