Merge branch 'tparallel' into 'master'
Add tparallel task See merge request slon/shad-go-private!19
This commit is contained in:
commit
5390645759
3 changed files with 242 additions and 0 deletions
23
tparallel/README.md
Normal file
23
tparallel/README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# tparallel
|
||||
|
||||
Реализуйте api, дублирующее поведение `t.Parallel()`.
|
||||
|
||||
Тест - это функция с сигнатурой `func(*T)`. Вам нужно реализовать функцию `Run(topTests []func(*T))`,
|
||||
запускающую множество top-level тестов.
|
||||
|
||||
Каждый тест получает аргументом уникальный объект `*T`.
|
||||
|
||||
В начате все тесты выполняются последовательно. Если тест вызывает `t.Parallel()`, то он становится
|
||||
паралельным и блокируется на этом вызове. После этого, запускается следующий последовательный тест.
|
||||
|
||||
Когда все последовательные тесты завершились, все паралельные тесты разблокируются и продолжают своё
|
||||
исполнения.
|
||||
|
||||
Функция `Run` выходит, когда завершились все тесты.
|
||||
|
||||
Тест может запускать под-тесты вызывая `t.Run`. Тест считается завершённым, когда завершился он сам и
|
||||
завершились все его подтесты.
|
||||
|
||||
Под-тест начинает своё выполнение последовательно, блокирую вызов Run. Подтест может стать параллельным,
|
||||
вызвав `t.Parallel()`. Такой тест должен продолжить исполнение, после того как функция родительского теста
|
||||
завершилась.
|
18
tparallel/tparallel.go
Normal file
18
tparallel/tparallel.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// +build !solution
|
||||
|
||||
package tparallel
|
||||
|
||||
type T struct {
|
||||
}
|
||||
|
||||
func (t *T) Parallel() {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t *T) Run(subtest func(t *T)) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func Run(topTests []func(t *T)) {
|
||||
panic("implement me")
|
||||
}
|
201
tparallel/tparallel_test.go
Normal file
201
tparallel/tparallel_test.go
Normal file
|
@ -0,0 +1,201 @@
|
|||
package tparallel
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ConcurrencyChecker struct {
|
||||
t *testing.T
|
||||
|
||||
mu sync.Mutex
|
||||
nextStage int
|
||||
waitCount int
|
||||
barrier chan struct{}
|
||||
}
|
||||
|
||||
func (c *ConcurrencyChecker) Sequential(stage int) {
|
||||
c.t.Helper()
|
||||
c.t.Logf("Sequential(%d)", stage)
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if stage != c.nextStage {
|
||||
c.t.Errorf("testing method is executed out of sequence: expected=%d, got=%d", c.nextStage, stage)
|
||||
return
|
||||
}
|
||||
|
||||
c.nextStage++
|
||||
}
|
||||
|
||||
func (c *ConcurrencyChecker) Parallel(stage, count int) {
|
||||
c.t.Helper()
|
||||
c.t.Logf("Parallel(%d, %d)", stage, count)
|
||||
|
||||
var barrier chan struct{}
|
||||
|
||||
func() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if stage != c.nextStage {
|
||||
c.t.Errorf("testing method is executed out of sequence: expected=%d, got=%d", c.nextStage, stage)
|
||||
return
|
||||
}
|
||||
|
||||
if c.waitCount == 0 {
|
||||
c.barrier = make(chan struct{})
|
||||
}
|
||||
barrier = c.barrier
|
||||
|
||||
c.waitCount++
|
||||
|
||||
if c.waitCount == count {
|
||||
c.waitCount = 0
|
||||
c.nextStage++
|
||||
close(c.barrier)
|
||||
}
|
||||
}()
|
||||
|
||||
<-barrier
|
||||
}
|
||||
|
||||
func (c *ConcurrencyChecker) Finish(total int) {
|
||||
if total != c.nextStage {
|
||||
c.t.Errorf("wrong number of stages executed: expected=%d, got=%d", total, c.nextStage)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSequentialExecution(t *testing.T) {
|
||||
check := &ConcurrencyChecker{t: t}
|
||||
defer check.Finish(3)
|
||||
|
||||
Run([]func(*T){
|
||||
func(t *T) {
|
||||
check.Sequential(0)
|
||||
},
|
||||
func(t *T) {
|
||||
check.Sequential(1)
|
||||
},
|
||||
func(t *T) {
|
||||
check.Sequential(2)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestParallelExecution(t *testing.T) {
|
||||
check := &ConcurrencyChecker{t: t}
|
||||
defer check.Finish(4)
|
||||
|
||||
Run([]func(*T){
|
||||
func(t *T) {
|
||||
check.Sequential(0)
|
||||
t.Parallel()
|
||||
check.Parallel(3, 3)
|
||||
},
|
||||
func(t *T) {
|
||||
check.Sequential(1)
|
||||
t.Parallel()
|
||||
check.Parallel(3, 3)
|
||||
},
|
||||
func(t *T) {
|
||||
check.Sequential(2)
|
||||
t.Parallel()
|
||||
check.Parallel(3, 3)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestSequentialSubTests(t *testing.T) {
|
||||
check := &ConcurrencyChecker{t: t}
|
||||
defer check.Finish(5)
|
||||
|
||||
Run([]func(*T){
|
||||
func(t *T) {
|
||||
check.Sequential(0)
|
||||
|
||||
t.Run(func(t *T) {
|
||||
check.Sequential(1)
|
||||
|
||||
t.Run(func(t *T) {
|
||||
check.Sequential(2)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run(func(t *T) {
|
||||
check.Sequential(3)
|
||||
})
|
||||
},
|
||||
func(t *T) {
|
||||
check.Sequential(4)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestParallelGroup(t *testing.T) {
|
||||
check := &ConcurrencyChecker{t: t}
|
||||
defer check.Finish(17)
|
||||
|
||||
Run([]func(*T){
|
||||
func(t *T) {
|
||||
check.Sequential(0)
|
||||
},
|
||||
func(t *T) {
|
||||
check.Sequential(1)
|
||||
|
||||
t.Run(func(t *T) {
|
||||
check.Sequential(2)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
t.Run(func(t *T) {
|
||||
check.Sequential(3 + i)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
check.Parallel(14, 10)
|
||||
})
|
||||
}
|
||||
|
||||
check.Sequential(13)
|
||||
})
|
||||
|
||||
check.Sequential(15)
|
||||
},
|
||||
func(t *T) {
|
||||
check.Sequential(16)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestTwoParallelSequences(t *testing.T) {
|
||||
check := &ConcurrencyChecker{t: t}
|
||||
defer check.Finish(4)
|
||||
|
||||
Run([]func(*T){
|
||||
func(t *T) {
|
||||
check.Sequential(0)
|
||||
t.Parallel()
|
||||
|
||||
t.Run(func(t *T) {
|
||||
check.Parallel(2, 2)
|
||||
})
|
||||
|
||||
t.Run(func(t *T) {
|
||||
check.Parallel(3, 2)
|
||||
})
|
||||
},
|
||||
func(t *T) {
|
||||
check.Sequential(1)
|
||||
t.Parallel()
|
||||
|
||||
t.Run(func(t *T) {
|
||||
check.Parallel(2, 2)
|
||||
})
|
||||
|
||||
t.Run(func(t *T) {
|
||||
check.Parallel(3, 2)
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue