Skip to content
Snippets Groups Projects
Unverified Commit fa554528 authored by Oliver's avatar Oliver Committed by GitHub
Browse files

Merge pull request #133 from oliver006/oh_update_dep_and_run_dep_prune

update Gopkg.toml, use new version of dep, update vendored files
parents a0d9e4c7 ddda4273
No related branches found
No related tags found
No related merge requests found
Showing
with 82 additions and 4333 deletions
Loading
@@ -15,9 +15,12 @@
Loading
@@ -15,9 +15,12 @@
   
[[projects]] [[projects]]
name = "github.com/garyburd/redigo" name = "github.com/garyburd/redigo"
packages = ["internal","redis"] packages = [
revision = "47dc60e71eed504e3ef8e77ee3c6fe720f3be57f" "internal",
version = "v1.3.0" "redis"
]
revision = "d1ed5c67e5794de818ea85e6b522fda02623a484"
version = "v1.4.0"
   
[[projects]] [[projects]]
branch = "master" branch = "master"
Loading
@@ -39,7 +42,10 @@
Loading
@@ -39,7 +42,10 @@
   
[[projects]] [[projects]]
name = "github.com/prometheus/client_golang" name = "github.com/prometheus/client_golang"
packages = ["prometheus","prometheus/promhttp"] packages = [
"prometheus",
"prometheus/promhttp"
]
revision = "c5b7fccd204277076155f10851dad72b76a49317" revision = "c5b7fccd204277076155f10851dad72b76a49317"
version = "v0.8.0" version = "v0.8.0"
   
Loading
@@ -52,13 +58,20 @@
Loading
@@ -52,13 +58,20 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "github.com/prometheus/common" name = "github.com/prometheus/common"
packages = ["expfmt","internal/bitbucket.org/ww/goautoneg","model"] packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model"
]
revision = "e3fb1a1acd7605367a2b378bc2e2f893c05174b7" revision = "e3fb1a1acd7605367a2b378bc2e2f893c05174b7"
   
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "github.com/prometheus/procfs" name = "github.com/prometheus/procfs"
packages = [".","xfs"] packages = [
".",
"xfs"
]
revision = "a6e9df898b1336106c743392c48ee0b71f5c4efa" revision = "a6e9df898b1336106c743392c48ee0b71f5c4efa"
   
[[projects]] [[projects]]
Loading
@@ -70,8 +83,8 @@
Loading
@@ -70,8 +83,8 @@
[[projects]] [[projects]]
name = "github.com/sirupsen/logrus" name = "github.com/sirupsen/logrus"
packages = ["."] packages = ["."]
revision = "f006c2ac4710855cf0f916dd6b77acf6b048dc6e" revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba"
version = "v1.0.3" version = "v1.0.4"
   
[[projects]] [[projects]]
branch = "master" branch = "master"
Loading
@@ -82,12 +95,15 @@
Loading
@@ -82,12 +95,15 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "golang.org/x/sys" name = "golang.org/x/sys"
packages = ["unix","windows"] packages = [
"unix",
"windows"
]
revision = "665f6529cca930e27b831a0d1dafffbe1c172924" revision = "665f6529cca930e27b831a0d1dafffbe1c172924"
   
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "2e013c0d4c7fe5e64f3b7e69e8aaabff0bb64b43d5acb6e2fddc383e2104dec3" inputs-digest = "64bcf02f7a4bee555d0391b42f0d1c2e7f614ab7bd691a737bb3f81a99a9c2b0"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1
[prune]
# Gopkg.toml example non-go = true
# unused-packages = true
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md go-tests = true
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
   
[[constraint]] [[constraint]]
name = "github.com/cloudfoundry-community/go-cfenv" name = "github.com/cloudfoundry-community/go-cfenv"
Loading
@@ -27,7 +9,7 @@
Loading
@@ -27,7 +9,7 @@
   
[[constraint]] [[constraint]]
name = "github.com/garyburd/redigo" name = "github.com/garyburd/redigo"
version = "1.3.0" version = "1.4.0"
   
[[constraint]] [[constraint]]
name = "github.com/prometheus/client_golang" name = "github.com/prometheus/client_golang"
Loading
@@ -39,4 +21,4 @@
Loading
@@ -39,4 +21,4 @@
   
[[constraint]] [[constraint]]
name = "github.com/sirupsen/logrus" name = "github.com/sirupsen/logrus"
version = "1.0.3" version = "1.0.4"
*.test
*.prof
# Perks for Go (golang.org)
Perks contains the Go package quantile that computes approximate quantiles over
an unbounded data stream within low memory and CPU bounds.
For more information and examples, see:
http://godoc.org/github.com/bmizerany/perks
A very special thank you and shout out to Graham Cormode (Rutgers University),
Flip Korn (AT&T Labs–Research), S. Muthukrishnan (Rutgers University), and
Divesh Srivastava (AT&T Labs–Research) for their research and publication of
[Effective Computation of Biased Quantiles over Data Streams](http://www.cs.rutgers.edu/~muthu/bquant.pdf)
Thank you, also:
* Armon Dadgar (@armon)
* Andrew Gerrand (@nf)
* Brad Fitzpatrick (@bradfitz)
* Keith Rarick (@kr)
FAQ:
Q: Why not move the quantile package into the project root?
A: I want to add more packages to perks later.
Copyright (C) 2013 Blake Mizerany
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package quantile
import (
"testing"
)
func BenchmarkInsertTargeted(b *testing.B) {
b.ReportAllocs()
s := NewTargeted(Targets)
b.ResetTimer()
for i := float64(0); i < float64(b.N); i++ {
s.Insert(i)
}
}
func BenchmarkInsertTargetedSmallEpsilon(b *testing.B) {
s := NewTargeted(TargetsSmallEpsilon)
b.ResetTimer()
for i := float64(0); i < float64(b.N); i++ {
s.Insert(i)
}
}
func BenchmarkInsertBiased(b *testing.B) {
s := NewLowBiased(0.01)
b.ResetTimer()
for i := float64(0); i < float64(b.N); i++ {
s.Insert(i)
}
}
func BenchmarkInsertBiasedSmallEpsilon(b *testing.B) {
s := NewLowBiased(0.0001)
b.ResetTimer()
for i := float64(0); i < float64(b.N); i++ {
s.Insert(i)
}
}
func BenchmarkQuery(b *testing.B) {
s := NewTargeted(Targets)
for i := float64(0); i < 1e6; i++ {
s.Insert(i)
}
b.ResetTimer()
n := float64(b.N)
for i := float64(0); i < n; i++ {
s.Query(i / n)
}
}
func BenchmarkQuerySmallEpsilon(b *testing.B) {
s := NewTargeted(TargetsSmallEpsilon)
for i := float64(0); i < 1e6; i++ {
s.Insert(i)
}
b.ResetTimer()
n := float64(b.N)
for i := float64(0); i < n; i++ {
s.Query(i / n)
}
}
// +build go1.1
package quantile_test
import (
"bufio"
"fmt"
"log"
"os"
"strconv"
"time"
"github.com/beorn7/perks/quantile"
)
func Example_simple() {
ch := make(chan float64)
go sendFloats(ch)
// Compute the 50th, 90th, and 99th percentile.
q := quantile.NewTargeted(map[float64]float64{
0.50: 0.005,
0.90: 0.001,
0.99: 0.0001,
})
for v := range ch {
q.Insert(v)
}
fmt.Println("perc50:", q.Query(0.50))
fmt.Println("perc90:", q.Query(0.90))
fmt.Println("perc99:", q.Query(0.99))
fmt.Println("count:", q.Count())
// Output:
// perc50: 5
// perc90: 16
// perc99: 223
// count: 2388
}
func Example_mergeMultipleStreams() {
// Scenario:
// We have multiple database shards. On each shard, there is a process
// collecting query response times from the database logs and inserting
// them into a Stream (created via NewTargeted(0.90)), much like the
// Simple example. These processes expose a network interface for us to
// ask them to serialize and send us the results of their
// Stream.Samples so we may Merge and Query them.
//
// NOTES:
// * These sample sets are small, allowing us to get them
// across the network much faster than sending the entire list of data
// points.
//
// * For this to work correctly, we must supply the same quantiles
// a priori the process collecting the samples supplied to NewTargeted,
// even if we do not plan to query them all here.
ch := make(chan quantile.Samples)
getDBQuerySamples(ch)
q := quantile.NewTargeted(map[float64]float64{0.90: 0.001})
for samples := range ch {
q.Merge(samples)
}
fmt.Println("perc90:", q.Query(0.90))
}
func Example_window() {
// Scenario: We want the 90th, 95th, and 99th percentiles for each
// minute.
ch := make(chan float64)
go sendStreamValues(ch)
tick := time.NewTicker(1 * time.Minute)
q := quantile.NewTargeted(map[float64]float64{
0.90: 0.001,
0.95: 0.0005,
0.99: 0.0001,
})
for {
select {
case t := <-tick.C:
flushToDB(t, q.Samples())
q.Reset()
case v := <-ch:
q.Insert(v)
}
}
}
func sendStreamValues(ch chan float64) {
// Use your imagination
}
func flushToDB(t time.Time, samples quantile.Samples) {
// Use your imagination
}
// This is a stub for the above example. In reality this would hit the remote
// servers via http or something like it.
func getDBQuerySamples(ch chan quantile.Samples) {}
func sendFloats(ch chan<- float64) {
f, err := os.Open("exampledata.txt")
if err != nil {
log.Fatal(err)
}
sc := bufio.NewScanner(f)
for sc.Scan() {
b := sc.Bytes()
v, err := strconv.ParseFloat(string(b), 64)
if err != nil {
log.Fatal(err)
}
ch <- v
}
if sc.Err() != nil {
log.Fatal(sc.Err())
}
close(ch)
}
8
5
26
12
5
235
13
6
28
30
3
3
3
3
5
2
33
7
2
4
7
12
14
5
8
3
10
4
5
3
6
6
209
20
3
10
14
3
4
6
8
5
11
7
3
2
3
3
212
5
222
4
10
10
5
6
3
8
3
10
254
220
2
3
5
24
5
4
222
7
3
3
223
8
15
12
14
14
3
2
2
3
13
3
11
4
4
6
5
7
13
5
3
5
2
5
3
5
2
7
15
17
14
3
6
6
3
17
5
4
7
6
4
4
8
6
8
3
9
3
6
3
4
5
3
3
660
4
6
10
3
6
3
2
5
13
2
4
4
10
4
8
4
3
7
9
9
3
10
37
3
13
4
12
3
6
10
8
5
21
2
3
8
3
2
3
3
4
12
2
4
8
8
4
3
2
20
1
6
32
2
11
6
18
3
8
11
3
212
3
4
2
6
7
12
11
3
2
16
10
6
4
6
3
2
7
3
2
2
2
2
5
6
4
3
10
3
4
6
5
3
4
4
5
6
4
3
4
4
5
7
5
5
3
2
7
2
4
12
4
5
6
2
4
4
8
4
15
13
7
16
5
3
23
5
5
7
3
2
9
8
7
5
8
11
4
10
76
4
47
4
3
2
7
4
2
3
37
10
4
2
20
5
4
4
10
10
4
3
7
23
240
7
13
5
5
3
3
2
5
4
2
8
7
19
2
23
8
7
2
5
3
8
3
8
13
5
5
5
2
3
23
4
9
8
4
3
3
5
220
2
3
4
6
14
3
53
6
2
5
18
6
3
219
6
5
2
5
3
6
5
15
4
3
17
3
2
4
7
2
3
3
4
4
3
2
664
6
3
23
5
5
16
5
8
2
4
2
24
12
3
2
3
5
8
3
5
4
3
14
3
5
8
2
3
7
9
4
2
3
6
8
4
3
4
6
5
3
3
6
3
19
4
4
6
3
6
3
5
22
5
4
4
3
8
11
4
9
7
6
13
4
4
4
6
17
9
3
3
3
4
3
221
5
11
3
4
2
12
6
3
5
7
5
7
4
9
7
14
37
19
217
16
3
5
2
2
7
19
7
6
7
4
24
5
11
4
7
7
9
13
3
4
3
6
28
4
4
5
5
2
5
6
4
4
6
10
5
4
3
2
3
3
6
5
5
4
3
2
3
7
4
6
18
16
8
16
4
5
8
6
9
13
1545
6
215
6
5
6
3
45
31
5
2
2
4
3
3
2
5
4
3
5
7
7
4
5
8
5
4
749
2
31
9
11
2
11
5
4
4
7
9
11
4
5
4
7
3
4
6
2
15
3
4
3
4
3
5
2
13
5
5
3
3
23
4
4
5
7
4
13
2
4
3
4
2
6
2
7
3
5
5
3
29
5
4
4
3
10
2
3
79
16
6
6
7
7
3
5
5
7
4
3
7
9
5
6
5
9
6
3
6
4
17
2
10
9
3
6
2
3
21
22
5
11
4
2
17
2
224
2
14
3
4
4
2
4
4
4
4
5
3
4
4
10
2
6
3
3
5
7
2
7
5
6
3
218
2
2
5
2
6
3
5
222
14
6
33
3
2
5
3
3
3
9
5
3
3
2
7
4
3
4
3
5
6
5
26
4
13
9
7
3
221
3
3
4
4
4
4
2
18
5
3
7
9
6
8
3
10
3
11
9
5
4
17
5
5
6
6
3
2
4
12
17
6
7
218
4
2
4
10
3
5
15
3
9
4
3
3
6
29
3
3
4
5
5
3
8
5
6
6
7
5
3
5
3
29
2
31
5
15
24
16
5
207
4
3
3
2
15
4
4
13
5
5
4
6
10
2
7
8
4
6
20
5
3
4
3
12
12
5
17
7
3
3
3
6
10
3
5
25
80
4
9
3
2
11
3
3
2
3
8
7
5
5
19
5
3
3
12
11
2
6
5
5
5
3
3
3
4
209
14
3
2
5
19
4
4
3
4
14
5
6
4
13
9
7
4
7
10
2
9
5
7
2
8
4
6
5
5
222
8
7
12
5
216
3
4
4
6
3
14
8
7
13
4
3
3
3
3
17
5
4
3
33
6
6
33
7
5
3
8
7
5
2
9
4
2
233
24
7
4
8
10
3
4
15
2
16
3
3
13
12
7
5
4
207
4
2
4
27
15
2
5
2
25
6
5
5
6
13
6
18
6
4
12
225
10
7
5
2
2
11
4
14
21
8
10
3
5
4
232
2
5
5
3
7
17
11
6
6
23
4
6
3
5
4
2
17
3
6
5
8
3
2
2
14
9
4
4
2
5
5
3
7
6
12
6
10
3
6
2
2
19
5
4
4
9
2
4
13
3
5
6
3
6
5
4
9
6
3
5
7
3
6
6
4
3
10
6
3
221
3
5
3
6
4
8
5
3
6
4
4
2
54
5
6
11
3
3
4
4
4
3
7
3
11
11
7
10
6
13
223
213
15
231
7
3
7
228
2
3
4
4
5
6
7
4
13
3
4
5
3
6
4
6
7
2
4
3
4
3
3
6
3
7
3
5
18
5
6
8
10
3
3
3
2
4
2
4
4
5
6
6
4
10
13
3
12
5
12
16
8
4
19
11
2
4
5
6
8
5
6
4
18
10
4
2
216
6
6
6
2
4
12
8
3
11
5
6
14
5
3
13
4
5
4
5
3
28
6
3
7
219
3
9
7
3
10
6
3
4
19
5
7
11
6
15
19
4
13
11
3
7
5
10
2
8
11
2
6
4
6
24
6
3
3
3
3
6
18
4
11
4
2
5
10
8
3
9
5
3
4
5
6
2
5
7
4
4
14
6
4
4
5
5
7
2
4
3
7
3
3
6
4
5
4
4
4
3
3
3
3
8
14
2
3
5
3
2
4
5
3
7
3
3
18
3
4
4
5
7
3
3
3
13
5
4
8
211
5
5
3
5
2
5
4
2
655
6
3
5
11
2
5
3
12
9
15
11
5
12
217
2
6
17
3
3
207
5
5
4
5
9
3
2
8
5
4
3
2
5
12
4
14
5
4
2
13
5
8
4
225
4
3
4
5
4
3
3
6
23
9
2
6
7
233
4
4
6
18
3
4
6
3
4
4
2
3
7
4
13
227
4
3
5
4
2
12
9
17
3
7
14
6
4
5
21
4
8
9
2
9
25
16
3
6
4
7
8
5
2
3
5
4
3
3
5
3
3
3
2
3
19
2
4
3
4
2
3
4
4
2
4
3
3
3
2
6
3
17
5
6
4
3
13
5
3
3
3
4
9
4
2
14
12
4
5
24
4
3
37
12
11
21
3
4
3
13
4
2
3
15
4
11
4
4
3
8
3
4
4
12
8
5
3
3
4
2
220
3
5
223
3
3
3
10
3
15
4
241
9
7
3
6
6
23
4
13
7
3
4
7
4
9
3
3
4
10
5
5
1
5
24
2
4
5
5
6
14
3
8
2
3
5
13
13
3
5
2
3
15
3
4
2
10
4
4
4
5
5
3
5
3
4
7
4
27
3
6
4
15
3
5
6
6
5
4
8
3
9
2
6
3
4
3
7
4
18
3
11
3
3
8
9
7
24
3
219
7
10
4
5
9
12
2
5
4
4
4
3
3
19
5
8
16
8
6
22
3
23
3
242
9
4
3
3
5
7
3
3
5
8
3
7
5
14
8
10
3
4
3
7
4
6
7
4
10
4
3
11
3
7
10
3
13
6
8
12
10
5
7
9
3
4
7
7
10
8
30
9
19
4
3
19
15
4
13
3
215
223
4
7
4
8
17
16
3
7
6
5
5
4
12
3
7
4
4
13
4
5
2
5
6
5
6
6
7
10
18
23
9
3
3
6
5
2
4
2
7
3
3
2
5
5
14
10
224
6
3
4
3
7
5
9
3
6
4
2
5
11
4
3
3
2
8
4
7
4
10
7
3
3
18
18
17
3
3
3
4
5
3
3
4
12
7
3
11
13
5
4
7
13
5
4
11
3
12
3
6
4
4
21
4
6
9
5
3
10
8
4
6
4
4
6
5
4
8
6
4
6
4
4
5
9
6
3
4
2
9
3
18
2
4
3
13
3
6
6
8
7
9
3
2
16
3
4
6
3
2
33
22
14
4
9
12
4
5
6
3
23
9
4
3
5
5
3
4
5
3
5
3
10
4
5
5
8
4
4
6
8
5
4
3
4
6
3
3
3
5
9
12
6
5
9
3
5
3
2
2
2
18
3
2
21
2
5
4
6
4
5
10
3
9
3
2
10
7
3
6
6
4
4
8
12
7
3
7
3
3
9
3
4
5
4
4
5
5
10
15
4
4
14
6
227
3
14
5
216
22
5
4
2
2
6
3
4
2
9
9
4
3
28
13
11
4
5
3
3
2
3
3
5
3
4
3
5
23
26
3
4
5
6
4
6
3
5
5
3
4
3
2
2
2
7
14
3
6
7
17
2
2
15
14
16
4
6
7
13
6
4
5
6
16
3
3
28
3
6
15
3
9
2
4
6
3
3
22
4
12
6
7
2
5
4
10
3
16
6
9
2
5
12
7
5
5
5
5
2
11
9
17
4
3
11
7
3
5
15
4
3
4
211
8
7
5
4
7
6
7
6
3
6
5
6
5
3
4
4
26
4
6
10
4
4
3
2
3
3
4
5
9
3
9
4
4
5
5
8
2
4
2
3
8
4
11
19
5
8
6
3
5
6
12
3
2
4
16
12
3
4
4
8
6
5
6
6
219
8
222
6
16
3
13
19
5
4
3
11
6
10
4
7
7
12
5
3
3
5
6
10
3
8
2
5
4
7
2
4
4
2
12
9
6
4
2
40
2
4
10
4
223
4
2
20
6
7
24
5
4
5
2
20
16
6
5
13
2
3
3
19
3
2
4
5
6
7
11
12
5
6
7
7
3
5
3
5
3
14
3
4
4
2
11
1
7
3
9
6
11
12
5
8
6
221
4
2
12
4
3
15
4
5
226
7
218
7
5
4
5
18
4
5
9
4
4
2
9
18
18
9
5
6
6
3
3
7
3
5
4
4
4
12
3
6
31
5
4
7
3
6
5
6
5
11
2
2
11
11
6
7
5
8
7
10
5
23
7
4
3
5
34
2
5
23
7
3
6
8
4
4
4
2
5
3
8
5
4
8
25
2
3
17
8
3
4
8
7
3
15
6
5
7
21
9
5
6
6
5
3
2
3
10
3
6
3
14
7
4
4
8
7
8
2
6
12
4
213
6
5
21
8
2
5
23
3
11
2
3
6
25
2
3
6
7
6
6
4
4
6
3
17
9
7
6
4
3
10
7
2
3
3
3
11
8
3
7
6
4
14
36
3
4
3
3
22
13
21
4
2
7
4
4
17
15
3
7
11
2
4
7
6
209
6
3
2
2
24
4
9
4
3
3
3
29
2
2
4
3
3
5
4
6
3
3
2
4
package quantile
import (
"math"
"math/rand"
"sort"
"testing"
)
var (
Targets = map[float64]float64{
0.01: 0.001,
0.10: 0.01,
0.50: 0.05,
0.90: 0.01,
0.99: 0.001,
}
TargetsSmallEpsilon = map[float64]float64{
0.01: 0.0001,
0.10: 0.001,
0.50: 0.005,
0.90: 0.001,
0.99: 0.0001,
}
LowQuantiles = []float64{0.01, 0.1, 0.5}
HighQuantiles = []float64{0.99, 0.9, 0.5}
)
const RelativeEpsilon = 0.01
func verifyPercsWithAbsoluteEpsilon(t *testing.T, a []float64, s *Stream) {
sort.Float64s(a)
for quantile, epsilon := range Targets {
n := float64(len(a))
k := int(quantile * n)
if k < 1 {
k = 1
}
lower := int((quantile - epsilon) * n)
if lower < 1 {
lower = 1
}
upper := int(math.Ceil((quantile + epsilon) * n))
if upper > len(a) {
upper = len(a)
}
w, min, max := a[k-1], a[lower-1], a[upper-1]
if g := s.Query(quantile); g < min || g > max {
t.Errorf("q=%f: want %v [%f,%f], got %v", quantile, w, min, max, g)
}
}
}
func verifyLowPercsWithRelativeEpsilon(t *testing.T, a []float64, s *Stream) {
sort.Float64s(a)
for _, qu := range LowQuantiles {
n := float64(len(a))
k := int(qu * n)
lowerRank := int((1 - RelativeEpsilon) * qu * n)
upperRank := int(math.Ceil((1 + RelativeEpsilon) * qu * n))
w, min, max := a[k-1], a[lowerRank-1], a[upperRank-1]
if g := s.Query(qu); g < min || g > max {
t.Errorf("q=%f: want %v [%f,%f], got %v", qu, w, min, max, g)
}
}
}
func verifyHighPercsWithRelativeEpsilon(t *testing.T, a []float64, s *Stream) {
sort.Float64s(a)
for _, qu := range HighQuantiles {
n := float64(len(a))
k := int(qu * n)
lowerRank := int((1 - (1+RelativeEpsilon)*(1-qu)) * n)
upperRank := int(math.Ceil((1 - (1-RelativeEpsilon)*(1-qu)) * n))
w, min, max := a[k-1], a[lowerRank-1], a[upperRank-1]
if g := s.Query(qu); g < min || g > max {
t.Errorf("q=%f: want %v [%f,%f], got %v", qu, w, min, max, g)
}
}
}
func populateStream(s *Stream) []float64 {
a := make([]float64, 0, 1e5+100)
for i := 0; i < cap(a); i++ {
v := rand.NormFloat64()
// Add 5% asymmetric outliers.
if i%20 == 0 {
v = v*v + 1
}
s.Insert(v)
a = append(a, v)
}
return a
}
func TestTargetedQuery(t *testing.T) {
rand.Seed(42)
s := NewTargeted(Targets)
a := populateStream(s)
verifyPercsWithAbsoluteEpsilon(t, a, s)
}
func TestTargetedQuerySmallSampleSize(t *testing.T) {
rand.Seed(42)
s := NewTargeted(TargetsSmallEpsilon)
a := []float64{1, 2, 3, 4, 5}
for _, v := range a {
s.Insert(v)
}
verifyPercsWithAbsoluteEpsilon(t, a, s)
// If not yet flushed, results should be precise:
if !s.flushed() {
for φ, want := range map[float64]float64{
0.01: 1,
0.10: 1,
0.50: 3,
0.90: 5,
0.99: 5,
} {
if got := s.Query(φ); got != want {
t.Errorf("want %f for φ=%f, got %f", want, φ, got)
}
}
}
}
func TestLowBiasedQuery(t *testing.T) {
rand.Seed(42)
s := NewLowBiased(RelativeEpsilon)
a := populateStream(s)
verifyLowPercsWithRelativeEpsilon(t, a, s)
}
func TestHighBiasedQuery(t *testing.T) {
rand.Seed(42)
s := NewHighBiased(RelativeEpsilon)
a := populateStream(s)
verifyHighPercsWithRelativeEpsilon(t, a, s)
}
// BrokenTestTargetedMerge is broken, see Merge doc comment.
func BrokenTestTargetedMerge(t *testing.T) {
rand.Seed(42)
s1 := NewTargeted(Targets)
s2 := NewTargeted(Targets)
a := populateStream(s1)
a = append(a, populateStream(s2)...)
s1.Merge(s2.Samples())
verifyPercsWithAbsoluteEpsilon(t, a, s1)
}
// BrokenTestLowBiasedMerge is broken, see Merge doc comment.
func BrokenTestLowBiasedMerge(t *testing.T) {
rand.Seed(42)
s1 := NewLowBiased(RelativeEpsilon)
s2 := NewLowBiased(RelativeEpsilon)
a := populateStream(s1)
a = append(a, populateStream(s2)...)
s1.Merge(s2.Samples())
verifyLowPercsWithRelativeEpsilon(t, a, s2)
}
// BrokenTestHighBiasedMerge is broken, see Merge doc comment.
func BrokenTestHighBiasedMerge(t *testing.T) {
rand.Seed(42)
s1 := NewHighBiased(RelativeEpsilon)
s2 := NewHighBiased(RelativeEpsilon)
a := populateStream(s1)
a = append(a, populateStream(s2)...)
s1.Merge(s2.Samples())
verifyHighPercsWithRelativeEpsilon(t, a, s2)
}
func TestUncompressed(t *testing.T) {
q := NewTargeted(Targets)
for i := 100; i > 0; i-- {
q.Insert(float64(i))
}
if g := q.Count(); g != 100 {
t.Errorf("want count 100, got %d", g)
}
// Before compression, Query should have 100% accuracy.
for quantile := range Targets {
w := quantile * 100
if g := q.Query(quantile); g != w {
t.Errorf("want %f, got %f", w, g)
}
}
}
func TestUncompressedSamples(t *testing.T) {
q := NewTargeted(map[float64]float64{0.99: 0.001})
for i := 1; i <= 100; i++ {
q.Insert(float64(i))
}
if g := q.Samples().Len(); g != 100 {
t.Errorf("want count 100, got %d", g)
}
}
func TestUncompressedOne(t *testing.T) {
q := NewTargeted(map[float64]float64{0.99: 0.01})
q.Insert(3.14)
if g := q.Query(0.90); g != 3.14 {
t.Error("want PI, got", g)
}
}
func TestDefaults(t *testing.T) {
if g := NewTargeted(map[float64]float64{0.99: 0.001}).Query(0.99); g != 0 {
t.Errorf("want 0, got %f", g)
}
}
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
vendor
Godeps
language: go
sudo: false
go:
- 1.6.2
before_install:
- go get -u golang.org/x/tools/cmd/cover
- go get -u github.com/alecthomas/gometalinter
- go get -u github.com/mitchellh/mapstructure
- go get -u github.com/onsi/ginkgo
- go get -u github.com/onsi/gomega
- export PATH=$HOME/gopath/bin:$PATH
- gometalinter --install
script:
- gometalinter --disable-all --enable=vet --enable=vetshadow --enable=golint --enable=ineffassign --exclude=comment --tests .
- go test -race .
- go test -cover .
# Go CF Environment Package [![Build Status - Master](https://travis-ci.org/cloudfoundry-community/go-cfenv.svg?branch=master)](https://travis-ci.org/cloudfoundry-community/go-cfenv)
### Overview
[![GoDoc](https://godoc.org/github.com/cloudfoundry-community/go-cfenv?status.png)](https://godoc.org/github.com/cloudfoundry-community/go-cfenv)
`cfenv` is a package to assist you in writing Go apps that run on [Cloud Foundry](http://cloudfoundry.org). It provides convenience functions and structures that map to Cloud Foundry environment variable primitives (http://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html).
### Usage
`go get github.com/cloudfoundry-community/go-cfenv`
```go
package main
import (
"github.com/cloudfoundry-community/go-cfenv"
)
func main() {
appEnv, _ := cfenv.Current()
fmt.Println("ID:", appEnv.ID)
fmt.Println("Index:", appEnv.Index)
fmt.Println("Name:", appEnv.Name)
fmt.Println("Host:", appEnv.Host)
fmt.Println("Port:", appEnv.Port)
fmt.Println("Version:", appEnv.Version)
fmt.Println("Home:", appEnv.Home)
fmt.Println("MemoryLimit:", appEnv.MemoryLimit)
fmt.Println("WorkingDir:", appEnv.WorkingDir)
fmt.Println("TempDir:", appEnv.TempDir)
fmt.Println("User:", appEnv.User)
fmt.Println("Services:", appEnv.Services)
}
```
### Contributing
Pull requests welcomed.
package cfenv_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestCfenv(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Cfenv Suite")
}
This diff is collapsed.
package cfenv_test
import (
. "github.com/cloudfoundry-community/go-cfenv"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Environment", func() {
Describe("Environment variables should be mapped", func() {
Context("With default environment", func() {
It("Should contain at least one mapped variable", func() {
vars := CurrentEnv()
Ω(len(vars)).Should(BeNumerically(">", 0), "Environment variables should exist")
})
It("Should split variables into keys and values", func() {
vars := CurrentEnv()
valueCount := 0
for k, v := range vars {
// Key should never be empty
Ω(k).ShouldNot(BeEmpty())
// Key should never have equals
Ω(k).ShouldNot(ContainSubstring("="))
// Value may be empty, but let's track non-empty values
if v != "" {
valueCount++
}
}
// Ensure we get at least one value from the environment
Ω(valueCount).Should(BeNumerically(">", 0))
})
})
})
})
package cfenv
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Envmap", func() {
Describe("Environment variables should be split correctly", func() {
test := func(input string, expectedKey string, expectedValue string) {
k, v := splitEnv(input)
Ω(k).Should(Equal(expectedKey))
Ω(v).Should(Equal(expectedValue))
}
Context("With empty env var", func() {
It("Should have empty value", func() {
test("", "", "")
})
})
Context("With env var not split by equals", func() {
It("Should have empty value", func() {
test("TEST", "TEST", "")
})
})
Context("With env var split by equals but no value", func() {
It("Should have empty value", func() {
test("TEST=", "TEST", "")
})
})
Context("With env var split by equals with key and value", func() {
It("Should have non-empty key and value", func() {
test("TEST=VAL", "TEST", "VAL")
})
})
Context("With env var split by equals with key and value containing equals", func() {
It("Should have non-empty key and value", func() {
test("TEST=VAL=OTHERVAL", "TEST", "VAL=OTHERVAL")
})
})
})
})
language: go
sudo: false
services:
- redis-server
go:
- 1.4
- 1.5
- 1.6
- 1.7
- 1.8
- 1.9
- tip
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- go vet $(go list ./... | grep -v /vendor/)
- go test -v -race ./...
Redigo
======
[![Build Status](https://travis-ci.org/garyburd/redigo.svg?branch=master)](https://travis-ci.org/garyburd/redigo)
[![GoDoc](https://godoc.org/github.com/garyburd/redigo/redis?status.svg)](https://godoc.org/github.com/garyburd/redigo/redis)
Redigo is a [Go](http://golang.org/) client for the [Redis](http://redis.io/) database.
Features
-------
* A [Print-like](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Executing_Commands) API with support for all Redis commands.
* [Pipelining](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining), including pipelined transactions.
* [Publish/Subscribe](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Publish_and_Subscribe).
* [Connection pooling](http://godoc.org/github.com/garyburd/redigo/redis#Pool).
* [Script helper type](http://godoc.org/github.com/garyburd/redigo/redis#Script) with optimistic use of EVALSHA.
* [Helper functions](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Reply_Helpers) for working with command replies.
Documentation
-------------
- [API Reference](http://godoc.org/github.com/garyburd/redigo/redis)
- [FAQ](https://github.com/garyburd/redigo/wiki/FAQ)
- [Examples](https://godoc.org/github.com/garyburd/redigo/redis#pkg-examples)
Installation
------------
Install Redigo using the "go get" command:
go get github.com/garyburd/redigo/redis
The Go distribution is Redigo's only dependency.
Related Projects
----------------
- [rafaeljusto/redigomock](https://godoc.org/github.com/rafaeljusto/redigomock) - A mock library for Redigo.
- [chasex/redis-go-cluster](https://github.com/chasex/redis-go-cluster) - A Redis cluster client implementation.
- [FZambia/go-sentinel](https://github.com/FZambia/go-sentinel) - Redis Sentinel support for Redigo
- [PuerkitoBio/redisc](https://github.com/PuerkitoBio/redisc) - Redis Cluster client built on top of Redigo
Contributing
------------
See [CONTRIBUTING.md](https://github.com/garyburd/redigo/blob/master/.github/CONTRIBUTING.md).
License
-------
Redigo is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
package internal
import "testing"
func TestLookupCommandInfo(t *testing.T) {
for _, n := range []string{"watch", "WATCH", "wAtch"} {
if LookupCommandInfo(n) == (CommandInfo{}) {
t.Errorf("LookupCommandInfo(%q) = CommandInfo{}, expected non-zero value", n)
}
}
}
func benchmarkLookupCommandInfo(b *testing.B, names ...string) {
for i := 0; i < b.N; i++ {
for _, c := range names {
LookupCommandInfo(c)
}
}
}
func BenchmarkLookupCommandInfoCorrectCase(b *testing.B) {
benchmarkLookupCommandInfo(b, "watch", "WATCH", "monitor", "MONITOR")
}
func BenchmarkLookupCommandInfoMixedCase(b *testing.B) {
benchmarkLookupCommandInfo(b, "wAtch", "WeTCH", "monItor", "MONiTOR")
}
Loading
@@ -29,6 +29,10 @@ import (
Loading
@@ -29,6 +29,10 @@ import (
"time" "time"
) )
   
var (
_ ConnWithTimeout = (*conn)(nil)
)
// conn is the low-level implementation of Conn // conn is the low-level implementation of Conn
type conn struct { type conn struct {
// Shared // Shared
Loading
@@ -72,6 +76,7 @@ type DialOption struct {
Loading
@@ -72,6 +76,7 @@ type DialOption struct {
type dialOptions struct { type dialOptions struct {
readTimeout time.Duration readTimeout time.Duration
writeTimeout time.Duration writeTimeout time.Duration
dialer *net.Dialer
dial func(network, addr string) (net.Conn, error) dial func(network, addr string) (net.Conn, error)
db int db int
password string password string
Loading
@@ -94,17 +99,27 @@ func DialWriteTimeout(d time.Duration) DialOption {
Loading
@@ -94,17 +99,27 @@ func DialWriteTimeout(d time.Duration) DialOption {
}} }}
} }
   
// DialConnectTimeout specifies the timeout for connecting to the Redis server. // DialConnectTimeout specifies the timeout for connecting to the Redis server when
// no DialNetDial option is specified.
func DialConnectTimeout(d time.Duration) DialOption { func DialConnectTimeout(d time.Duration) DialOption {
return DialOption{func(do *dialOptions) { return DialOption{func(do *dialOptions) {
dialer := net.Dialer{Timeout: d} do.dialer.Timeout = d
do.dial = dialer.Dial }}
}
// DialKeepAlive specifies the keep-alive period for TCP connections to the Redis server
// when no DialNetDial option is specified.
// If zero, keep-alives are not enabled. If no DialKeepAlive option is specified then
// the default of 5 minutes is used to ensure that half-closed TCP sessions are detected.
func DialKeepAlive(d time.Duration) DialOption {
return DialOption{func(do *dialOptions) {
do.dialer.KeepAlive = d
}} }}
} }
   
// DialNetDial specifies a custom dial function for creating TCP // DialNetDial specifies a custom dial function for creating TCP
// connections. If this option is left out, then net.Dial is // connections, otherwise a net.Dialer customized via the other options is used.
// used. DialNetDial overrides DialConnectTimeout. // DialNetDial overrides DialConnectTimeout and DialKeepAlive.
func DialNetDial(dial func(network, addr string) (net.Conn, error)) DialOption { func DialNetDial(dial func(network, addr string) (net.Conn, error)) DialOption {
return DialOption{func(do *dialOptions) { return DialOption{func(do *dialOptions) {
do.dial = dial do.dial = dial
Loading
@@ -154,11 +169,16 @@ func DialUseTLS(useTLS bool) DialOption {
Loading
@@ -154,11 +169,16 @@ func DialUseTLS(useTLS bool) DialOption {
// address using the specified options. // address using the specified options.
func Dial(network, address string, options ...DialOption) (Conn, error) { func Dial(network, address string, options ...DialOption) (Conn, error) {
do := dialOptions{ do := dialOptions{
dial: net.Dial, dialer: &net.Dialer{
KeepAlive: time.Minute * 5,
},
} }
for _, option := range options { for _, option := range options {
option.f(&do) option.f(&do)
} }
if do.dial == nil {
do.dial = do.dialer.Dial
}
   
netConn, err := do.dial(network, address) netConn, err := do.dial(network, address)
if err != nil { if err != nil {
Loading
@@ -166,7 +186,12 @@ func Dial(network, address string, options ...DialOption) (Conn, error) {
Loading
@@ -166,7 +186,12 @@ func Dial(network, address string, options ...DialOption) (Conn, error) {
} }
   
if do.useTLS { if do.useTLS {
tlsConfig := cloneTLSClientConfig(do.tlsConfig, do.skipVerify) var tlsConfig *tls.Config
if do.tlsConfig == nil {
tlsConfig = &tls.Config{InsecureSkipVerify: do.skipVerify}
} else {
tlsConfig = cloneTLSConfig(do.tlsConfig)
}
if tlsConfig.ServerName == "" { if tlsConfig.ServerName == "" {
host, _, err := net.SplitHostPort(address) host, _, err := net.SplitHostPort(address)
if err != nil { if err != nil {
Loading
@@ -555,10 +580,17 @@ func (c *conn) Flush() error {
Loading
@@ -555,10 +580,17 @@ func (c *conn) Flush() error {
return nil return nil
} }
   
func (c *conn) Receive() (reply interface{}, err error) { func (c *conn) Receive() (interface{}, error) {
if c.readTimeout != 0 { return c.ReceiveWithTimeout(c.readTimeout)
c.conn.SetReadDeadline(time.Now().Add(c.readTimeout)) }
func (c *conn) ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err error) {
var deadline time.Time
if timeout != 0 {
deadline = time.Now().Add(timeout)
} }
c.conn.SetReadDeadline(deadline)
if reply, err = c.readReply(); err != nil { if reply, err = c.readReply(); err != nil {
return nil, c.fatal(err) return nil, c.fatal(err)
} }
Loading
@@ -581,6 +613,10 @@ func (c *conn) Receive() (reply interface{}, err error) {
Loading
@@ -581,6 +613,10 @@ func (c *conn) Receive() (reply interface{}, err error) {
} }
   
func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) { func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {
return c.DoWithTimeout(c.readTimeout, cmd, args...)
}
func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...interface{}) (interface{}, error) {
c.mu.Lock() c.mu.Lock()
pending := c.pending pending := c.pending
c.pending = 0 c.pending = 0
Loading
@@ -604,9 +640,11 @@ func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {
Loading
@@ -604,9 +640,11 @@ func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {
return nil, c.fatal(err) return nil, c.fatal(err)
} }
   
if c.readTimeout != 0 { var deadline time.Time
c.conn.SetReadDeadline(time.Now().Add(c.readTimeout)) if readTimeout != 0 {
deadline = time.Now().Add(readTimeout)
} }
c.conn.SetReadDeadline(deadline)
   
if cmd == "" { if cmd == "" {
reply := make([]interface{}, pending) reply := make([]interface{}, pending)
Loading
Loading
// Copyright 2012 Gary Burd
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package redis_test
import (
"bytes"
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"math"
"net"
"os"
"reflect"
"strings"
"testing"
"time"
"github.com/garyburd/redigo/redis"
)
type testConn struct {
io.Reader
io.Writer
}
func (*testConn) Close() error { return nil }
func (*testConn) LocalAddr() net.Addr { return nil }
func (*testConn) RemoteAddr() net.Addr { return nil }
func (*testConn) SetDeadline(t time.Time) error { return nil }
func (*testConn) SetReadDeadline(t time.Time) error { return nil }
func (*testConn) SetWriteDeadline(t time.Time) error { return nil }
func dialTestConn(r string, w io.Writer) redis.DialOption {
return redis.DialNetDial(func(network, addr string) (net.Conn, error) {
return &testConn{Reader: strings.NewReader(r), Writer: w}, nil
})
}
type tlsTestConn struct {
net.Conn
done chan struct{}
}
func (c *tlsTestConn) Close() error {
c.Conn.Close()
<-c.done
return nil
}
func dialTestConnTLS(r string, w io.Writer) redis.DialOption {
return redis.DialNetDial(func(network, addr string) (net.Conn, error) {
client, server := net.Pipe()
tlsServer := tls.Server(server, &serverTLSConfig)
go io.Copy(tlsServer, strings.NewReader(r))
done := make(chan struct{})
go func() {
io.Copy(w, tlsServer)
close(done)
}()
return &tlsTestConn{Conn: client, done: done}, nil
})
}
type durationArg struct {
time.Duration
}
func (t durationArg) RedisArg() interface{} {
return t.Seconds()
}
type recursiveArg int
func (v recursiveArg) RedisArg() interface{} { return v }
var writeTests = []struct {
args []interface{}
expected string
}{
{
[]interface{}{"SET", "key", "value"},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n",
},
{
[]interface{}{"SET", "key", "value"},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n",
},
{
[]interface{}{"SET", "key", byte(100)},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n100\r\n",
},
{
[]interface{}{"SET", "key", 100},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n100\r\n",
},
{
[]interface{}{"SET", "key", int64(math.MinInt64)},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$20\r\n-9223372036854775808\r\n",
},
{
[]interface{}{"SET", "key", float64(1349673917.939762)},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$21\r\n1.349673917939762e+09\r\n",
},
{
[]interface{}{"SET", "key", ""},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
},
{
[]interface{}{"SET", "key", nil},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
},
{
[]interface{}{"SET", "key", durationArg{time.Minute}},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$2\r\n60\r\n",
},
{
[]interface{}{"SET", "key", recursiveArg(123)},
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n123\r\n",
},
{
[]interface{}{"ECHO", true, false},
"*3\r\n$4\r\nECHO\r\n$1\r\n1\r\n$1\r\n0\r\n",
},
}
func TestWrite(t *testing.T) {
for _, tt := range writeTests {
var buf bytes.Buffer
c, _ := redis.Dial("", "", dialTestConn("", &buf))
err := c.Send(tt.args[0].(string), tt.args[1:]...)
if err != nil {
t.Errorf("Send(%v) returned error %v", tt.args, err)
continue
}
c.Flush()
actual := buf.String()
if actual != tt.expected {
t.Errorf("Send(%v) = %q, want %q", tt.args, actual, tt.expected)
}
}
}
var errorSentinel = &struct{}{}
var readTests = []struct {
reply string
expected interface{}
}{
{
"+OK\r\n",
"OK",
},
{
"+PONG\r\n",
"PONG",
},
{
"@OK\r\n",
errorSentinel,
},
{
"$6\r\nfoobar\r\n",
[]byte("foobar"),
},
{
"$-1\r\n",
nil,
},
{
":1\r\n",
int64(1),
},
{
":-2\r\n",
int64(-2),
},
{
"*0\r\n",
[]interface{}{},
},
{
"*-1\r\n",
nil,
},
{
"*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$5\r\nHello\r\n$5\r\nWorld\r\n",
[]interface{}{[]byte("foo"), []byte("bar"), []byte("Hello"), []byte("World")},
},
{
"*3\r\n$3\r\nfoo\r\n$-1\r\n$3\r\nbar\r\n",
[]interface{}{[]byte("foo"), nil, []byte("bar")},
},
{
// "x" is not a valid length
"$x\r\nfoobar\r\n",
errorSentinel,
},
{
// -2 is not a valid length
"$-2\r\n",
errorSentinel,
},
{
// "x" is not a valid integer
":x\r\n",
errorSentinel,
},
{
// missing \r\n following value
"$6\r\nfoobar",
errorSentinel,
},
{
// short value
"$6\r\nxx",
errorSentinel,
},
{
// long value
"$6\r\nfoobarx\r\n",
errorSentinel,
},
}
func TestRead(t *testing.T) {
for _, tt := range readTests {
c, _ := redis.Dial("", "", dialTestConn(tt.reply, nil))
actual, err := c.Receive()
if tt.expected == errorSentinel {
if err == nil {
t.Errorf("Receive(%q) did not return expected error", tt.reply)
}
} else {
if err != nil {
t.Errorf("Receive(%q) returned error %v", tt.reply, err)
continue
}
if !reflect.DeepEqual(actual, tt.expected) {
t.Errorf("Receive(%q) = %v, want %v", tt.reply, actual, tt.expected)
}
}
}
}
var testCommands = []struct {
args []interface{}
expected interface{}
}{
{
[]interface{}{"PING"},
"PONG",
},
{
[]interface{}{"SET", "foo", "bar"},
"OK",
},
{
[]interface{}{"GET", "foo"},
[]byte("bar"),
},
{
[]interface{}{"GET", "nokey"},
nil,
},
{
[]interface{}{"MGET", "nokey", "foo"},
[]interface{}{nil, []byte("bar")},
},
{
[]interface{}{"INCR", "mycounter"},
int64(1),
},
{
[]interface{}{"LPUSH", "mylist", "foo"},
int64(1),
},
{
[]interface{}{"LPUSH", "mylist", "bar"},
int64(2),
},
{
[]interface{}{"LRANGE", "mylist", 0, -1},
[]interface{}{[]byte("bar"), []byte("foo")},
},
{
[]interface{}{"MULTI"},
"OK",
},
{
[]interface{}{"LRANGE", "mylist", 0, -1},
"QUEUED",
},
{
[]interface{}{"PING"},
"QUEUED",
},
{
[]interface{}{"EXEC"},
[]interface{}{
[]interface{}{[]byte("bar"), []byte("foo")},
"PONG",
},
},
}
func TestDoCommands(t *testing.T) {
c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
defer c.Close()
for _, cmd := range testCommands {
actual, err := c.Do(cmd.args[0].(string), cmd.args[1:]...)
if err != nil {
t.Errorf("Do(%v) returned error %v", cmd.args, err)
continue
}
if !reflect.DeepEqual(actual, cmd.expected) {
t.Errorf("Do(%v) = %v, want %v", cmd.args, actual, cmd.expected)
}
}
}
func TestPipelineCommands(t *testing.T) {
c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
defer c.Close()
for _, cmd := range testCommands {
if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
t.Fatalf("Send(%v) returned error %v", cmd.args, err)
}
}
if err := c.Flush(); err != nil {
t.Errorf("Flush() returned error %v", err)
}
for _, cmd := range testCommands {
actual, err := c.Receive()
if err != nil {
t.Fatalf("Receive(%v) returned error %v", cmd.args, err)
}
if !reflect.DeepEqual(actual, cmd.expected) {
t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
}
}
}
func TestBlankCommmand(t *testing.T) {
c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
defer c.Close()
for _, cmd := range testCommands {
if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
t.Fatalf("Send(%v) returned error %v", cmd.args, err)
}
}
reply, err := redis.Values(c.Do(""))
if err != nil {
t.Fatalf("Do() returned error %v", err)
}
if len(reply) != len(testCommands) {
t.Fatalf("len(reply)=%d, want %d", len(reply), len(testCommands))
}
for i, cmd := range testCommands {
actual := reply[i]
if !reflect.DeepEqual(actual, cmd.expected) {
t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
}
}
}
func TestRecvBeforeSend(t *testing.T) {
c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
defer c.Close()
done := make(chan struct{})
go func() {
c.Receive()
close(done)
}()
time.Sleep(time.Millisecond)
c.Send("PING")
c.Flush()
<-done
_, err = c.Do("")
if err != nil {
t.Fatalf("error=%v", err)
}
}
func TestError(t *testing.T) {
c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
defer c.Close()
c.Do("SET", "key", "val")
_, err = c.Do("HSET", "key", "fld", "val")
if err == nil {
t.Errorf("Expected err for HSET on string key.")
}
if c.Err() != nil {
t.Errorf("Conn has Err()=%v, expect nil", c.Err())
}
_, err = c.Do("SET", "key", "val")
if err != nil {
t.Errorf("Do(SET, key, val) returned error %v, expected nil.", err)
}
}
func TestReadTimeout(t *testing.T) {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("net.Listen returned %v", err)
}
defer l.Close()
go func() {
for {
c, err := l.Accept()
if err != nil {
return
}
go func() {
time.Sleep(time.Second)
c.Write([]byte("+OK\r\n"))
c.Close()
}()
}
}()
// Do
c1, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
if err != nil {
t.Fatalf("redis.Dial returned %v", err)
}
defer c1.Close()
_, err = c1.Do("PING")
if err == nil {
t.Fatalf("c1.Do() returned nil, expect error")
}
if c1.Err() == nil {
t.Fatalf("c1.Err() = nil, expect error")
}
// Send/Flush/Receive
c2, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
if err != nil {
t.Fatalf("redis.Dial returned %v", err)
}
defer c2.Close()
c2.Send("PING")
c2.Flush()
_, err = c2.Receive()
if err == nil {
t.Fatalf("c2.Receive() returned nil, expect error")
}
if c2.Err() == nil {
t.Fatalf("c2.Err() = nil, expect error")
}
}
var dialErrors = []struct {
rawurl string
expectedError string
}{
{
"localhost",
"invalid redis URL scheme",
},
// The error message for invalid hosts is different in different
// versions of Go, so just check that there is an error message.
{
"redis://weird url",
"",
},
{
"redis://foo:bar:baz",
"",
},
{
"http://www.google.com",
"invalid redis URL scheme: http",
},
{
"redis://localhost:6379/abc123",
"invalid database: abc123",
},
}
func TestDialURLErrors(t *testing.T) {
for _, d := range dialErrors {
_, err := redis.DialURL(d.rawurl)
if err == nil || !strings.Contains(err.Error(), d.expectedError) {
t.Errorf("DialURL did not return expected error (expected %v to contain %s)", err, d.expectedError)
}
}
}
func TestDialURLPort(t *testing.T) {
checkPort := func(network, address string) (net.Conn, error) {
if address != "localhost:6379" {
t.Errorf("DialURL did not set port to 6379 by default (got %v)", address)
}
return nil, nil
}
_, err := redis.DialURL("redis://localhost", redis.DialNetDial(checkPort))
if err != nil {
t.Error("dial error:", err)
}
}
func TestDialURLHost(t *testing.T) {
checkHost := func(network, address string) (net.Conn, error) {
if address != "localhost:6379" {
t.Errorf("DialURL did not set host to localhost by default (got %v)", address)
}
return nil, nil
}
_, err := redis.DialURL("redis://:6379", redis.DialNetDial(checkHost))
if err != nil {
t.Error("dial error:", err)
}
}
var dialURLTests = []struct {
description string
url string
r string
w string
}{
{"password", "redis://x:abc123@localhost", "+OK\r\n", "*2\r\n$4\r\nAUTH\r\n$6\r\nabc123\r\n"},
{"database 3", "redis://localhost/3", "+OK\r\n", "*2\r\n$6\r\nSELECT\r\n$1\r\n3\r\n"},
{"database 99", "redis://localhost/99", "+OK\r\n", "*2\r\n$6\r\nSELECT\r\n$2\r\n99\r\n"},
{"no database", "redis://localhost/", "+OK\r\n", ""},
}
func TestDialURL(t *testing.T) {
for _, tt := range dialURLTests {
var buf bytes.Buffer
// UseTLS should be ignored in all of these tests.
_, err := redis.DialURL(tt.url, dialTestConn(tt.r, &buf), redis.DialUseTLS(true))
if err != nil {
t.Errorf("%s dial error: %v", tt.description, err)
continue
}
if w := buf.String(); w != tt.w {
t.Errorf("%s commands = %q, want %q", tt.description, w, tt.w)
}
}
}
func checkPingPong(t *testing.T, buf *bytes.Buffer, c redis.Conn) {
resp, err := c.Do("PING")
if err != nil {
t.Fatal("ping error:", err)
}
// Close connection to ensure that writes to buf are complete.
c.Close()
expected := "*1\r\n$4\r\nPING\r\n"
actual := buf.String()
if actual != expected {
t.Errorf("commands = %q, want %q", actual, expected)
}
if resp != "PONG" {
t.Errorf("resp = %v, want %v", resp, "PONG")
}
}
const pingResponse = "+PONG\r\n"
func TestDialURLTLS(t *testing.T) {
var buf bytes.Buffer
c, err := redis.DialURL("rediss://example.com/",
redis.DialTLSConfig(&clientTLSConfig),
dialTestConnTLS(pingResponse, &buf))
if err != nil {
t.Fatal("dial error:", err)
}
checkPingPong(t, &buf, c)
}
func TestDialUseTLS(t *testing.T) {
var buf bytes.Buffer
c, err := redis.Dial("tcp", "example.com:6379",
redis.DialTLSConfig(&clientTLSConfig),
dialTestConnTLS(pingResponse, &buf),
redis.DialUseTLS(true))
if err != nil {
t.Fatal("dial error:", err)
}
checkPingPong(t, &buf, c)
}
func TestDialTLSSKipVerify(t *testing.T) {
var buf bytes.Buffer
c, err := redis.Dial("tcp", "example.com:6379",
dialTestConnTLS(pingResponse, &buf),
redis.DialTLSSkipVerify(true),
redis.DialUseTLS(true))
if err != nil {
t.Fatal("dial error:", err)
}
checkPingPong(t, &buf, c)
}
// Connect to local instance of Redis running on the default port.
func ExampleDial() {
c, err := redis.Dial("tcp", ":6379")
if err != nil {
// handle error
}
defer c.Close()
}
// Connect to remote instance of Redis using a URL.
func ExampleDialURL() {
c, err := redis.DialURL(os.Getenv("REDIS_URL"))
if err != nil {
// handle connection error
}
defer c.Close()
}
// TextExecError tests handling of errors in a transaction. See
// http://redis.io/topics/transactions for information on how Redis handles
// errors in a transaction.
func TestExecError(t *testing.T) {
c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
defer c.Close()
// Execute commands that fail before EXEC is called.
c.Do("DEL", "k0")
c.Do("ZADD", "k0", 0, 0)
c.Send("MULTI")
c.Send("NOTACOMMAND", "k0", 0, 0)
c.Send("ZINCRBY", "k0", 0, 0)
v, err := c.Do("EXEC")
if err == nil {
t.Fatalf("EXEC returned values %v, expected error", v)
}
// Execute commands that fail after EXEC is called. The first command
// returns an error.
c.Do("DEL", "k1")
c.Do("ZADD", "k1", 0, 0)
c.Send("MULTI")
c.Send("HSET", "k1", 0, 0)
c.Send("ZINCRBY", "k1", 0, 0)
v, err = c.Do("EXEC")
if err != nil {
t.Fatalf("EXEC returned error %v", err)
}
vs, err := redis.Values(v, nil)
if err != nil {
t.Fatalf("Values(v) returned error %v", err)
}
if len(vs) != 2 {
t.Fatalf("len(vs) == %d, want 2", len(vs))
}
if _, ok := vs[0].(error); !ok {
t.Fatalf("first result is type %T, expected error", vs[0])
}
if _, ok := vs[1].([]byte); !ok {
t.Fatalf("second result is type %T, expected []byte", vs[1])
}
// Execute commands that fail after EXEC is called. The second command
// returns an error.
c.Do("ZADD", "k2", 0, 0)
c.Send("MULTI")
c.Send("ZINCRBY", "k2", 0, 0)
c.Send("HSET", "k2", 0, 0)
v, err = c.Do("EXEC")
if err != nil {
t.Fatalf("EXEC returned error %v", err)
}
vs, err = redis.Values(v, nil)
if err != nil {
t.Fatalf("Values(v) returned error %v", err)
}
if len(vs) != 2 {
t.Fatalf("len(vs) == %d, want 2", len(vs))
}
if _, ok := vs[0].([]byte); !ok {
t.Fatalf("first result is type %T, expected []byte", vs[0])
}
if _, ok := vs[1].(error); !ok {
t.Fatalf("second result is type %T, expected error", vs[2])
}
}
func BenchmarkDoEmpty(b *testing.B) {
b.StopTimer()
c, err := redis.DialDefaultServer()
if err != nil {
b.Fatal(err)
}
defer c.Close()
b.StartTimer()
for i := 0; i < b.N; i++ {
if _, err := c.Do(""); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkDoPing(b *testing.B) {
b.StopTimer()
c, err := redis.DialDefaultServer()
if err != nil {
b.Fatal(err)
}
defer c.Close()
b.StartTimer()
for i := 0; i < b.N; i++ {
if _, err := c.Do("PING"); err != nil {
b.Fatal(err)
}
}
}
var clientTLSConfig, serverTLSConfig tls.Config
func init() {
// The certificate and key for testing TLS dial options was created
// using the command
//
// go run GOROOT/src/crypto/tls/generate_cert.go \
// --rsa-bits 1024 \
// --host 127.0.0.1,::1,example.com --ca \
// --start-date "Jan 1 00:00:00 1970" \
// --duration=1000000h
//
// where GOROOT is the value of GOROOT reported by go env.
localhostCert := []byte(`
-----BEGIN CERTIFICATE-----
MIICFDCCAX2gAwIBAgIRAJfBL4CUxkXcdlFurb3K+iowDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2
MDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEArizw8WxMUQ3bGHLeuJ4fDrEpy+L2pqrbYRlKk1DasJ/VkB8bImzIpe6+
LGjiYIxvnDCOJ3f3QplcQuiuMyl6f2irJlJsbFT8Lo/3obnuTKAIaqUdJUqBg6y+
JaL8Auk97FvunfKFv8U1AIhgiLzAfQ/3Eaq1yi87Ra6pMjGbTtcCAwEAAaNoMGYw
DgYDVR0PAQH/BAQDAgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQF
MAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAAAAAAAAAA
AAAAAAEwDQYJKoZIhvcNAQELBQADgYEAdZ8daIVkyhVwflt5I19m0oq1TycbGO1+
ach7T6cZiBQeNR/SJtxr/wKPEpmvUgbv2BfFrKJ8QoIHYsbNSURTWSEa02pfw4k9
6RQhij3ZkG79Ituj5OYRORV6Z0HUW32r670BtcuHuAhq7YA6Nxy4FtSt7bAlVdRt
rrKgNsltzMk=
-----END CERTIFICATE-----`)
localhostKey := []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCuLPDxbExRDdsYct64nh8OsSnL4vamqtthGUqTUNqwn9WQHxsi
bMil7r4saOJgjG+cMI4nd/dCmVxC6K4zKXp/aKsmUmxsVPwuj/ehue5MoAhqpR0l
SoGDrL4lovwC6T3sW+6d8oW/xTUAiGCIvMB9D/cRqrXKLztFrqkyMZtO1wIDAQAB
AoGACrc5G6FOEK6JjDeE/Fa+EmlT6PdNtXNNi+vCas3Opo8u1G8VfEi1D4BgstrB
Eq+RLkrOdB8tVyuYQYWPMhabMqF+hhKJN72j0OwfuPlVvTInwb/cKjo/zbH1IA+Y
HenHNK4ywv7/p/9/MvQPJ3I32cQBCgGUW5chVSH5M1sj5gECQQDabQAI1X0uDqCm
KbX9gXVkAgxkFddrt6LBHt57xujFcqEKFE7nwKhDh7DweVs/VEJ+kpid4z+UnLOw
KjtP9JolAkEAzCNBphQ//IsbH5rNs10wIUw3Ks/Oepicvr6kUFbIv+neRzi1iJHa
m6H7EayK3PWgax6BAsR/t0Jc9XV7r2muSwJAVzN09BHnK+ADGtNEKLTqXMbEk6B0
pDhn7ZmZUOkUPN+Kky+QYM11X6Bob1jDqQDGmymDbGUxGO+GfSofC8inUQJAGfci
Eo3g1a6b9JksMPRZeuLG4ZstGErxJRH6tH1Va5PDwitka8qhk8o2tTjNMO3NSdLH
diKoXBcE2/Pll5pJoQJBAIMiiMIzXJhnN4mX8may44J/HvMlMf2xuVH2gNMwmZuc
Bjqn3yoLHaoZVvbWOi0C2TCN4FjXjaLNZGifQPbIcaA=
-----END RSA PRIVATE KEY-----`)
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
if err != nil {
panic(fmt.Sprintf("error creating key pair: %v", err))
}
serverTLSConfig.Certificates = []tls.Certificate{cert}
certificate, err := x509.ParseCertificate(serverTLSConfig.Certificates[0].Certificate[0])
if err != nil {
panic(fmt.Sprintf("error parsing x509 certificate: %v", err))
}
clientTLSConfig.RootCAs = x509.NewCertPool()
clientTLSConfig.RootCAs.AddCert(certificate)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment