Last active
August 5, 2022 15:13
-
-
Save mniak/70bbcaf2b367fcbb5442a75f7b33a044 to your computer and use it in GitHub Desktop.
Golang utils
This file contains hidden or 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
package crypto | |
import ( | |
"bytes" | |
"crypto/md5" | |
"encoding/binary" | |
"io" | |
) | |
type fakeRandom struct { | |
counter int | |
buffer bytes.Buffer | |
} | |
func (fr *fakeRandom) Read(p []byte) (n int, err error) { | |
num := make([]byte, 4) | |
for fr.buffer.Len() < len(p) { | |
binary.BigEndian.PutUint32(num, uint32(fr.counter)) | |
md5Result := md5.Sum(num) | |
_, err := fr.buffer.Write(md5Result[:]) | |
if err != nil { | |
return 0, err | |
} | |
fr.counter++ | |
} | |
return fr.buffer.Read(p) | |
} | |
func FakeRandom() io.Reader { | |
return &fakeRandom{} | |
} |
This file contains hidden or 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
package async | |
import ( | |
"errors" | |
"time" | |
) | |
func Loop(interval time.Duration, fn func()) (stop func()) { | |
stopChan := make(chan bool) | |
go func() { | |
for { | |
select { | |
case <-stopChan: | |
return | |
default: | |
fn() | |
time.Sleep(interval) | |
} | |
} | |
}() | |
return func() { stopChan <- true } | |
} | |
func waitForSuccessOnce(timeout time.Duration, fn func() bool) error { | |
deadline := time.Now().Add(timeout) | |
for time.Now().Before(deadline) { | |
if fn() { | |
return nil | |
} | |
} | |
return errors.New("deadline exceeded") | |
} | |
func WaitForSuccessOnceThenLoop(interval time.Duration, timeout time.Duration, fn func() bool) (stopfn func(), err error) { | |
err = waitForSuccessOnce(timeout, fn) | |
if err != nil { | |
return nil, err | |
} | |
return Loop(interval, func() { fn() }), nil | |
} |
This file contains hidden or 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
package async | |
import ( | |
"sync" | |
"testing" | |
"time" | |
"github.com/stretchr/testify/assert" | |
"github.com/stretchr/testify/require" | |
) | |
func TestLoop(t *testing.T) { | |
const max = 5 | |
array := make([]int, 0) | |
counter := 0 | |
stopChan := make(chan int) | |
stop := Loop(100*time.Millisecond, func() { | |
array = append(array, counter) | |
counter++ | |
if counter == max { | |
stopChan <- counter | |
} | |
}) | |
<-stopChan | |
stop() | |
time.Sleep(1 * time.Second) | |
assert.Equal(t, 5, counter) | |
assert.Equal(t, []int{0, 1, 2, 3, 4}, array) | |
} | |
func TestLoop_Stop(t *testing.T) { | |
counter := 0 | |
stop := Loop(10*time.Millisecond, func() { | |
counter++ | |
}) | |
time.Sleep(100 * time.Millisecond) | |
stop() | |
assert.Equal(t, 10, counter) | |
} | |
func TestWaitForSuccessOnceThenLoop(t *testing.T) { | |
t.Run("Succeed on first attempt", func(t *testing.T) { | |
counter := 0 | |
var mutex sync.Mutex | |
_, err := WaitForSuccessOnceThenLoop(time.Millisecond, time.Second, func() bool { | |
mutex.Lock() | |
counter++ | |
mutex.Unlock() | |
return true | |
}) | |
assert.NoError(t, err) | |
mutex.Lock() | |
assert.Equal(t, 1, counter) | |
mutex.Unlock() | |
}) | |
t.Run("Succeed on third attempt", func(t *testing.T) { | |
counter := 0 | |
var mutex sync.Mutex | |
_, err := WaitForSuccessOnceThenLoop(time.Millisecond, time.Second, func() bool { | |
if counter == 3 { | |
return true | |
} | |
mutex.Lock() | |
counter++ | |
mutex.Unlock() | |
return false | |
}) | |
assert.NoError(t, err) | |
mutex.Lock() | |
assert.Equal(t, 3, counter) | |
mutex.Unlock() | |
}) | |
t.Run("Timeout", func(t *testing.T) { | |
counter := 0 | |
_, err := WaitForSuccessOnceThenLoop(time.Millisecond, time.Second, func() bool { | |
counter++ | |
time.Sleep(100 * time.Millisecond) | |
return false | |
}) | |
assert.Equal(t, 10, counter) | |
assert.EqualError(t, err, "deadline exceeded") | |
}) | |
t.Run("Succeed on first attempt and then continue", func(t *testing.T) { | |
const max = 5 | |
array := make([]int, 0) | |
counter := 0 | |
ch := make(chan int) | |
stop, err := WaitForSuccessOnceThenLoop(time.Millisecond, time.Second, func() bool { | |
array = append(array, counter) | |
counter++ | |
if counter > 1 { | |
ch <- counter | |
} | |
return true | |
}) | |
for { | |
if <-ch >= max { | |
stop() | |
break | |
} | |
} | |
assert.NoError(t, err) | |
assert.Equal(t, []int{0, 1, 2, 3, 4}, array) | |
}) | |
} | |
func TestWaitForSuccessOnceThenLoop_Stop(t *testing.T) { | |
counter := 0 | |
stop, err := WaitForSuccessOnceThenLoop(10*time.Millisecond, time.Second, func() bool { | |
counter++ | |
return true | |
}) | |
require.NoError(t, err) | |
time.Sleep(100 * time.Millisecond) | |
stop() | |
assert.Equal(t, 11, counter) | |
} |
This file contains hidden or 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
package async | |
type Promise[T any] struct { | |
chresult <-chan T | |
cherr <-chan error | |
} | |
func (p Promise[T]) Then(fn func(result T)) Promise[T] { | |
fn(<-p.chresult) | |
return p | |
} | |
func (p Promise[T]) Error(fn func(err error)) Promise[T] { | |
fn(<-p.cherr) | |
return p | |
} | |
func (p Promise[T]) Wait() (T, error) { | |
select { | |
case result := <-p.chresult: | |
return result, nil | |
case err := <-p.cherr: | |
var zero T | |
return zero, err | |
} | |
} | |
func NewPromise[T any](work func(successChan chan<- T, failureChan chan<- error)) Promise[T] { | |
chresult := make(chan T) | |
cherr := make(chan error) | |
go work(chresult, cherr) | |
return Promise[T]{ | |
chresult: chresult, | |
cherr: cherr, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment