Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
go-libp2p
Commits
0c73722a
Commit
0c73722a
authored
Nov 15, 2015
by
Jeromy
Browse files
vendor in notifier
parent
d4b42f8e
Changes
82
Show whitespace changes
Inline
Side-by-side
vendor/QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess/periodic/README.md
0 → 100644
View file @
0c73722a
# goprocess/periodic - periodic process creation
-
goprocess: https://github.com/jbenet/goprocess
-
Godoc: https://godoc.org/github.com/jbenet/goprocess/periodic
vendor/QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess/periodic/examples_test.go
0 → 100644
View file @
0c73722a
package
periodicproc_test
import
(
"fmt"
"time"
goprocess
"QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess"
periodicproc
"QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess/periodic"
)
func
ExampleEvery
()
{
tock
:=
make
(
chan
struct
{})
i
:=
0
p
:=
periodicproc
.
Every
(
time
.
Second
,
func
(
proc
goprocess
.
Process
)
{
tock
<-
struct
{}{}
fmt
.
Printf
(
"hello %d
\n
"
,
i
)
i
++
})
<-
tock
<-
tock
<-
tock
p
.
Close
()
// Output:
// hello 0
// hello 1
// hello 2
}
func
ExampleTick
()
{
p
:=
periodicproc
.
Tick
(
time
.
Second
,
func
(
proc
goprocess
.
Process
)
{
fmt
.
Println
(
"tick"
)
})
<-
time
.
After
(
3
*
time
.
Second
+
500
*
time
.
Millisecond
)
p
.
Close
()
// Output:
// tick
// tick
// tick
}
func
ExampleTickGo
()
{
// with TickGo, execution is not rate limited,
// there can be many in-flight simultaneously
wait
:=
make
(
chan
struct
{})
p
:=
periodicproc
.
TickGo
(
time
.
Second
,
func
(
proc
goprocess
.
Process
)
{
fmt
.
Println
(
"tick"
)
<-
wait
})
<-
time
.
After
(
3
*
time
.
Second
+
500
*
time
.
Millisecond
)
wait
<-
struct
{}{}
wait
<-
struct
{}{}
wait
<-
struct
{}{}
p
.
Close
()
// blocks us until all children are closed.
// Output:
// tick
// tick
// tick
}
func
ExampleOnSignal
()
{
sig
:=
make
(
chan
struct
{})
p
:=
periodicproc
.
OnSignal
(
sig
,
func
(
proc
goprocess
.
Process
)
{
fmt
.
Println
(
"fire!"
)
})
sig
<-
struct
{}{}
sig
<-
struct
{}{}
sig
<-
struct
{}{}
p
.
Close
()
// Output:
// fire!
// fire!
// fire!
}
vendor/QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess/periodic/periodic.go
0 → 100644
View file @
0c73722a
// Package periodic is part of github.com/jbenet/goprocess.
// It provides a simple periodic processor that calls a function
// periodically based on some options.
//
// For example:
//
// // use a time.Duration
// p := periodicproc.Every(time.Second, func(proc goprocess.Process) {
// fmt.Printf("the time is %s and all is well", time.Now())
// })
//
// <-time.After(5*time.Second)
// p.Close()
//
// // use a time.Time channel (like time.Ticker)
// p := periodicproc.Tick(time.Tick(time.Second), func(proc goprocess.Process) {
// fmt.Printf("the time is %s and all is well", time.Now())
// })
//
// <-time.After(5*time.Second)
// p.Close()
//
// // or arbitrary signals
// signal := make(chan struct{})
// p := periodicproc.OnSignal(signal, func(proc goprocess.Process) {
// fmt.Printf("the time is %s and all is well", time.Now())
// })
//
// signal<- struct{}{}
// signal<- struct{}{}
// <-time.After(5 * time.Second)
// signal<- struct{}{}
// p.Close()
//
package
periodicproc
import
(
"time"
gp
"QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess"
)
// Every calls the given ProcessFunc at periodic intervals. Internally, it uses
// <-time.After(interval), so it will have the behavior of waiting _at least_
// interval in between calls. If you'd prefer the time.Ticker behavior, use
// periodicproc.Tick instead.
// This is sequentially rate limited, only one call will be in-flight at a time.
func
Every
(
interval
time
.
Duration
,
procfunc
gp
.
ProcessFunc
)
gp
.
Process
{
return
gp
.
Go
(
func
(
proc
gp
.
Process
)
{
for
{
select
{
case
<-
time
.
After
(
interval
)
:
select
{
case
<-
proc
.
Go
(
procfunc
)
.
Closed
()
:
// spin it out as a child, and wait till it's done.
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
}
})
}
// EveryGo calls the given ProcessFunc at periodic intervals. Internally, it uses
// <-time.After(interval)
// This is not rate limited, multiple calls could be in-flight at the same time.
func
EveryGo
(
interval
time
.
Duration
,
procfunc
gp
.
ProcessFunc
)
gp
.
Process
{
return
gp
.
Go
(
func
(
proc
gp
.
Process
)
{
for
{
select
{
case
<-
time
.
After
(
interval
)
:
proc
.
Go
(
procfunc
)
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
}
})
}
// Tick constructs a ticker with interval, and calls the given ProcessFunc every
// time the ticker fires.
// This is sequentially rate limited, only one call will be in-flight at a time.
//
// p := periodicproc.Tick(time.Second, func(proc goprocess.Process) {
// fmt.Println("fire!")
// })
//
// <-time.After(3 * time.Second)
// p.Close()
//
// // Output:
// // fire!
// // fire!
// // fire!
func
Tick
(
interval
time
.
Duration
,
procfunc
gp
.
ProcessFunc
)
gp
.
Process
{
return
gp
.
Go
(
func
(
proc
gp
.
Process
)
{
ticker
:=
time
.
NewTicker
(
interval
)
callOnTicker
(
ticker
.
C
,
procfunc
)(
proc
)
ticker
.
Stop
()
})
}
// TickGo constructs a ticker with interval, and calls the given ProcessFunc every
// time the ticker fires.
// This is not rate limited, multiple calls could be in-flight at the same time.
//
// p := periodicproc.TickGo(time.Second, func(proc goprocess.Process) {
// fmt.Println("fire!")
// <-time.After(10 * time.Second) // will not block sequential execution
// })
//
// <-time.After(3 * time.Second)
// p.Close()
//
// // Output:
// // fire!
// // fire!
// // fire!
func
TickGo
(
interval
time
.
Duration
,
procfunc
gp
.
ProcessFunc
)
gp
.
Process
{
return
gp
.
Go
(
func
(
proc
gp
.
Process
)
{
ticker
:=
time
.
NewTicker
(
interval
)
goCallOnTicker
(
ticker
.
C
,
procfunc
)(
proc
)
ticker
.
Stop
()
})
}
// Ticker calls the given ProcessFunc every time the ticker fires.
// This is sequentially rate limited, only one call will be in-flight at a time.
func
Ticker
(
ticker
<-
chan
time
.
Time
,
procfunc
gp
.
ProcessFunc
)
gp
.
Process
{
return
gp
.
Go
(
callOnTicker
(
ticker
,
procfunc
))
}
// TickerGo calls the given ProcessFunc every time the ticker fires.
// This is not rate limited, multiple calls could be in-flight at the same time.
func
TickerGo
(
ticker
<-
chan
time
.
Time
,
procfunc
gp
.
ProcessFunc
)
gp
.
Process
{
return
gp
.
Go
(
goCallOnTicker
(
ticker
,
procfunc
))
}
func
callOnTicker
(
ticker
<-
chan
time
.
Time
,
pf
gp
.
ProcessFunc
)
gp
.
ProcessFunc
{
return
func
(
proc
gp
.
Process
)
{
for
{
select
{
case
<-
ticker
:
select
{
case
<-
proc
.
Go
(
pf
)
.
Closed
()
:
// spin it out as a child, and wait till it's done.
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
}
}
}
func
goCallOnTicker
(
ticker
<-
chan
time
.
Time
,
pf
gp
.
ProcessFunc
)
gp
.
ProcessFunc
{
return
func
(
proc
gp
.
Process
)
{
for
{
select
{
case
<-
ticker
:
proc
.
Go
(
pf
)
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
}
}
}
// OnSignal calls the given ProcessFunc every time the signal fires, and waits for it to exit.
// This is sequentially rate limited, only one call will be in-flight at a time.
//
// sig := make(chan struct{})
// p := periodicproc.OnSignal(sig, func(proc goprocess.Process) {
// fmt.Println("fire!")
// <-time.After(time.Second) // delays sequential execution by 1 second
// })
//
// sig<- struct{}
// sig<- struct{}
// sig<- struct{}
//
// // Output:
// // fire!
// // fire!
// // fire!
func
OnSignal
(
sig
<-
chan
struct
{},
procfunc
gp
.
ProcessFunc
)
gp
.
Process
{
return
gp
.
Go
(
func
(
proc
gp
.
Process
)
{
for
{
select
{
case
<-
sig
:
select
{
case
<-
proc
.
Go
(
procfunc
)
.
Closed
()
:
// spin it out as a child, and wait till it's done.
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
}
})
}
// OnSignalGo calls the given ProcessFunc every time the signal fires.
// This is not rate limited, multiple calls could be in-flight at the same time.
//
// sig := make(chan struct{})
// p := periodicproc.OnSignalGo(sig, func(proc goprocess.Process) {
// fmt.Println("fire!")
// <-time.After(time.Second) // wont block execution
// })
//
// sig<- struct{}
// sig<- struct{}
// sig<- struct{}
//
// // Output:
// // fire!
// // fire!
// // fire!
func
OnSignalGo
(
sig
<-
chan
struct
{},
procfunc
gp
.
ProcessFunc
)
gp
.
Process
{
return
gp
.
Go
(
func
(
proc
gp
.
Process
)
{
for
{
select
{
case
<-
sig
:
proc
.
Go
(
procfunc
)
case
<-
proc
.
Closing
()
:
// we're told to close
return
}
}
})
}
vendor/QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess/periodic/periodic_test.go
0 → 100644
View file @
0c73722a
package
periodicproc
import
(
"testing"
"time"
gp
"QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess"
ci
"github.com/jbenet/go-cienv"
)
var
(
grace
=
time
.
Millisecond
*
5
interval
=
time
.
Millisecond
*
10
timeout
=
time
.
Second
*
5
)
func
init
()
{
if
ci
.
IsRunning
()
{
grace
=
time
.
Millisecond
*
500
interval
=
time
.
Millisecond
*
1000
timeout
=
time
.
Second
*
15
}
}
func
between
(
min
,
diff
,
max
time
.
Duration
)
bool
{
return
min
<=
diff
&&
diff
<=
max
}
func
testBetween
(
t
*
testing
.
T
,
min
,
diff
,
max
time
.
Duration
)
{
if
!
between
(
min
,
diff
,
max
)
{
t
.
Error
(
"time diff incorrect:"
,
min
,
diff
,
max
)
}
}
type
intervalFunc
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
func
testSeq
(
t
*
testing
.
T
,
toTest
intervalFunc
)
{
t
.
Parallel
()
last
:=
time
.
Now
()
times
:=
make
(
chan
time
.
Time
,
10
)
p
:=
toTest
(
times
,
nil
)
for
i
:=
0
;
i
<
5
;
i
++
{
next
:=
<-
times
testBetween
(
t
,
interval
-
grace
,
next
.
Sub
(
last
),
interval
+
grace
)
last
=
next
}
go
p
.
Close
()
select
{
case
<-
p
.
Closed
()
:
case
<-
time
.
After
(
timeout
)
:
t
.
Error
(
"proc failed to close"
)
}
}
func
testSeqWait
(
t
*
testing
.
T
,
toTest
intervalFunc
)
{
t
.
Parallel
()
last
:=
time
.
Now
()
times
:=
make
(
chan
time
.
Time
,
10
)
wait
:=
make
(
chan
struct
{})
p
:=
toTest
(
times
,
wait
)
for
i
:=
0
;
i
<
5
;
i
++
{
next
:=
<-
times
testBetween
(
t
,
interval
-
grace
,
next
.
Sub
(
last
),
interval
+
grace
)
<-
time
.
After
(
interval
*
2
)
// make it wait.
last
=
time
.
Now
()
// make it now (sequential)
wait
<-
struct
{}{}
// release it.
}
go
p
.
Close
()
select
{
case
<-
p
.
Closed
()
:
case
<-
time
.
After
(
timeout
)
:
t
.
Error
(
"proc failed to close"
)
}
}
func
testSeqNoWait
(
t
*
testing
.
T
,
toTest
intervalFunc
)
{
t
.
Parallel
()
last
:=
time
.
Now
()
times
:=
make
(
chan
time
.
Time
,
10
)
wait
:=
make
(
chan
struct
{})
p
:=
toTest
(
times
,
wait
)
for
i
:=
0
;
i
<
5
;
i
++
{
next
:=
<-
times
testBetween
(
t
,
0
,
next
.
Sub
(
last
),
interval
+
grace
)
// min of 0
<-
time
.
After
(
interval
*
2
)
// make it wait.
last
=
time
.
Now
()
// make it now (sequential)
wait
<-
struct
{}{}
// release it.
}
go
p
.
Close
()
end
:
select
{
case
wait
<-
struct
{}{}
:
// drain any extras.
goto
end
case
<-
p
.
Closed
()
:
case
<-
time
.
After
(
timeout
)
:
t
.
Error
(
"proc failed to close"
)
}
}
func
testParallel
(
t
*
testing
.
T
,
toTest
intervalFunc
)
{
t
.
Parallel
()
last
:=
time
.
Now
()
times
:=
make
(
chan
time
.
Time
,
10
)
wait
:=
make
(
chan
struct
{})
p
:=
toTest
(
times
,
wait
)
for
i
:=
0
;
i
<
5
;
i
++
{
next
:=
<-
times
testBetween
(
t
,
interval
-
grace
,
next
.
Sub
(
last
),
interval
+
grace
)
last
=
next
<-
time
.
After
(
interval
*
2
)
// make it wait.
wait
<-
struct
{}{}
// release it.
}
go
p
.
Close
()
end
:
select
{
case
wait
<-
struct
{}{}
:
// drain any extras.
goto
end
case
<-
p
.
Closed
()
:
case
<-
time
.
After
(
timeout
)
:
t
.
Error
(
"proc failed to close"
)
}
}
func
TestEverySeq
(
t
*
testing
.
T
)
{
testSeq
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
Every
(
interval
,
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
})
})
}
func
TestEverySeqWait
(
t
*
testing
.
T
)
{
testSeqWait
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
Every
(
interval
,
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
select
{
case
<-
wait
:
case
<-
proc
.
Closing
()
:
}
})
})
}
func
TestEveryGoSeq
(
t
*
testing
.
T
)
{
testSeq
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
EveryGo
(
interval
,
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
})
})
}
func
TestEveryGoSeqParallel
(
t
*
testing
.
T
)
{
testParallel
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
EveryGo
(
interval
,
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
select
{
case
<-
wait
:
case
<-
proc
.
Closing
()
:
}
})
})
}
func
TestTickSeq
(
t
*
testing
.
T
)
{
testSeq
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
Tick
(
interval
,
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
})
})
}
func
TestTickSeqNoWait
(
t
*
testing
.
T
)
{
testSeqNoWait
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
Tick
(
interval
,
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
select
{
case
<-
wait
:
case
<-
proc
.
Closing
()
:
}
})
})
}
func
TestTickGoSeq
(
t
*
testing
.
T
)
{
testSeq
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
TickGo
(
interval
,
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
})
})
}
func
TestTickGoSeqParallel
(
t
*
testing
.
T
)
{
testParallel
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
TickGo
(
interval
,
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
select
{
case
<-
wait
:
case
<-
proc
.
Closing
()
:
}
})
})
}
func
TestTickerSeq
(
t
*
testing
.
T
)
{
testSeq
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
Ticker
(
time
.
Tick
(
interval
),
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
})
})
}
func
TestTickerSeqNoWait
(
t
*
testing
.
T
)
{
testSeqNoWait
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
Ticker
(
time
.
Tick
(
interval
),
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
select
{
case
<-
wait
:
case
<-
proc
.
Closing
()
:
}
})
})
}
func
TestTickerGoSeq
(
t
*
testing
.
T
)
{
testSeq
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
TickerGo
(
time
.
Tick
(
interval
),
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
})
})
}
func
TestTickerGoParallel
(
t
*
testing
.
T
)
{
testParallel
(
t
,
func
(
times
chan
<-
time
.
Time
,
wait
<-
chan
struct
{})
(
proc
gp
.
Process
)
{
return
TickerGo
(
time
.
Tick
(
interval
),
func
(
proc
gp
.
Process
)
{
times
<-
time
.
Now
()
select
{
case
<-
wait
:
case
<-
proc
.
Closing
()
:
}
})
})
}
vendor/QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess/ratelimit/README.md
0 → 100644
View file @
0c73722a
# goprocess/ratelimit - ratelimit children creation
-
goprocess: https://github.com/jbenet/goprocess
-
Godoc: https://godoc.org/github.com/jbenet/goprocess/ratelimit
vendor/QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess/ratelimit/ratelimit.go
0 → 100644
View file @
0c73722a
// Package ratelimit is part of github.com/jbenet/goprocess.
// It provides a simple process that ratelimits child creation.
// This is done internally with a channel/semaphore.
// So the call `RateLimiter.LimitedGo` may block until another
// child is Closed().
package
ratelimit
import
(
process
"QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess"
)
// RateLimiter limits the spawning of children. It does so
// with an internal semaphore. Note that Go will continue
// to be the unlimited process.Process.Go, and ONLY the
// added function `RateLimiter.LimitedGo` will honor the
// limit. This is to improve readability and avoid confusion
// for the reader, particularly if code changes over time.
type
RateLimiter
struct
{
process
.
Process
limiter
chan
struct
{}
}
func
NewRateLimiter
(
parent
process
.
Process
,
limit
int
)
*
RateLimiter
{
proc
:=
process
.
WithParent
(
parent
)
return
&
RateLimiter
{
Process
:
proc
,
limiter
:
LimitChan
(
limit
)}
}
// LimitedGo creates a new process, adds it as a child, and spawns the
// ProcessFunc f in its own goroutine, but may block according to the
// internal rate limit. It is equivalent to:
//
// func(f process.ProcessFunc) {
// <-limitch
// p.Go(func (child process.Process) {
// f(child)
// f.Close() // make sure its children close too!
// limitch<- struct{}{}
// })
/// }
//
// It is useful to construct simple asynchronous workers, children of p,
// and rate limit their creation, to avoid spinning up too many, too fast.
// This is great for providing backpressure to producers.
func
(
rl
*
RateLimiter
)
LimitedGo
(
f
process
.
ProcessFunc
)
{
<-
rl
.
limiter
p
:=
rl
.
Go
(
f
)
// this <-closed() is here because the child may have spawned
// children of its own, and our rate limiter should capture that.
go
func
()
{
<-
p
.
Closed
()
rl
.
limiter
<-
struct
{}{}
}()
}
// LimitChan returns a rate-limiting channel. it is the usual, simple,
// golang-idiomatic rate-limiting semaphore. This function merely
// initializes it with certain buffer size, and sends that many values,
// so it is ready to be used.
func
LimitChan
(
limit
int
)
chan
struct
{}
{
limitch
:=
make
(
chan
struct
{},
limit
)
for
i
:=
0
;
i
<
limit
;
i
++
{
limitch
<-
struct
{}{}
}
return
limitch
}
vendor/QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess/ratelimit/ratelimit_test.go
0 → 100644
View file @
0c73722a
package
ratelimit
import
(
"testing"
"time"
process
"QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU/goprocess"
)
func
TestRateLimitLimitedGoBlocks
(
t
*
testing
.
T
)
{
numChildren
:=
6
t
.
Logf
(
"create a rate limiter with limit of %d"
,
numChildren
/
2
)
rl
:=
NewRateLimiter
(
process
.
Background
(),
numChildren
/
2
)
doneSpawning
:=
make
(
chan
struct
{})
childClosing
:=
make
(
chan
struct
{})
t
.
Log
(
"spawn 6 children with LimitedGo."
)
go
func
()
{
for
i
:=
0
;
i
<
numChildren
;
i
++
{
rl
.
LimitedGo
(
func
(
child
process
.
Process
)
{
// hang until we drain childClosing
childClosing
<-
struct
{}{}
})
t
.
Logf
(
"spawned %d"
,
i
)
}
close
(
doneSpawning
)
}()
t
.
Log
(
"should have blocked."
)
select
{
case
<-
doneSpawning
:
t
.
Error
(
"did not block"
)
case
<-
time
.
After
(
time
.
Millisecond
)
:
// for scheduler
t
.
Log
(
"blocked"
)
}
t
.
Logf
(
"drain %d children so they close"
,
numChildren
/
2
)
for
i
:=
0
;
i
<
numChildren
/
2
;
i
++
{
t
.
Logf
(
"closing %d"
,
i
)
<-
childClosing
// consume child cloing
t
.
Logf
(
"closed %d"
,
i
)
}
t
.
Log
(
"should be done spawning."
)
select
{
case
<-
doneSpawning
:
case
<-
time
.
After
(
100
*
time
.
Millisecond
)
:
// for scheduler
t
.
Error
(
"still blocked..."
)
}
t
.
Logf
(
"drain %d children so they close"
,
numChildren
/
2
)
for
i
:=
0
;
i
<
numChildren
/
2
;
i
++
{
<-
childClosing
t
.
Logf
(
"closed %d"
,
i
)
}
rl
.
Close
()
// ensure everyone's closed.
}
func
TestRateLimitGoDoesntBlock
(
t
*
testing
.
T
)
{
numChildren
:=
6
t
.
Logf
(
"create a rate limiter with limit of %d"
,
numChildren
/
2
)
rl
:=
NewRateLimiter
(
process
.
Background
(),
numChildren
/
2
)
doneSpawning
:=
make
(
chan
struct
{})
childClosing
:=
make
(
chan
struct
{})
t
.
Log
(
"spawn 6 children with usual Process.Go."
)
go
func
()
{
for
i
:=
0
;
i
<
numChildren
;
i
++
{
rl
.
Go
(
func
(
child
process
.
Process
)
{
// hang until we drain childClosing
childClosing
<-
struct
{}{}
})
t
.
Logf
(
"spawned %d"
,
i
)
}
close
(
doneSpawning
)
}()
t
.
Log
(
"should not have blocked."
)
select
{
case
<-
doneSpawning
:
t
.
Log
(
"did not block"
)
case
<-
time
.
After
(
100
*
time
.
Millisecond
)
:
// for scheduler
t
.
Error
(
"process.Go blocked. it should not."
)
}
t
.
Log
(
"drain children so they close"
)
for
i
:=
0
;
i
<
numChildren
;
i
++
{
<-
childClosing
t
.
Logf
(
"closed %d"
,
i
)
}
rl
.
Close
()
// ensure everyone's closed.
}
vendor/
thirdparty/
notifier/notifier.go
→
vendor/
QmUtEiB6DmXs7eLJiwS9YFyTAtptqzaWutxCsjHy7UKEgo/go-
notifier/notifier.go
View file @
0c73722a
...
...
@@ -6,8 +6,8 @@ package notifier
import
(
"sync"
process
"
github.com/jbenet
/goprocess"
ratelimit
"
github.com/jbenet
/goprocess/ratelimit"
process
"
QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU
/goprocess"
ratelimit
"
QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU
/goprocess/ratelimit"
)
// Notifiee is a generic interface. Clients implement
...
...
vendor/
thirdparty/
notifier/notifier_test.go
→
vendor/
QmUtEiB6DmXs7eLJiwS9YFyTAtptqzaWutxCsjHy7UKEgo/go-
notifier/notifier_test.go
View file @
0c73722a
File moved
vendor/QmUtEiB6DmXs7eLJiwS9YFyTAtptqzaWutxCsjHy7UKEgo/go-notifier/package.json
0 → 100644
View file @
0c73722a
{
"name"
:
"go-notifier"
,
"author"
:
"whyrusleeping"
,
"version"
:
"1.0.0"
,
"gxDependencies"
:
[
{
"name"
:
"goprocess"
,
"hash"
:
"QmSir6qPL1tjuxd8LkR8VZq6v625ExAUVs2eCLeqQuaPGU"
,
"version"
:
"1.0.0"
}
],
"language"
:
"go"
,
"gx"
:
{
"dvcsimport"
:
"github.com/whyrusleeping/go-notifier"
}
}
\ No newline at end of file
vendor/QmWRypnfEwrgH4k93KEHN5hng7VjKYkWmzDYRuTZeh2Mgh/go-log/context.go
View file @
0c73722a
...
...
@@ -3,7 +3,7 @@ package log
import
(
"errors"
"
golang.org/x/ne
t/context"
"
QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUc
t/context"
)
type
key
int
...
...
vendor/QmWRypnfEwrgH4k93KEHN5hng7VjKYkWmzDYRuTZeh2Mgh/go-log/context_test.go
View file @
0c73722a
...
...
@@ -3,7 +3,7 @@ package log
import
(
"testing"
"
golang.org/x/ne
t/context"
"
QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUc
t/context"
)
func
TestContextContainsMetadata
(
t
*
testing
.
T
)
{
...
...
vendor/QmWRypnfEwrgH4k93KEHN5hng7VjKYkWmzDYRuTZeh2Mgh/go-log/example_test.go
View file @
0c73722a
package
log
import
"
golang.org/x/ne
t/context"
import
"
QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUc
t/context"
func
ExampleEventLogger
()
{
{
...
...
vendor/QmWRypnfEwrgH4k93KEHN5hng7VjKYkWmzDYRuTZeh2Mgh/go-log/log.go
View file @
0c73722a
...
...
@@ -5,7 +5,7 @@ import (
"fmt"
"time"
context
"
golang.org/x/ne
t/context"
context
"
QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUc
t/context"
)
// StandardLogger provides API compatibility with standard printf loggers
...
...
vendor/QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUct/context/context.go
0 → 100644
View file @
0c73722a
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package context defines the Context type, which carries deadlines,
// cancelation signals, and other request-scoped values across API boundaries
// and between processes.
//
// Incoming requests to a server should create a Context, and outgoing calls to
// servers should accept a Context. The chain of function calls between must
// propagate the Context, optionally replacing it with a modified copy created
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
//
// Programs that use Contexts should follow these rules to keep interfaces
// consistent across packages and enable static analysis tools to check context
// propagation:
//
// Do not store Contexts inside a struct type; instead, pass a Context
// explicitly to each function that needs it. The Context should be the first
// parameter, typically named ctx:
//
// func DoSomething(ctx context.Context, arg Arg) error {
// // ... use ctx ...
// }
//
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
// if you are unsure about which Context to use.
//
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
//
// The same Context may be passed to functions running in different goroutines;
// Contexts are safe for simultaneous use by multiple goroutines.
//
// See http://blog.golang.org/context for example code for a server that uses
// Contexts.
package
context
import
(
"errors"
"fmt"
"sync"
"time"
)
// A Context carries a deadline, a cancelation signal, and other values across
// API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
type
Context
interface
{
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
Deadline
()
(
deadline
time
.
Time
,
ok
bool
)
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
//
// WithCancel arranges for Done to be closed when cancel is called;
// WithDeadline arranges for Done to be closed when the deadline
// expires; WithTimeout arranges for Done to be closed when the timeout
// elapses.
//
// Done is provided for use in select statements:
//
// // Stream generates values with DoSomething and sends them to out
// // until DoSomething returns an error or ctx.Done is closed.
// func Stream(ctx context.Context, out <-chan Value) error {
// for {
// v, err := DoSomething(ctx)
// if err != nil {
// return err
// }
// select {
// case <-ctx.Done():
// return ctx.Err()
// case out <- v:
// }
// }
// }
//
// See http://blog.golang.org/pipelines for more examples of how to use
// a Done channel for cancelation.
Done
()
<-
chan
struct
{}
// Err returns a non-nil error value after Done is closed. Err returns
// Canceled if the context was canceled or DeadlineExceeded if the
// context's deadline passed. No other values for Err are defined.
// After Done is closed, successive calls to Err return the same value.
Err
()
error
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
//
// Use context values only for request-scoped data that transits
// processes and API boundaries, not for passing optional parameters to
// functions.
//
// A key identifies a specific value in a Context. Functions that wish
// to store values in Context typically allocate a key in a global
// variable then use that key as the argument to context.WithValue and
// Context.Value. A key can be any type that supports equality;
// packages should define keys as an unexported type to avoid
// collisions.
//
// Packages that define a Context key should provide type-safe accessors
// for the values stores using that key:
//
// // Package user defines a User type that's stored in Contexts.
// package user
//
// import "golang.org/x/net/context"
//
// // User is the type of value stored in the Contexts.
// type User struct {...}
//
// // key is an unexported type for keys defined in this package.
// // This prevents collisions with keys defined in other packages.
// type key int
//
// // userKey is the key for user.User values in Contexts. It is
// // unexported; clients use user.NewContext and user.FromContext
// // instead of using this key directly.
// var userKey key = 0
//
// // NewContext returns a new Context that carries value u.
// func NewContext(ctx context.Context, u *User) context.Context {
// return context.WithValue(ctx, userKey, u)
// }
//
// // FromContext returns the User value stored in ctx, if any.
// func FromContext(ctx context.Context) (*User, bool) {
// u, ok := ctx.Value(userKey).(*User)
// return u, ok
// }
Value
(
key
interface
{})
interface
{}
}
// Canceled is the error returned by Context.Err when the context is canceled.
var
Canceled
=
errors
.
New
(
"context canceled"
)
// DeadlineExceeded is the error returned by Context.Err when the context's
// deadline passes.
var
DeadlineExceeded
=
errors
.
New
(
"context deadline exceeded"
)
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type
emptyCtx
int
func
(
*
emptyCtx
)
Deadline
()
(
deadline
time
.
Time
,
ok
bool
)
{
return
}
func
(
*
emptyCtx
)
Done
()
<-
chan
struct
{}
{
return
nil
}
func
(
*
emptyCtx
)
Err
()
error
{
return
nil
}
func
(
*
emptyCtx
)
Value
(
key
interface
{})
interface
{}
{
return
nil
}
func
(
e
*
emptyCtx
)
String
()
string
{
switch
e
{
case
background
:
return
"context.Background"
case
todo
:
return
"context.TODO"
}
return
"unknown empty Context"
}
var
(
background
=
new
(
emptyCtx
)
todo
=
new
(
emptyCtx
)
)
// Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming
// requests.
func
Background
()
Context
{
return
background
}
// TODO returns a non-nil, empty Context. Code should use context.TODO when
// it's unclear which Context to use or it is not yet available (because the
// surrounding function has not yet been extended to accept a Context
// parameter). TODO is recognized by static analysis tools that determine
// whether Contexts are propagated correctly in a program.
func
TODO
()
Context
{
return
todo
}
// A CancelFunc tells an operation to abandon its work.
// A CancelFunc does not wait for the work to stop.
// After the first call, subsequent calls to a CancelFunc do nothing.
type
CancelFunc
func
()
// WithCancel returns a copy of parent with a new Done channel. The returned
// context's Done channel is closed when the returned cancel function is called
// or when the parent context's Done channel is closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func
WithCancel
(
parent
Context
)
(
ctx
Context
,
cancel
CancelFunc
)
{
c
:=
newCancelCtx
(
parent
)
propagateCancel
(
parent
,
&
c
)
return
&
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
// newCancelCtx returns an initialized cancelCtx.
func
newCancelCtx
(
parent
Context
)
cancelCtx
{
return
cancelCtx
{
Context
:
parent
,
done
:
make
(
chan
struct
{}),
}
}
// propagateCancel arranges for child to be canceled when parent is.
func
propagateCancel
(
parent
Context
,
child
canceler
)
{
if
parent
.
Done
()
==
nil
{
return
// parent is never canceled
}
if
p
,
ok
:=
parentCancelCtx
(
parent
);
ok
{
p
.
mu
.
Lock
()
if
p
.
err
!=
nil
{
// parent has already been canceled
child
.
cancel
(
false
,
p
.
err
)
}
else
{
if
p
.
children
==
nil
{
p
.
children
=
make
(
map
[
canceler
]
bool
)
}
p
.
children
[
child
]
=
true
}
p
.
mu
.
Unlock
()
}
else
{
go
func
()
{
select
{
case
<-
parent
.
Done
()
:
child
.
cancel
(
false
,
parent
.
Err
())
case
<-
child
.
Done
()
:
}
}()
}
}
// parentCancelCtx follows a chain of parent references until it finds a
// *cancelCtx. This function understands how each of the concrete types in this
// package represents its parent.
func
parentCancelCtx
(
parent
Context
)
(
*
cancelCtx
,
bool
)
{
for
{
switch
c
:=
parent
.
(
type
)
{
case
*
cancelCtx
:
return
c
,
true
case
*
timerCtx
:
return
&
c
.
cancelCtx
,
true
case
*
valueCtx
:
parent
=
c
.
Context
default
:
return
nil
,
false
}
}
}
// removeChild removes a context from its parent.
func
removeChild
(
parent
Context
,
child
canceler
)
{
p
,
ok
:=
parentCancelCtx
(
parent
)
if
!
ok
{
return
}
p
.
mu
.
Lock
()
if
p
.
children
!=
nil
{
delete
(
p
.
children
,
child
)
}
p
.
mu
.
Unlock
()
}
// A canceler is a context type that can be canceled directly. The
// implementations are *cancelCtx and *timerCtx.
type
canceler
interface
{
cancel
(
removeFromParent
bool
,
err
error
)
Done
()
<-
chan
struct
{}
}
// A cancelCtx can be canceled. When canceled, it also cancels any children
// that implement canceler.
type
cancelCtx
struct
{
Context
done
chan
struct
{}
// closed by the first cancel call.
mu
sync
.
Mutex
children
map
[
canceler
]
bool
// set to nil by the first cancel call
err
error
// set to non-nil by the first cancel call
}
func
(
c
*
cancelCtx
)
Done
()
<-
chan
struct
{}
{
return
c
.
done
}
func
(
c
*
cancelCtx
)
Err
()
error
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
return
c
.
err
}
func
(
c
*
cancelCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithCancel"
,
c
.
Context
)
}
// cancel closes c.done, cancels each of c's children, and, if
// removeFromParent is true, removes c from its parent's children.
func
(
c
*
cancelCtx
)
cancel
(
removeFromParent
bool
,
err
error
)
{
if
err
==
nil
{
panic
(
"context: internal error: missing cancel error"
)
}
c
.
mu
.
Lock
()
if
c
.
err
!=
nil
{
c
.
mu
.
Unlock
()
return
// already canceled
}
c
.
err
=
err
close
(
c
.
done
)
for
child
:=
range
c
.
children
{
// NOTE: acquiring the child's lock while holding parent's lock.
child
.
cancel
(
false
,
err
)
}
c
.
children
=
nil
c
.
mu
.
Unlock
()
if
removeFromParent
{
removeChild
(
c
.
Context
,
c
)
}
}
// WithDeadline returns a copy of the parent context with the deadline adjusted
// to be no later than d. If the parent's deadline is already earlier than d,
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
// context's Done channel is closed when the deadline expires, when the returned
// cancel function is called, or when the parent context's Done channel is
// closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func
WithDeadline
(
parent
Context
,
deadline
time
.
Time
)
(
Context
,
CancelFunc
)
{
if
cur
,
ok
:=
parent
.
Deadline
();
ok
&&
cur
.
Before
(
deadline
)
{
// The current deadline is already sooner than the new one.
return
WithCancel
(
parent
)
}
c
:=
&
timerCtx
{
cancelCtx
:
newCancelCtx
(
parent
),
deadline
:
deadline
,
}
propagateCancel
(
parent
,
c
)
d
:=
deadline
.
Sub
(
time
.
Now
())
if
d
<=
0
{
c
.
cancel
(
true
,
DeadlineExceeded
)
// deadline has already passed
return
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
if
c
.
err
==
nil
{
c
.
timer
=
time
.
AfterFunc
(
d
,
func
()
{
c
.
cancel
(
true
,
DeadlineExceeded
)
})
}
return
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
// implement Done and Err. It implements cancel by stopping its timer then
// delegating to cancelCtx.cancel.
type
timerCtx
struct
{
cancelCtx
timer
*
time
.
Timer
// Under cancelCtx.mu.
deadline
time
.
Time
}
func
(
c
*
timerCtx
)
Deadline
()
(
deadline
time
.
Time
,
ok
bool
)
{
return
c
.
deadline
,
true
}
func
(
c
*
timerCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithDeadline(%s [%s])"
,
c
.
cancelCtx
.
Context
,
c
.
deadline
,
c
.
deadline
.
Sub
(
time
.
Now
()))
}
func
(
c
*
timerCtx
)
cancel
(
removeFromParent
bool
,
err
error
)
{
c
.
cancelCtx
.
cancel
(
false
,
err
)
if
removeFromParent
{
// Remove this timerCtx from its parent cancelCtx's children.
removeChild
(
c
.
cancelCtx
.
Context
,
c
)
}
c
.
mu
.
Lock
()
if
c
.
timer
!=
nil
{
c
.
timer
.
Stop
()
c
.
timer
=
nil
}
c
.
mu
.
Unlock
()
}
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete:
//
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
// defer cancel() // releases resources if slowOperation completes before timeout elapses
// return slowOperation(ctx)
// }
func
WithTimeout
(
parent
Context
,
timeout
time
.
Duration
)
(
Context
,
CancelFunc
)
{
return
WithDeadline
(
parent
,
time
.
Now
()
.
Add
(
timeout
))
}
// WithValue returns a copy of parent in which the value associated with key is
// val.
//
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
func
WithValue
(
parent
Context
,
key
interface
{},
val
interface
{})
Context
{
return
&
valueCtx
{
parent
,
key
,
val
}
}
// A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context.
type
valueCtx
struct
{
Context
key
,
val
interface
{}
}
func
(
c
*
valueCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithValue(%#v, %#v)"
,
c
.
Context
,
c
.
key
,
c
.
val
)
}
func
(
c
*
valueCtx
)
Value
(
key
interface
{})
interface
{}
{
if
c
.
key
==
key
{
return
c
.
val
}
return
c
.
Context
.
Value
(
key
)
}
vendor/QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUct/context/context_test.go
0 → 100644
View file @
0c73722a
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
context
import
(
"fmt"
"math/rand"
"runtime"
"strings"
"sync"
"testing"
"time"
)
// otherContext is a Context that's not one of the types defined in context.go.
// This lets us test code paths that differ based on the underlying type of the
// Context.
type
otherContext
struct
{
Context
}
func
TestBackground
(
t
*
testing
.
T
)
{
c
:=
Background
()
if
c
==
nil
{
t
.
Fatalf
(
"Background returned nil"
)
}
select
{
case
x
:=
<-
c
.
Done
()
:
t
.
Errorf
(
"<-c.Done() == %v want nothing (it should block)"
,
x
)
default
:
}
if
got
,
want
:=
fmt
.
Sprint
(
c
),
"context.Background"
;
got
!=
want
{
t
.
Errorf
(
"Background().String() = %q want %q"
,
got
,
want
)
}
}
func
TestTODO
(
t
*
testing
.
T
)
{
c
:=
TODO
()
if
c
==
nil
{
t
.
Fatalf
(
"TODO returned nil"
)
}
select
{
case
x
:=
<-
c
.
Done
()
:
t
.
Errorf
(
"<-c.Done() == %v want nothing (it should block)"
,
x
)
default
:
}
if
got
,
want
:=
fmt
.
Sprint
(
c
),
"context.TODO"
;
got
!=
want
{
t
.
Errorf
(
"TODO().String() = %q want %q"
,
got
,
want
)
}
}
func
TestWithCancel
(
t
*
testing
.
T
)
{
c1
,
cancel
:=
WithCancel
(
Background
())
if
got
,
want
:=
fmt
.
Sprint
(
c1
),
"context.Background.WithCancel"
;
got
!=
want
{
t
.
Errorf
(
"c1.String() = %q want %q"
,
got
,
want
)
}
o
:=
otherContext
{
c1
}
c2
,
_
:=
WithCancel
(
o
)
contexts
:=
[]
Context
{
c1
,
o
,
c2
}
for
i
,
c
:=
range
contexts
{
if
d
:=
c
.
Done
();
d
==
nil
{
t
.
Errorf
(
"c[%d].Done() == %v want non-nil"
,
i
,
d
)
}
if
e
:=
c
.
Err
();
e
!=
nil
{
t
.
Errorf
(
"c[%d].Err() == %v want nil"
,
i
,
e
)
}
select
{
case
x
:=
<-
c
.
Done
()
:
t
.
Errorf
(
"<-c.Done() == %v want nothing (it should block)"
,
x
)
default
:
}
}
cancel
()
time
.
Sleep
(
100
*
time
.
Millisecond
)
// let cancelation propagate
for
i
,
c
:=
range
contexts
{
select
{
case
<-
c
.
Done
()
:
default
:
t
.
Errorf
(
"<-c[%d].Done() blocked, but shouldn't have"
,
i
)
}
if
e
:=
c
.
Err
();
e
!=
Canceled
{
t
.
Errorf
(
"c[%d].Err() == %v want %v"
,
i
,
e
,
Canceled
)
}
}
}
func
TestParentFinishesChild
(
t
*
testing
.
T
)
{
// Context tree:
// parent -> cancelChild
// parent -> valueChild -> timerChild
parent
,
cancel
:=
WithCancel
(
Background
())
cancelChild
,
stop
:=
WithCancel
(
parent
)
defer
stop
()
valueChild
:=
WithValue
(
parent
,
"key"
,
"value"
)
timerChild
,
stop
:=
WithTimeout
(
valueChild
,
10000
*
time
.
Hour
)
defer
stop
()
select
{
case
x
:=
<-
parent
.
Done
()
:
t
.
Errorf
(
"<-parent.Done() == %v want nothing (it should block)"
,
x
)
case
x
:=
<-
cancelChild
.
Done
()
:
t
.
Errorf
(
"<-cancelChild.Done() == %v want nothing (it should block)"
,
x
)
case
x
:=
<-
timerChild
.
Done
()
:
t
.
Errorf
(
"<-timerChild.Done() == %v want nothing (it should block)"
,
x
)
case
x
:=
<-
valueChild
.
Done
()
:
t
.
Errorf
(
"<-valueChild.Done() == %v want nothing (it should block)"
,
x
)
default
:
}
// The parent's children should contain the two cancelable children.
pc
:=
parent
.
(
*
cancelCtx
)
cc
:=
cancelChild
.
(
*
cancelCtx
)
tc
:=
timerChild
.
(
*
timerCtx
)
pc
.
mu
.
Lock
()
if
len
(
pc
.
children
)
!=
2
||
!
pc
.
children
[
cc
]
||
!
pc
.
children
[
tc
]
{
t
.
Errorf
(
"bad linkage: pc.children = %v, want %v and %v"
,
pc
.
children
,
cc
,
tc
)
}
pc
.
mu
.
Unlock
()
if
p
,
ok
:=
parentCancelCtx
(
cc
.
Context
);
!
ok
||
p
!=
pc
{
t
.
Errorf
(
"bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true"
,
p
,
ok
,
pc
)
}
if
p
,
ok
:=
parentCancelCtx
(
tc
.
Context
);
!
ok
||
p
!=
pc
{
t
.
Errorf
(
"bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true"
,
p
,
ok
,
pc
)
}
cancel
()
pc
.
mu
.
Lock
()
if
len
(
pc
.
children
)
!=
0
{
t
.
Errorf
(
"pc.cancel didn't clear pc.children = %v"
,
pc
.
children
)
}
pc
.
mu
.
Unlock
()
// parent and children should all be finished.
check
:=
func
(
ctx
Context
,
name
string
)
{
select
{
case
<-
ctx
.
Done
()
:
default
:
t
.
Errorf
(
"<-%s.Done() blocked, but shouldn't have"
,
name
)
}
if
e
:=
ctx
.
Err
();
e
!=
Canceled
{
t
.
Errorf
(
"%s.Err() == %v want %v"
,
name
,
e
,
Canceled
)
}
}
check
(
parent
,
"parent"
)
check
(
cancelChild
,
"cancelChild"
)
check
(
valueChild
,
"valueChild"
)
check
(
timerChild
,
"timerChild"
)
// WithCancel should return a canceled context on a canceled parent.
precanceledChild
:=
WithValue
(
parent
,
"key"
,
"value"
)
select
{
case
<-
precanceledChild
.
Done
()
:
default
:
t
.
Errorf
(
"<-precanceledChild.Done() blocked, but shouldn't have"
)
}
if
e
:=
precanceledChild
.
Err
();
e
!=
Canceled
{
t
.
Errorf
(
"precanceledChild.Err() == %v want %v"
,
e
,
Canceled
)
}
}
func
TestChildFinishesFirst
(
t
*
testing
.
T
)
{
cancelable
,
stop
:=
WithCancel
(
Background
())
defer
stop
()
for
_
,
parent
:=
range
[]
Context
{
Background
(),
cancelable
}
{
child
,
cancel
:=
WithCancel
(
parent
)
select
{
case
x
:=
<-
parent
.
Done
()
:
t
.
Errorf
(
"<-parent.Done() == %v want nothing (it should block)"
,
x
)
case
x
:=
<-
child
.
Done
()
:
t
.
Errorf
(
"<-child.Done() == %v want nothing (it should block)"
,
x
)
default
:
}
cc
:=
child
.
(
*
cancelCtx
)
pc
,
pcok
:=
parent
.
(
*
cancelCtx
)
// pcok == false when parent == Background()
if
p
,
ok
:=
parentCancelCtx
(
cc
.
Context
);
ok
!=
pcok
||
(
ok
&&
pc
!=
p
)
{
t
.
Errorf
(
"bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v"
,
p
,
ok
,
pc
,
pcok
)
}
if
pcok
{
pc
.
mu
.
Lock
()
if
len
(
pc
.
children
)
!=
1
||
!
pc
.
children
[
cc
]
{
t
.
Errorf
(
"bad linkage: pc.children = %v, cc = %v"
,
pc
.
children
,
cc
)
}
pc
.
mu
.
Unlock
()
}
cancel
()
if
pcok
{
pc
.
mu
.
Lock
()
if
len
(
pc
.
children
)
!=
0
{
t
.
Errorf
(
"child's cancel didn't remove self from pc.children = %v"
,
pc
.
children
)
}
pc
.
mu
.
Unlock
()
}
// child should be finished.
select
{
case
<-
child
.
Done
()
:
default
:
t
.
Errorf
(
"<-child.Done() blocked, but shouldn't have"
)
}
if
e
:=
child
.
Err
();
e
!=
Canceled
{
t
.
Errorf
(
"child.Err() == %v want %v"
,
e
,
Canceled
)
}
// parent should not be finished.
select
{
case
x
:=
<-
parent
.
Done
()
:
t
.
Errorf
(
"<-parent.Done() == %v want nothing (it should block)"
,
x
)
default
:
}
if
e
:=
parent
.
Err
();
e
!=
nil
{
t
.
Errorf
(
"parent.Err() == %v want nil"
,
e
)
}
}
}
func
testDeadline
(
c
Context
,
wait
time
.
Duration
,
t
*
testing
.
T
)
{
select
{
case
<-
time
.
After
(
wait
)
:
t
.
Fatalf
(
"context should have timed out"
)
case
<-
c
.
Done
()
:
}
if
e
:=
c
.
Err
();
e
!=
DeadlineExceeded
{
t
.
Errorf
(
"c.Err() == %v want %v"
,
e
,
DeadlineExceeded
)
}
}
func
TestDeadline
(
t
*
testing
.
T
)
{
c
,
_
:=
WithDeadline
(
Background
(),
time
.
Now
()
.
Add
(
100
*
time
.
Millisecond
))
if
got
,
prefix
:=
fmt
.
Sprint
(
c
),
"context.Background.WithDeadline("
;
!
strings
.
HasPrefix
(
got
,
prefix
)
{
t
.
Errorf
(
"c.String() = %q want prefix %q"
,
got
,
prefix
)
}
testDeadline
(
c
,
200
*
time
.
Millisecond
,
t
)
c
,
_
=
WithDeadline
(
Background
(),
time
.
Now
()
.
Add
(
100
*
time
.
Millisecond
))
o
:=
otherContext
{
c
}
testDeadline
(
o
,
200
*
time
.
Millisecond
,
t
)
c
,
_
=
WithDeadline
(
Background
(),
time
.
Now
()
.
Add
(
100
*
time
.
Millisecond
))
o
=
otherContext
{
c
}
c
,
_
=
WithDeadline
(
o
,
time
.
Now
()
.
Add
(
300
*
time
.
Millisecond
))
testDeadline
(
c
,
200
*
time
.
Millisecond
,
t
)
}
func
TestTimeout
(
t
*
testing
.
T
)
{
c
,
_
:=
WithTimeout
(
Background
(),
100
*
time
.
Millisecond
)
if
got
,
prefix
:=
fmt
.
Sprint
(
c
),
"context.Background.WithDeadline("
;
!
strings
.
HasPrefix
(
got
,
prefix
)
{
t
.
Errorf
(
"c.String() = %q want prefix %q"
,
got
,
prefix
)
}
testDeadline
(
c
,
200
*
time
.
Millisecond
,
t
)
c
,
_
=
WithTimeout
(
Background
(),
100
*
time
.
Millisecond
)
o
:=
otherContext
{
c
}
testDeadline
(
o
,
200
*
time
.
Millisecond
,
t
)
c
,
_
=
WithTimeout
(
Background
(),
100
*
time
.
Millisecond
)
o
=
otherContext
{
c
}
c
,
_
=
WithTimeout
(
o
,
300
*
time
.
Millisecond
)
testDeadline
(
c
,
200
*
time
.
Millisecond
,
t
)
}
func
TestCanceledTimeout
(
t
*
testing
.
T
)
{
c
,
_
:=
WithTimeout
(
Background
(),
200
*
time
.
Millisecond
)
o
:=
otherContext
{
c
}
c
,
cancel
:=
WithTimeout
(
o
,
400
*
time
.
Millisecond
)
cancel
()
time
.
Sleep
(
100
*
time
.
Millisecond
)
// let cancelation propagate
select
{
case
<-
c
.
Done
()
:
default
:
t
.
Errorf
(
"<-c.Done() blocked, but shouldn't have"
)
}
if
e
:=
c
.
Err
();
e
!=
Canceled
{
t
.
Errorf
(
"c.Err() == %v want %v"
,
e
,
Canceled
)
}
}
type
key1
int
type
key2
int
var
k1
=
key1
(
1
)
var
k2
=
key2
(
1
)
// same int as k1, different type
var
k3
=
key2
(
3
)
// same type as k2, different int
func
TestValues
(
t
*
testing
.
T
)
{
check
:=
func
(
c
Context
,
nm
,
v1
,
v2
,
v3
string
)
{
if
v
,
ok
:=
c
.
Value
(
k1
)
.
(
string
);
ok
==
(
len
(
v1
)
==
0
)
||
v
!=
v1
{
t
.
Errorf
(
`%s.Value(k1).(string) = %q, %t want %q, %t`
,
nm
,
v
,
ok
,
v1
,
len
(
v1
)
!=
0
)
}
if
v
,
ok
:=
c
.
Value
(
k2
)
.
(
string
);
ok
==
(
len
(
v2
)
==
0
)
||
v
!=
v2
{
t
.
Errorf
(
`%s.Value(k2).(string) = %q, %t want %q, %t`
,
nm
,
v
,
ok
,
v2
,
len
(
v2
)
!=
0
)
}
if
v
,
ok
:=
c
.
Value
(
k3
)
.
(
string
);
ok
==
(
len
(
v3
)
==
0
)
||
v
!=
v3
{
t
.
Errorf
(
`%s.Value(k3).(string) = %q, %t want %q, %t`
,
nm
,
v
,
ok
,
v3
,
len
(
v3
)
!=
0
)
}
}
c0
:=
Background
()
check
(
c0
,
"c0"
,
""
,
""
,
""
)
c1
:=
WithValue
(
Background
(),
k1
,
"c1k1"
)
check
(
c1
,
"c1"
,
"c1k1"
,
""
,
""
)
if
got
,
want
:=
fmt
.
Sprint
(
c1
),
`context.Background.WithValue(1, "c1k1")`
;
got
!=
want
{
t
.
Errorf
(
"c.String() = %q want %q"
,
got
,
want
)
}
c2
:=
WithValue
(
c1
,
k2
,
"c2k2"
)
check
(
c2
,
"c2"
,
"c1k1"
,
"c2k2"
,
""
)
c3
:=
WithValue
(
c2
,
k3
,
"c3k3"
)
check
(
c3
,
"c2"
,
"c1k1"
,
"c2k2"
,
"c3k3"
)
c4
:=
WithValue
(
c3
,
k1
,
nil
)
check
(
c4
,
"c4"
,
""
,
"c2k2"
,
"c3k3"
)
o0
:=
otherContext
{
Background
()}
check
(
o0
,
"o0"
,
""
,
""
,
""
)
o1
:=
otherContext
{
WithValue
(
Background
(),
k1
,
"c1k1"
)}
check
(
o1
,
"o1"
,
"c1k1"
,
""
,
""
)
o2
:=
WithValue
(
o1
,
k2
,
"o2k2"
)
check
(
o2
,
"o2"
,
"c1k1"
,
"o2k2"
,
""
)
o3
:=
otherContext
{
c4
}
check
(
o3
,
"o3"
,
""
,
"c2k2"
,
"c3k3"
)
o4
:=
WithValue
(
o3
,
k3
,
nil
)
check
(
o4
,
"o4"
,
""
,
"c2k2"
,
""
)
}
func
TestAllocs
(
t
*
testing
.
T
)
{
bg
:=
Background
()
for
_
,
test
:=
range
[]
struct
{
desc
string
f
func
()
limit
float64
gccgoLimit
float64
}{
{
desc
:
"Background()"
,
f
:
func
()
{
Background
()
},
limit
:
0
,
gccgoLimit
:
0
,
},
{
desc
:
fmt
.
Sprintf
(
"WithValue(bg, %v, nil)"
,
k1
),
f
:
func
()
{
c
:=
WithValue
(
bg
,
k1
,
nil
)
c
.
Value
(
k1
)
},
limit
:
3
,
gccgoLimit
:
3
,
},
{
desc
:
"WithTimeout(bg, 15*time.Millisecond)"
,
f
:
func
()
{
c
,
_
:=
WithTimeout
(
bg
,
15
*
time
.
Millisecond
)
<-
c
.
Done
()
},
limit
:
8
,
gccgoLimit
:
15
,
},
{
desc
:
"WithCancel(bg)"
,
f
:
func
()
{
c
,
cancel
:=
WithCancel
(
bg
)
cancel
()
<-
c
.
Done
()
},
limit
:
5
,
gccgoLimit
:
8
,
},
{
desc
:
"WithTimeout(bg, 100*time.Millisecond)"
,
f
:
func
()
{
c
,
cancel
:=
WithTimeout
(
bg
,
100
*
time
.
Millisecond
)
cancel
()
<-
c
.
Done
()
},
limit
:
8
,
gccgoLimit
:
25
,
},
}
{
limit
:=
test
.
limit
if
runtime
.
Compiler
==
"gccgo"
{
// gccgo does not yet do escape analysis.
// TOOD(iant): Remove this when gccgo does do escape analysis.
limit
=
test
.
gccgoLimit
}
if
n
:=
testing
.
AllocsPerRun
(
100
,
test
.
f
);
n
>
limit
{
t
.
Errorf
(
"%s allocs = %f want %d"
,
test
.
desc
,
n
,
int
(
limit
))
}
}
}
func
TestSimultaneousCancels
(
t
*
testing
.
T
)
{
root
,
cancel
:=
WithCancel
(
Background
())
m
:=
map
[
Context
]
CancelFunc
{
root
:
cancel
}
q
:=
[]
Context
{
root
}
// Create a tree of contexts.
for
len
(
q
)
!=
0
&&
len
(
m
)
<
100
{
parent
:=
q
[
0
]
q
=
q
[
1
:
]
for
i
:=
0
;
i
<
4
;
i
++
{
ctx
,
cancel
:=
WithCancel
(
parent
)
m
[
ctx
]
=
cancel
q
=
append
(
q
,
ctx
)
}
}
// Start all the cancels in a random order.
var
wg
sync
.
WaitGroup
wg
.
Add
(
len
(
m
))
for
_
,
cancel
:=
range
m
{
go
func
(
cancel
CancelFunc
)
{
cancel
()
wg
.
Done
()
}(
cancel
)
}
// Wait on all the contexts in a random order.
for
ctx
:=
range
m
{
select
{
case
<-
ctx
.
Done
()
:
case
<-
time
.
After
(
1
*
time
.
Second
)
:
buf
:=
make
([]
byte
,
10
<<
10
)
n
:=
runtime
.
Stack
(
buf
,
true
)
t
.
Fatalf
(
"timed out waiting for <-ctx.Done(); stacks:
\n
%s"
,
buf
[
:
n
])
}
}
// Wait for all the cancel functions to return.
done
:=
make
(
chan
struct
{})
go
func
()
{
wg
.
Wait
()
close
(
done
)
}()
select
{
case
<-
done
:
case
<-
time
.
After
(
1
*
time
.
Second
)
:
buf
:=
make
([]
byte
,
10
<<
10
)
n
:=
runtime
.
Stack
(
buf
,
true
)
t
.
Fatalf
(
"timed out waiting for cancel functions; stacks:
\n
%s"
,
buf
[
:
n
])
}
}
func
TestInterlockedCancels
(
t
*
testing
.
T
)
{
parent
,
cancelParent
:=
WithCancel
(
Background
())
child
,
cancelChild
:=
WithCancel
(
parent
)
go
func
()
{
parent
.
Done
()
cancelChild
()
}()
cancelParent
()
select
{
case
<-
child
.
Done
()
:
case
<-
time
.
After
(
1
*
time
.
Second
)
:
buf
:=
make
([]
byte
,
10
<<
10
)
n
:=
runtime
.
Stack
(
buf
,
true
)
t
.
Fatalf
(
"timed out waiting for child.Done(); stacks:
\n
%s"
,
buf
[
:
n
])
}
}
func
TestLayersCancel
(
t
*
testing
.
T
)
{
testLayers
(
t
,
time
.
Now
()
.
UnixNano
(),
false
)
}
func
TestLayersTimeout
(
t
*
testing
.
T
)
{
testLayers
(
t
,
time
.
Now
()
.
UnixNano
(),
true
)
}
func
testLayers
(
t
*
testing
.
T
,
seed
int64
,
testTimeout
bool
)
{
rand
.
Seed
(
seed
)
errorf
:=
func
(
format
string
,
a
...
interface
{})
{
t
.
Errorf
(
fmt
.
Sprintf
(
"seed=%d: %s"
,
seed
,
format
),
a
...
)
}
const
(
timeout
=
200
*
time
.
Millisecond
minLayers
=
30
)
type
value
int
var
(
vals
[]
*
value
cancels
[]
CancelFunc
numTimers
int
ctx
=
Background
()
)
for
i
:=
0
;
i
<
minLayers
||
numTimers
==
0
||
len
(
cancels
)
==
0
||
len
(
vals
)
==
0
;
i
++
{
switch
rand
.
Intn
(
3
)
{
case
0
:
v
:=
new
(
value
)
ctx
=
WithValue
(
ctx
,
v
,
v
)
vals
=
append
(
vals
,
v
)
case
1
:
var
cancel
CancelFunc
ctx
,
cancel
=
WithCancel
(
ctx
)
cancels
=
append
(
cancels
,
cancel
)
case
2
:
var
cancel
CancelFunc
ctx
,
cancel
=
WithTimeout
(
ctx
,
timeout
)
cancels
=
append
(
cancels
,
cancel
)
numTimers
++
}
}
checkValues
:=
func
(
when
string
)
{
for
_
,
key
:=
range
vals
{
if
val
:=
ctx
.
Value
(
key
)
.
(
*
value
);
key
!=
val
{
errorf
(
"%s: ctx.Value(%p) = %p want %p"
,
when
,
key
,
val
,
key
)
}
}
}
select
{
case
<-
ctx
.
Done
()
:
errorf
(
"ctx should not be canceled yet"
)
default
:
}
if
s
,
prefix
:=
fmt
.
Sprint
(
ctx
),
"context.Background."
;
!
strings
.
HasPrefix
(
s
,
prefix
)
{
t
.
Errorf
(
"ctx.String() = %q want prefix %q"
,
s
,
prefix
)
}
t
.
Log
(
ctx
)
checkValues
(
"before cancel"
)
if
testTimeout
{
select
{
case
<-
ctx
.
Done
()
:
case
<-
time
.
After
(
timeout
+
100
*
time
.
Millisecond
)
:
errorf
(
"ctx should have timed out"
)
}
checkValues
(
"after timeout"
)
}
else
{
cancel
:=
cancels
[
rand
.
Intn
(
len
(
cancels
))]
cancel
()
select
{
case
<-
ctx
.
Done
()
:
default
:
errorf
(
"ctx should be canceled"
)
}
checkValues
(
"after cancel"
)
}
}
func
TestCancelRemoves
(
t
*
testing
.
T
)
{
checkChildren
:=
func
(
when
string
,
ctx
Context
,
want
int
)
{
if
got
:=
len
(
ctx
.
(
*
cancelCtx
)
.
children
);
got
!=
want
{
t
.
Errorf
(
"%s: context has %d children, want %d"
,
when
,
got
,
want
)
}
}
ctx
,
_
:=
WithCancel
(
Background
())
checkChildren
(
"after creation"
,
ctx
,
0
)
_
,
cancel
:=
WithCancel
(
ctx
)
checkChildren
(
"with WithCancel child "
,
ctx
,
1
)
cancel
()
checkChildren
(
"after cancelling WithCancel child"
,
ctx
,
0
)
ctx
,
_
=
WithCancel
(
Background
())
checkChildren
(
"after creation"
,
ctx
,
0
)
_
,
cancel
=
WithTimeout
(
ctx
,
60
*
time
.
Minute
)
checkChildren
(
"with WithTimeout child "
,
ctx
,
1
)
cancel
()
checkChildren
(
"after cancelling WithTimeout child"
,
ctx
,
0
)
}
vendor/QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUct/context/ctxhttp/cancelreq.go
0 → 100644
View file @
0c73722a
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.5
package
ctxhttp
import
"net/http"
func
canceler
(
client
*
http
.
Client
,
req
*
http
.
Request
)
func
()
{
ch
:=
make
(
chan
struct
{})
req
.
Cancel
=
ch
return
func
()
{
close
(
ch
)
}
}
vendor/QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUct/context/ctxhttp/cancelreq_go14.go
0 → 100644
View file @
0c73722a
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.5
package
ctxhttp
import
"net/http"
type
requestCanceler
interface
{
CancelRequest
(
*
http
.
Request
)
}
func
canceler
(
client
*
http
.
Client
,
req
*
http
.
Request
)
func
()
{
rc
,
ok
:=
client
.
Transport
.
(
requestCanceler
)
if
!
ok
{
return
func
()
{}
}
return
func
()
{
rc
.
CancelRequest
(
req
)
}
}
vendor/QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUct/context/ctxhttp/ctxhttp.go
0 → 100644
View file @
0c73722a
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
package
ctxhttp
import
(
"io"
"net/http"
"net/url"
"strings"
"QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUct/context"
)
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
// If the client is nil, http.DefaultClient is used.
// If the context is canceled or times out, ctx.Err() will be returned.
func
Do
(
ctx
context
.
Context
,
client
*
http
.
Client
,
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
if
client
==
nil
{
client
=
http
.
DefaultClient
}
// Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go.
cancel
:=
canceler
(
client
,
req
)
type
responseAndError
struct
{
resp
*
http
.
Response
err
error
}
result
:=
make
(
chan
responseAndError
,
1
)
go
func
()
{
resp
,
err
:=
client
.
Do
(
req
)
result
<-
responseAndError
{
resp
,
err
}
}()
select
{
case
<-
ctx
.
Done
()
:
cancel
()
return
nil
,
ctx
.
Err
()
case
r
:=
<-
result
:
return
r
.
resp
,
r
.
err
}
}
// Get issues a GET request via the Do function.
func
Get
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"GET"
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
Do
(
ctx
,
client
,
req
)
}
// Head issues a HEAD request via the Do function.
func
Head
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"HEAD"
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
Do
(
ctx
,
client
,
req
)
}
// Post issues a POST request via the Do function.
func
Post
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
bodyType
string
,
body
io
.
Reader
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"POST"
,
url
,
body
)
if
err
!=
nil
{
return
nil
,
err
}
req
.
Header
.
Set
(
"Content-Type"
,
bodyType
)
return
Do
(
ctx
,
client
,
req
)
}
// PostForm issues a POST request via the Do function.
func
PostForm
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
data
url
.
Values
)
(
*
http
.
Response
,
error
)
{
return
Post
(
ctx
,
client
,
url
,
"application/x-www-form-urlencoded"
,
strings
.
NewReader
(
data
.
Encode
()))
}
vendor/QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUct/context/ctxhttp/ctxhttp_test.go
0 → 100644
View file @
0c73722a
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
ctxhttp
import
(
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"time"
"QmacZi9WygGK7Me8mH53pypyscHzU386aUZXpr28GZgUct/context"
)
const
(
requestDuration
=
100
*
time
.
Millisecond
requestBody
=
"ok"
)
func
TestNoTimeout
(
t
*
testing
.
T
)
{
ctx
:=
context
.
Background
()
resp
,
err
:=
doRequest
(
ctx
)
if
resp
==
nil
||
err
!=
nil
{
t
.
Fatalf
(
"error received from client: %v %v"
,
err
,
resp
)
}
}
func
TestCancel
(
t
*
testing
.
T
)
{
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
go
func
()
{
time
.
Sleep
(
requestDuration
/
2
)
cancel
()
}()
resp
,
err
:=
doRequest
(
ctx
)
if
resp
!=
nil
||
err
==
nil
{
t
.
Fatalf
(
"expected error, didn't get one. resp: %v"
,
resp
)
}
if
err
!=
ctx
.
Err
()
{
t
.
Fatalf
(
"expected error from context but got: %v"
,
err
)
}
}
func
TestCancelAfterRequest
(
t
*
testing
.
T
)
{
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
resp
,
err
:=
doRequest
(
ctx
)
// Cancel before reading the body.
// Request.Body should still be readable after the context is canceled.
cancel
()
b
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
||
string
(
b
)
!=
requestBody
{
t
.
Fatalf
(
"could not read body: %q %v"
,
b
,
err
)
}
}
func
doRequest
(
ctx
context
.
Context
)
(
*
http
.
Response
,
error
)
{
var
okHandler
=
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
time
.
Sleep
(
requestDuration
)
w
.
Write
([]
byte
(
requestBody
))
})
serv
:=
httptest
.
NewServer
(
okHandler
)
defer
serv
.
Close
()
return
Get
(
ctx
,
nil
,
serv
.
URL
)
}
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment