-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain_test.go
168 lines (148 loc) · 5.85 KB
/
main_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package main
import (
"crypto/md5"
"fmt"
"hash/crc32"
"strconv"
"sync/atomic"
"testing"
"time"
)
/*
это тест на проверку того что у нас это действительно конвейер
неправильное поведение: накапливать результаты выполнения одной функции, а потом слать их в следующую.
это не позволяет запускать на конвейере бесконечные задачи
правильное поведение: обеспечить беспрепятственный поток
*/
/*
This test checks that you in fact implemented a pipeline and not accumulating all results (until the input
is exhausted) and only then passing it to next function in pipeline. This is a wrong approach! It will not
allow to work with tasks that requires input of undefined length. You need to pass the computed result of
the function to the next function in pipeline as soon as it is ready.
*/
func TestPipeline(t *testing.T) {
var ok = true
var recieved uint32
freeFlowJobs := []job{
job(func(in, out chan interface{}) {
out <- 1
time.Sleep(10 * time.Millisecond)
currRecieved := atomic.LoadUint32(&recieved)
// в чем тут суть
// если вы накапливаете значения, то пока вся функция не отрабоатет - дальше они не пойдут
// тут я проверяю, что счетчик увеличился в следующей функции
// это значит что туда дошло значение прежде чем текущая функция отработала
// Here is a gist of this test:
// If you are accumulating values instead of implementing a pipeline, you are not passing values to the
// next funcion before your current function is finished. That is what I am checking: counter
// should increase in next function (meaning that values are going there) before current function
// finished its execution.
if currRecieved == 0 {
ok = false
}
}),
job(func(in, out chan interface{}) {
for _ = range in {
atomic.AddUint32(&recieved, 1)
}
}),
}
ExecutePipeline(freeFlowJobs...)
if !ok || recieved == 0 {
t.Errorf("no value free flow - dont collect them")
}
}
func TestSigner(t *testing.T) {
testExpected := "1173136728138862632818075107442090076184424490584241521304_1696913515191343735512658979631549563179965036907783101867_27225454331033649287118297354036464389062965355426795162684_29568666068035183841425683795340791879727309630931025356555_3994492081516972096677631278379039212655368881548151736_4958044192186797981418233587017209679042592862002427381542_4958044192186797981418233587017209679042592862002427381542"
testResult := "NOT_SET"
// это небольшая защита от попыток не вызывать мои функции расчета
// я преопределяю фукции на свои которые инкрементят локальный счетчик
// переопределение возможо потому что я объявил функцию как переменную, в которой лежит функция
// This is a small check to verify that you are actually using supplied `DataSignerMd5` and
// `DataSignerCrc32` functions. These function are substituted by the ones that are incrementing
// some local counter. Substitution is possible due to the fact that functions are passed as
// variables.
var (
DataSignerSalt string = "" // на сервере будет другое значение
OverheatLockCounter uint32
OverheatUnlockCounter uint32
DataSignerMd5Counter uint32
DataSignerCrc32Counter uint32
)
OverheatLock = func() {
atomic.AddUint32(&OverheatLockCounter, 1)
for {
if swapped := atomic.CompareAndSwapUint32(&dataSignerOverheat, 0, 1); !swapped {
fmt.Println("OverheatLock happend")
time.Sleep(time.Second)
} else {
break
}
}
}
OverheatUnlock = func() {
atomic.AddUint32(&OverheatUnlockCounter, 1)
for {
if swapped := atomic.CompareAndSwapUint32(&dataSignerOverheat, 1, 0); !swapped {
fmt.Println("OverheatUnlock happend")
time.Sleep(time.Second)
} else {
break
}
}
}
DataSignerMd5 = func(data string) string {
atomic.AddUint32(&DataSignerMd5Counter, 1)
OverheatLock()
defer OverheatUnlock()
data += DataSignerSalt
dataHash := fmt.Sprintf("%x", md5.Sum([]byte(data)))
time.Sleep(10 * time.Millisecond)
return dataHash
}
DataSignerCrc32 = func(data string) string {
atomic.AddUint32(&DataSignerCrc32Counter, 1)
data += DataSignerSalt
crcH := crc32.ChecksumIEEE([]byte(data))
dataHash := strconv.FormatUint(uint64(crcH), 10)
time.Sleep(time.Second)
return dataHash
}
inputData := []int{0, 1, 1, 2, 3, 5, 8}
//inputData := []int{0, 1}
hashSignJobs := []job{
job(func(in, out chan interface{}) {
for _, fibNum := range inputData {
out <- fibNum
}
}),
job(SingleHash),
job(MultiHash),
job(CombineResults),
job(func(in, out chan interface{}) {
dataRaw := <-in
data, ok := dataRaw.(string)
if !ok {
t.Error("cant convert result data to string")
}
testResult = data
}),
}
start := time.Now()
ExecutePipeline(hashSignJobs...)
end := time.Since(start)
expectedTime := 3 * time.Second
if testExpected != testResult {
t.Errorf("results not match\nGot: %v\nExpected: %v", testResult, testExpected)
}
if end > expectedTime {
t.Errorf("execition too long\nGot: %s\nExpected: <%s", end, time.Second*3)
}
// 8 потому что 2 в SingleHash и 6 в MultiHash
if int(OverheatLockCounter) != len(inputData) ||
int(OverheatUnlockCounter) != len(inputData) ||
int(DataSignerMd5Counter) != len(inputData) ||
int(DataSignerCrc32Counter) != len(inputData)*8 {
t.Errorf("not enough hash-func calls")
}
}