mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
PLT-3753 Added Segment analytics (#3972)
This commit is contained in:
4
vendor/github.com/jehiah/go-strftime/README.md
generated
vendored
Normal file
4
vendor/github.com/jehiah/go-strftime/README.md
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
go-strftime
|
||||
===========
|
||||
|
||||
go implementation of strftime
|
||||
71
vendor/github.com/jehiah/go-strftime/strftime.go
generated
vendored
Normal file
71
vendor/github.com/jehiah/go-strftime/strftime.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// go implementation of strftime
|
||||
package strftime
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// taken from time/format.go
|
||||
var conversion = map[rune]string {
|
||||
/*stdLongMonth */ 'B':"January",
|
||||
/*stdMonth */ 'b': "Jan",
|
||||
// stdNumMonth */ 'm': "1",
|
||||
/*stdZeroMonth */ 'm': "01",
|
||||
/*stdLongWeekDay */ 'A': "Monday",
|
||||
/*stdWeekDay */ 'a': "Mon",
|
||||
// stdDay */ 'd': "2",
|
||||
// stdUnderDay */ 'd': "_2",
|
||||
/*stdZeroDay */ 'd': "02",
|
||||
/*stdHour */ 'H': "15",
|
||||
// stdHour12 */ 'I': "3",
|
||||
/*stdZeroHour12 */ 'I': "03",
|
||||
// stdMinute */ 'M': "4",
|
||||
/*stdZeroMinute */ 'M': "04",
|
||||
// stdSecond */ 'S': "5",
|
||||
/*stdZeroSecond */ 'S': "05",
|
||||
/*stdLongYear */ 'Y': "2006",
|
||||
/*stdYear */ 'y': "06",
|
||||
/*stdPM */ 'p': "PM",
|
||||
// stdpm */ 'p': "pm",
|
||||
/*stdTZ */ 'Z': "MST",
|
||||
// stdISO8601TZ */ 'z': "Z0700", // prints Z for UTC
|
||||
// stdISO8601ColonTZ */ 'z': "Z07:00", // prints Z for UTC
|
||||
/*stdNumTZ */ 'z': "-0700", // always numeric
|
||||
// stdNumShortTZ */ 'b': "-07", // always numeric
|
||||
// stdNumColonTZ */ 'b': "-07:00", // always numeric
|
||||
}
|
||||
|
||||
// This is an alternative to time.Format because no one knows
|
||||
// what date 040305 is supposed to create when used as a 'layout' string
|
||||
// this takes standard strftime format options. For a complete list
|
||||
// of format options see http://strftime.org/
|
||||
func Format(format string, t time.Time) string {
|
||||
retval := make([]byte, 0, len(format))
|
||||
for i, ni := 0, 0; i < len(format); i = ni + 2 {
|
||||
ni = strings.IndexByte(format[i:], '%')
|
||||
if ni < 0 {
|
||||
ni = len(format)
|
||||
} else {
|
||||
ni += i
|
||||
}
|
||||
retval = append(retval, []byte(format[i:ni])...)
|
||||
if ni + 1 < len(format) {
|
||||
c := format[ni + 1]
|
||||
if c == '%' {
|
||||
retval = append(retval, '%')
|
||||
} else {
|
||||
if layoutCmd, ok := conversion[rune(c)]; ok {
|
||||
retval = append(retval, []byte(t.Format(layoutCmd))...)
|
||||
} else {
|
||||
retval = append(retval, '%', c)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ni < len(format) {
|
||||
retval = append(retval, '%')
|
||||
}
|
||||
}
|
||||
}
|
||||
return string(retval)
|
||||
}
|
||||
40
vendor/github.com/jehiah/go-strftime/strftime_test.go
generated
vendored
Normal file
40
vendor/github.com/jehiah/go-strftime/strftime_test.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package strftime
|
||||
|
||||
import (
|
||||
"time"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func ExampleFormat() {
|
||||
t := time.Unix(1340244776, 0)
|
||||
utc, _ := time.LoadLocation("UTC")
|
||||
t = t.In(utc)
|
||||
fmt.Println(Format("%Y-%m-%d %H:%M:%S", t))
|
||||
// Output:
|
||||
// 2012-06-21 02:12:56
|
||||
}
|
||||
|
||||
func TestNoLeadingPercentSign(t *testing.T) {
|
||||
tm := time.Unix(1340244776, 0)
|
||||
utc, _ := time.LoadLocation("UTC")
|
||||
tm = tm.In(utc)
|
||||
result := Format("aaabbb0123456789%Y", tm)
|
||||
if result != "aaabbb01234567892012" {
|
||||
t.Logf("%s != %s", result, "aaabbb01234567892012")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestUnsupported(t *testing.T) {
|
||||
tm := time.Unix(1340244776, 0)
|
||||
utc, _ := time.LoadLocation("UTC")
|
||||
tm = tm.In(utc)
|
||||
result := Format("%0%1%%%2", tm)
|
||||
if result != "%0%1%%2" {
|
||||
t.Logf("%s != %s", result, "%0%1%%2")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
17
vendor/github.com/segmentio/analytics-go/Godeps/Godeps.json
generated
vendored
Normal file
17
vendor/github.com/segmentio/analytics-go/Godeps/Godeps.json
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"ImportPath": "github.com/segmentio/analytics-go",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/jehiah/go-strftime",
|
||||
"Rev": "834e15c05a45371503440cc195bbd05c9a0968d9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/xtgo/uuid",
|
||||
"Rev": "a0b114877d4caeffbd7f87e3757c17fce570fea7"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
vendor/github.com/segmentio/analytics-go/Godeps/Readme
generated
vendored
Normal file
5
vendor/github.com/segmentio/analytics-go/Godeps/Readme
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
||||
2
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/.gitignore
generated
vendored
Normal file
2
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/pkg
|
||||
/bin
|
||||
22
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/jehiah/go-strftime/.gitignore
generated
vendored
Normal file
22
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/jehiah/go-strftime/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# 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
|
||||
4
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/jehiah/go-strftime/README.md
generated
vendored
Normal file
4
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/jehiah/go-strftime/README.md
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
go-strftime
|
||||
===========
|
||||
|
||||
go implementation of strftime
|
||||
71
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/jehiah/go-strftime/strftime.go
generated
vendored
Normal file
71
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/jehiah/go-strftime/strftime.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// go implementation of strftime
|
||||
package strftime
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// taken from time/format.go
|
||||
var conversion = map[rune]string {
|
||||
/*stdLongMonth */ 'B':"January",
|
||||
/*stdMonth */ 'b': "Jan",
|
||||
// stdNumMonth */ 'm': "1",
|
||||
/*stdZeroMonth */ 'm': "01",
|
||||
/*stdLongWeekDay */ 'A': "Monday",
|
||||
/*stdWeekDay */ 'a': "Mon",
|
||||
// stdDay */ 'd': "2",
|
||||
// stdUnderDay */ 'd': "_2",
|
||||
/*stdZeroDay */ 'd': "02",
|
||||
/*stdHour */ 'H': "15",
|
||||
// stdHour12 */ 'I': "3",
|
||||
/*stdZeroHour12 */ 'I': "03",
|
||||
// stdMinute */ 'M': "4",
|
||||
/*stdZeroMinute */ 'M': "04",
|
||||
// stdSecond */ 'S': "5",
|
||||
/*stdZeroSecond */ 'S': "05",
|
||||
/*stdLongYear */ 'Y': "2006",
|
||||
/*stdYear */ 'y': "06",
|
||||
/*stdPM */ 'p': "PM",
|
||||
// stdpm */ 'p': "pm",
|
||||
/*stdTZ */ 'Z': "MST",
|
||||
// stdISO8601TZ */ 'z': "Z0700", // prints Z for UTC
|
||||
// stdISO8601ColonTZ */ 'z': "Z07:00", // prints Z for UTC
|
||||
/*stdNumTZ */ 'z': "-0700", // always numeric
|
||||
// stdNumShortTZ */ 'b': "-07", // always numeric
|
||||
// stdNumColonTZ */ 'b': "-07:00", // always numeric
|
||||
}
|
||||
|
||||
// This is an alternative to time.Format because no one knows
|
||||
// what date 040305 is supposed to create when used as a 'layout' string
|
||||
// this takes standard strftime format options. For a complete list
|
||||
// of format options see http://strftime.org/
|
||||
func Format(format string, t time.Time) string {
|
||||
retval := make([]byte, 0, len(format))
|
||||
for i, ni := 0, 0; i < len(format); i = ni + 2 {
|
||||
ni = strings.IndexByte(format[i:], '%')
|
||||
if ni < 0 {
|
||||
ni = len(format)
|
||||
} else {
|
||||
ni += i
|
||||
}
|
||||
retval = append(retval, []byte(format[i:ni])...)
|
||||
if ni + 1 < len(format) {
|
||||
c := format[ni + 1]
|
||||
if c == '%' {
|
||||
retval = append(retval, '%')
|
||||
} else {
|
||||
if layoutCmd, ok := conversion[rune(c)]; ok {
|
||||
retval = append(retval, []byte(t.Format(layoutCmd))...)
|
||||
} else {
|
||||
retval = append(retval, '%', c)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ni < len(format) {
|
||||
retval = append(retval, '%')
|
||||
}
|
||||
}
|
||||
}
|
||||
return string(retval)
|
||||
}
|
||||
40
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/jehiah/go-strftime/strftime_test.go
generated
vendored
Normal file
40
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/jehiah/go-strftime/strftime_test.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package strftime
|
||||
|
||||
import (
|
||||
"time"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func ExampleFormat() {
|
||||
t := time.Unix(1340244776, 0)
|
||||
utc, _ := time.LoadLocation("UTC")
|
||||
t = t.In(utc)
|
||||
fmt.Println(Format("%Y-%m-%d %H:%M:%S", t))
|
||||
// Output:
|
||||
// 2012-06-21 02:12:56
|
||||
}
|
||||
|
||||
func TestNoLeadingPercentSign(t *testing.T) {
|
||||
tm := time.Unix(1340244776, 0)
|
||||
utc, _ := time.LoadLocation("UTC")
|
||||
tm = tm.In(utc)
|
||||
result := Format("aaabbb0123456789%Y", tm)
|
||||
if result != "aaabbb01234567892012" {
|
||||
t.Logf("%s != %s", result, "aaabbb01234567892012")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestUnsupported(t *testing.T) {
|
||||
tm := time.Unix(1340244776, 0)
|
||||
utc, _ := time.LoadLocation("UTC")
|
||||
tm = tm.In(utc)
|
||||
result := Format("%0%1%%%2", tm)
|
||||
if result != "%0%1%%2" {
|
||||
t.Logf("%s != %s", result, "%0%1%%2")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
5
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/xtgo/uuid/AUTHORS
generated
vendored
Normal file
5
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/xtgo/uuid/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# This source file refers to The gocql Authors for copyright purposes.
|
||||
|
||||
Christoph Hack <christoph@tux21b.org>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Thorsten von Eicken <tve@rightscale.com>
|
||||
27
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/xtgo/uuid/LICENSE
generated
vendored
Normal file
27
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/xtgo/uuid/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 The gocql Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
204
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/xtgo/uuid/uuid.go
generated
vendored
Normal file
204
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/xtgo/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright (c) 2012 The gocql 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 uuid can be used to generate and parse universally unique
|
||||
// identifiers, a standardized format in the form of a 128 bit number.
|
||||
//
|
||||
// http://tools.ietf.org/html/rfc4122
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UUID [16]byte
|
||||
|
||||
var hardwareAddr []byte
|
||||
|
||||
const (
|
||||
VariantNCSCompat = 0
|
||||
VariantIETF = 2
|
||||
VariantMicrosoft = 6
|
||||
VariantFuture = 7
|
||||
)
|
||||
|
||||
func init() {
|
||||
if interfaces, err := net.Interfaces(); err == nil {
|
||||
for _, i := range interfaces {
|
||||
if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 {
|
||||
hardwareAddr = i.HardwareAddr
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if hardwareAddr == nil {
|
||||
// If we failed to obtain the MAC address of the current computer,
|
||||
// we will use a randomly generated 6 byte sequence instead and set
|
||||
// the multicast bit as recommended in RFC 4122.
|
||||
hardwareAddr = make([]byte, 6)
|
||||
_, err := io.ReadFull(rand.Reader, hardwareAddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
hardwareAddr[0] = hardwareAddr[0] | 0x01
|
||||
}
|
||||
}
|
||||
|
||||
// Parse parses a 32 digit hexadecimal number (that might contain hyphens)
|
||||
// representing an UUID.
|
||||
func Parse(input string) (UUID, error) {
|
||||
var u UUID
|
||||
j := 0
|
||||
for i := 0; i < len(input); i++ {
|
||||
b := input[i]
|
||||
switch {
|
||||
default:
|
||||
fallthrough
|
||||
case j == 32:
|
||||
goto err
|
||||
case b == '-':
|
||||
continue
|
||||
case '0' <= b && b <= '9':
|
||||
b -= '0'
|
||||
case 'a' <= b && b <= 'f':
|
||||
b -= 'a' - 10
|
||||
case 'A' <= b && b <= 'F':
|
||||
b -= 'A' - 10
|
||||
}
|
||||
u[j/2] |= b << byte(^j&1<<2)
|
||||
j++
|
||||
}
|
||||
if j == 32 {
|
||||
return u, nil
|
||||
}
|
||||
err:
|
||||
return UUID{}, errors.New("invalid UUID " + strconv.Quote(input))
|
||||
}
|
||||
|
||||
// FromBytes converts a raw byte slice to an UUID. It will panic if the slice
|
||||
// isn't exactly 16 bytes long.
|
||||
func FromBytes(input []byte) UUID {
|
||||
var u UUID
|
||||
if len(input) != 16 {
|
||||
panic("UUIDs must be exactly 16 bytes long")
|
||||
}
|
||||
copy(u[:], input)
|
||||
return u
|
||||
}
|
||||
|
||||
// NewRandom generates a totally random UUID (version 4) as described in
|
||||
// RFC 4122.
|
||||
func NewRandom() UUID {
|
||||
var u UUID
|
||||
io.ReadFull(rand.Reader, u[:])
|
||||
u[6] &= 0x0F // clear version
|
||||
u[6] |= 0x40 // set version to 4 (random uuid)
|
||||
u[8] &= 0x3F // clear variant
|
||||
u[8] |= 0x80 // set to IETF variant
|
||||
return u
|
||||
}
|
||||
|
||||
var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
|
||||
|
||||
// NewTime generates a new time based UUID (version 1) as described in RFC
|
||||
// 4122. This UUID contains the MAC address of the node that generated the
|
||||
// UUID, a timestamp and a sequence number.
|
||||
func NewTime() UUID {
|
||||
var u UUID
|
||||
|
||||
now := time.Now().In(time.UTC)
|
||||
t := uint64(now.Unix()-timeBase)*10000000 + uint64(now.Nanosecond()/100)
|
||||
u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
|
||||
u[4], u[5] = byte(t>>40), byte(t>>32)
|
||||
u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)
|
||||
|
||||
var clockSeq [2]byte
|
||||
io.ReadFull(rand.Reader, clockSeq[:])
|
||||
u[8] = clockSeq[1]
|
||||
u[9] = clockSeq[0]
|
||||
|
||||
copy(u[10:], hardwareAddr)
|
||||
|
||||
u[6] |= 0x10 // set version to 1 (time based uuid)
|
||||
u[8] &= 0x3F // clear variant
|
||||
u[8] |= 0x80 // set to IETF variant
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// String returns the UUID in it's canonical form, a 32 digit hexadecimal
|
||||
// number in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
|
||||
func (u UUID) String() string {
|
||||
buf := [36]byte{8: '-', 13: '-', 18: '-', 23: '-'}
|
||||
hex.Encode(buf[0:], u[0:4])
|
||||
hex.Encode(buf[9:], u[4:6])
|
||||
hex.Encode(buf[14:], u[6:8])
|
||||
hex.Encode(buf[19:], u[8:10])
|
||||
hex.Encode(buf[24:], u[10:])
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
// Bytes returns the raw byte slice for this UUID. A UUID is always 128 bits
|
||||
// (16 bytes) long.
|
||||
func (u UUID) Bytes() []byte {
|
||||
return u[:]
|
||||
}
|
||||
|
||||
// Variant returns the variant of this UUID. This package will only generate
|
||||
// UUIDs in the IETF variant.
|
||||
func (u UUID) Variant() int {
|
||||
x := u[8]
|
||||
switch byte(0) {
|
||||
case x & 0x80:
|
||||
return VariantNCSCompat
|
||||
case x & 0x40:
|
||||
return VariantIETF
|
||||
case x & 0x20:
|
||||
return VariantMicrosoft
|
||||
}
|
||||
return VariantFuture
|
||||
}
|
||||
|
||||
// Version extracts the version of this UUID variant. The RFC 4122 describes
|
||||
// five kinds of UUIDs.
|
||||
func (u UUID) Version() int {
|
||||
return int(u[6] & 0xF0 >> 4)
|
||||
}
|
||||
|
||||
// Node extracts the MAC address of the node who generated this UUID. It will
|
||||
// return nil if the UUID is not a time based UUID (version 1).
|
||||
func (u UUID) Node() []byte {
|
||||
if u.Version() != 1 {
|
||||
return nil
|
||||
}
|
||||
return u[10:]
|
||||
}
|
||||
|
||||
// Timestamp extracts the timestamp information from a time based UUID
|
||||
// (version 1).
|
||||
func (u UUID) Timestamp() uint64 {
|
||||
if u.Version() != 1 {
|
||||
return 0
|
||||
}
|
||||
return uint64(u[0])<<24 + uint64(u[1])<<16 + uint64(u[2])<<8 +
|
||||
uint64(u[3]) + uint64(u[4])<<40 + uint64(u[5])<<32 +
|
||||
uint64(u[7])<<48 + uint64(u[6]&0x0F)<<56
|
||||
}
|
||||
|
||||
// Time is like Timestamp, except that it returns a time.Time.
|
||||
func (u UUID) Time() time.Time {
|
||||
t := u.Timestamp()
|
||||
if t == 0 {
|
||||
return time.Time{}
|
||||
}
|
||||
sec := t / 10000000
|
||||
nsec := t - sec
|
||||
return time.Unix(int64(sec)+timeBase, int64(nsec))
|
||||
}
|
||||
102
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/xtgo/uuid/uuid_test.go
generated
vendored
Normal file
102
vendor/github.com/segmentio/analytics-go/Godeps/_workspace/src/github.com/xtgo/uuid/uuid_test.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2012 The gocql 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 uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNil(t *testing.T) {
|
||||
var uuid UUID
|
||||
want, got := "00000000-0000-0000-0000-000000000000", uuid.String()
|
||||
if want != got {
|
||||
t.Fatalf("TestNil: expected %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
input string
|
||||
variant int
|
||||
version int
|
||||
}{
|
||||
{"b4f00409-cef8-4822-802c-deb20704c365", VariantIETF, 4},
|
||||
{"f81d4fae-7dec-11d0-a765-00a0c91e6bf6", VariantIETF, 1},
|
||||
{"00000000-7dec-11d0-a765-00a0c91e6bf6", VariantIETF, 1},
|
||||
{"3051a8d7-aea7-1801-e0bf-bc539dd60cf3", VariantFuture, 1},
|
||||
{"3051a8d7-aea7-2801-e0bf-bc539dd60cf3", VariantFuture, 2},
|
||||
{"3051a8d7-aea7-3801-e0bf-bc539dd60cf3", VariantFuture, 3},
|
||||
{"3051a8d7-aea7-4801-e0bf-bc539dd60cf3", VariantFuture, 4},
|
||||
{"3051a8d7-aea7-3801-e0bf-bc539dd60cf3", VariantFuture, 5},
|
||||
{"d0e817e1-e4b1-1801-3fe6-b4b60ccecf9d", VariantNCSCompat, 0},
|
||||
{"d0e817e1-e4b1-1801-bfe6-b4b60ccecf9d", VariantIETF, 1},
|
||||
{"d0e817e1-e4b1-1801-dfe6-b4b60ccecf9d", VariantMicrosoft, 0},
|
||||
{"d0e817e1-e4b1-1801-ffe6-b4b60ccecf9d", VariantFuture, 0},
|
||||
}
|
||||
|
||||
func TestPredefined(t *testing.T) {
|
||||
for i := range tests {
|
||||
uuid, err := Parse(tests[i].input)
|
||||
if err != nil {
|
||||
t.Errorf("Parse #%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if str := uuid.String(); str != tests[i].input {
|
||||
t.Errorf("String #%d: expected %q got %q", i, tests[i].input, str)
|
||||
continue
|
||||
}
|
||||
|
||||
if variant := uuid.Variant(); variant != tests[i].variant {
|
||||
t.Errorf("Variant #%d: expected %d got %d", i, tests[i].variant, variant)
|
||||
}
|
||||
|
||||
if tests[i].variant == VariantIETF {
|
||||
if version := uuid.Version(); version != tests[i].version {
|
||||
t.Errorf("Version #%d: expected %d got %d", i, tests[i].version, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRandom(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
uuid := NewRandom()
|
||||
|
||||
if variant := uuid.Variant(); variant != VariantIETF {
|
||||
t.Errorf("wrong variant. expected %d got %d", VariantIETF, variant)
|
||||
}
|
||||
if version := uuid.Version(); version != 4 {
|
||||
t.Errorf("wrong version. expected %d got %d", 4, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTime(t *testing.T) {
|
||||
var node []byte
|
||||
timestamp := uint64(0)
|
||||
for i := 0; i < 20; i++ {
|
||||
uuid := NewTime()
|
||||
|
||||
if variant := uuid.Variant(); variant != VariantIETF {
|
||||
t.Errorf("wrong variant. expected %d got %d", VariantIETF, variant)
|
||||
}
|
||||
if version := uuid.Version(); version != 1 {
|
||||
t.Errorf("wrong version. expected %d got %d", 1, version)
|
||||
}
|
||||
|
||||
if n := uuid.Node(); !bytes.Equal(n, node) && i > 0 {
|
||||
t.Errorf("wrong node. expected %x, got %x", node, n)
|
||||
} else if i == 0 {
|
||||
node = n
|
||||
}
|
||||
|
||||
ts := uuid.Timestamp()
|
||||
if ts < timestamp {
|
||||
t.Errorf("timestamps must grow")
|
||||
}
|
||||
timestamp = ts
|
||||
}
|
||||
}
|
||||
67
vendor/github.com/segmentio/analytics-go/History.md
generated
vendored
Normal file
67
vendor/github.com/segmentio/analytics-go/History.md
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
v2.1.1 / 2016-04-26
|
||||
===================
|
||||
|
||||
* Fix blocking the goroutine when Close is the first call.
|
||||
* Fix blocking the goroutine when the message queue fills up.
|
||||
|
||||
v2.1.0 / 2015-12-28
|
||||
===================
|
||||
|
||||
* Add ability to set custom timestamps for messages.
|
||||
* Add ability to set a custom `net/http` client.
|
||||
* Add ability to set a custom logger.
|
||||
* Fix edge case when client would try to upload no messages.
|
||||
* Properly upload in-flight messages when client is asked to shutdown.
|
||||
* Add ability to set `.integrations` field on messages.
|
||||
* Fix resource leak with interval ticker after shutdown.
|
||||
* Add retries and back-off when uploading messages.
|
||||
* Add ability to set custom flush interval.
|
||||
|
||||
v2.0.0 / 2015-02-03
|
||||
===================
|
||||
|
||||
* rewrite with breaking API changes
|
||||
|
||||
v1.2.0 / 2014-09-03
|
||||
==================
|
||||
|
||||
* add public .Flush() method
|
||||
* rename .Stop() to .Close()
|
||||
|
||||
v1.1.0 / 2014-09-02
|
||||
==================
|
||||
|
||||
* add client.Stop() to flash/wait. Closes #7
|
||||
|
||||
v1.0.0 / 2014-08-26
|
||||
==================
|
||||
|
||||
* fix response close
|
||||
* change comments to be more go-like
|
||||
* change uuid libraries
|
||||
|
||||
0.1.2 / 2014-06-11
|
||||
==================
|
||||
|
||||
* add runnable example
|
||||
* fix: close body
|
||||
|
||||
0.1.1 / 2014-05-31
|
||||
==================
|
||||
|
||||
* refactor locking
|
||||
|
||||
0.1.0 / 2014-05-22
|
||||
==================
|
||||
|
||||
* replace Debug option with debug package
|
||||
|
||||
0.0.2 / 2014-05-20
|
||||
==================
|
||||
|
||||
* add .Start()
|
||||
* add mutexes
|
||||
* rename BufferSize to FlushAt and FlushInterval to FlushAfter
|
||||
* lower FlushInterval to 5 seconds
|
||||
* lower BufferSize to 20 to match other clients
|
||||
10
vendor/github.com/segmentio/analytics-go/Makefile
generated
vendored
Normal file
10
vendor/github.com/segmentio/analytics-go/Makefile
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
vet:
|
||||
@godep go vet ./...
|
||||
|
||||
build:
|
||||
@godep go build
|
||||
|
||||
test:
|
||||
@godep go test -race -cover ./...
|
||||
|
||||
.PHONY: vet build test
|
||||
8
vendor/github.com/segmentio/analytics-go/Readme.md
generated
vendored
Normal file
8
vendor/github.com/segmentio/analytics-go/Readme.md
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# analytics-go
|
||||
|
||||
Segment analytics client for Go. For additional documentation
|
||||
visit [https://segment.com/docs/libraries/go](https://segment.com/docs/libraries/go/) or view the [godocs](http://godoc.org/github.com/segmentio/analytics-go).
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
407
vendor/github.com/segmentio/analytics-go/analytics.go
generated
vendored
Normal file
407
vendor/github.com/segmentio/analytics-go/analytics.go
generated
vendored
Normal file
@@ -0,0 +1,407 @@
|
||||
package analytics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jehiah/go-strftime"
|
||||
"github.com/segmentio/backo-go"
|
||||
"github.com/xtgo/uuid"
|
||||
)
|
||||
|
||||
// Version of the client.
|
||||
const Version = "2.1.0"
|
||||
|
||||
// Endpoint for the Segment API.
|
||||
const Endpoint = "https://api.segment.io"
|
||||
|
||||
// DefaultContext of message batches.
|
||||
var DefaultContext = map[string]interface{}{
|
||||
"library": map[string]interface{}{
|
||||
"name": "analytics-go",
|
||||
"version": Version,
|
||||
},
|
||||
}
|
||||
|
||||
// Backoff policy.
|
||||
var Backo = backo.DefaultBacko()
|
||||
|
||||
// Message interface.
|
||||
type message interface {
|
||||
setMessageId(string)
|
||||
setTimestamp(string)
|
||||
}
|
||||
|
||||
// Message fields common to all.
|
||||
type Message struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
MessageId string `json:"messageId,omitempty"`
|
||||
Timestamp string `json:"timestamp,omitempty"`
|
||||
SentAt string `json:"sentAt,omitempty"`
|
||||
}
|
||||
|
||||
// Batch message.
|
||||
type Batch struct {
|
||||
Context map[string]interface{} `json:"context,omitempty"`
|
||||
Messages []interface{} `json:"batch"`
|
||||
Message
|
||||
}
|
||||
|
||||
// Identify message.
|
||||
type Identify struct {
|
||||
Context map[string]interface{} `json:"context,omitempty"`
|
||||
Integrations map[string]interface{} `json:"integrations,omitempty"`
|
||||
Traits map[string]interface{} `json:"traits,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
Message
|
||||
}
|
||||
|
||||
// Group message.
|
||||
type Group struct {
|
||||
Context map[string]interface{} `json:"context,omitempty"`
|
||||
Integrations map[string]interface{} `json:"integrations,omitempty"`
|
||||
Traits map[string]interface{} `json:"traits,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
GroupId string `json:"groupId"`
|
||||
Message
|
||||
}
|
||||
|
||||
// Track message.
|
||||
type Track struct {
|
||||
Context map[string]interface{} `json:"context,omitempty"`
|
||||
Integrations map[string]interface{} `json:"integrations,omitempty"`
|
||||
Properties map[string]interface{} `json:"properties,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
Event string `json:"event"`
|
||||
Message
|
||||
}
|
||||
|
||||
// Page message.
|
||||
type Page struct {
|
||||
Context map[string]interface{} `json:"context,omitempty"`
|
||||
Integrations map[string]interface{} `json:"integrations,omitempty"`
|
||||
Traits map[string]interface{} `json:"properties,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
Category string `json:"category,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Message
|
||||
}
|
||||
|
||||
// Alias message.
|
||||
type Alias struct {
|
||||
PreviousId string `json:"previousId"`
|
||||
UserId string `json:"userId"`
|
||||
Message
|
||||
}
|
||||
|
||||
// Client which batches messages and flushes at the given Interval or
|
||||
// when the Size limit is exceeded. Set Verbose to true to enable
|
||||
// logging output.
|
||||
type Client struct {
|
||||
Endpoint string
|
||||
// Interval represents the duration at which messages are flushed. It may be
|
||||
// configured only before any messages are enqueued.
|
||||
Interval time.Duration
|
||||
Size int
|
||||
Logger *log.Logger
|
||||
Verbose bool
|
||||
Client http.Client
|
||||
key string
|
||||
msgs chan interface{}
|
||||
quit chan struct{}
|
||||
shutdown chan struct{}
|
||||
uid func() string
|
||||
now func() time.Time
|
||||
once sync.Once
|
||||
wg sync.WaitGroup
|
||||
|
||||
// These synchronization primitives are used to control how many goroutines
|
||||
// are spawned by the client for uploads.
|
||||
upmtx sync.Mutex
|
||||
upcond sync.Cond
|
||||
upcount int
|
||||
}
|
||||
|
||||
// New client with write key.
|
||||
func New(key string) *Client {
|
||||
c := &Client{
|
||||
Endpoint: Endpoint,
|
||||
Interval: 5 * time.Second,
|
||||
Size: 250,
|
||||
Logger: log.New(os.Stderr, "segment ", log.LstdFlags),
|
||||
Verbose: false,
|
||||
Client: *http.DefaultClient,
|
||||
key: key,
|
||||
msgs: make(chan interface{}, 100),
|
||||
quit: make(chan struct{}),
|
||||
shutdown: make(chan struct{}),
|
||||
now: time.Now,
|
||||
uid: uid,
|
||||
}
|
||||
|
||||
c.upcond.L = &c.upmtx
|
||||
return c
|
||||
}
|
||||
|
||||
// Alias buffers an "alias" message.
|
||||
func (c *Client) Alias(msg *Alias) error {
|
||||
if msg.UserId == "" {
|
||||
return errors.New("You must pass a 'userId'.")
|
||||
}
|
||||
|
||||
if msg.PreviousId == "" {
|
||||
return errors.New("You must pass a 'previousId'.")
|
||||
}
|
||||
|
||||
msg.Type = "alias"
|
||||
c.queue(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Page buffers an "page" message.
|
||||
func (c *Client) Page(msg *Page) error {
|
||||
if msg.UserId == "" && msg.AnonymousId == "" {
|
||||
return errors.New("You must pass either an 'anonymousId' or 'userId'.")
|
||||
}
|
||||
|
||||
msg.Type = "page"
|
||||
c.queue(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Group buffers an "group" message.
|
||||
func (c *Client) Group(msg *Group) error {
|
||||
if msg.GroupId == "" {
|
||||
return errors.New("You must pass a 'groupId'.")
|
||||
}
|
||||
|
||||
if msg.UserId == "" && msg.AnonymousId == "" {
|
||||
return errors.New("You must pass either an 'anonymousId' or 'userId'.")
|
||||
}
|
||||
|
||||
msg.Type = "group"
|
||||
c.queue(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Identify buffers an "identify" message.
|
||||
func (c *Client) Identify(msg *Identify) error {
|
||||
if msg.UserId == "" && msg.AnonymousId == "" {
|
||||
return errors.New("You must pass either an 'anonymousId' or 'userId'.")
|
||||
}
|
||||
|
||||
msg.Type = "identify"
|
||||
c.queue(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Track buffers an "track" message.
|
||||
func (c *Client) Track(msg *Track) error {
|
||||
if msg.Event == "" {
|
||||
return errors.New("You must pass 'event'.")
|
||||
}
|
||||
|
||||
if msg.UserId == "" && msg.AnonymousId == "" {
|
||||
return errors.New("You must pass either an 'anonymousId' or 'userId'.")
|
||||
}
|
||||
|
||||
msg.Type = "track"
|
||||
c.queue(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) startLoop() {
|
||||
go c.loop()
|
||||
}
|
||||
|
||||
// Queue message.
|
||||
func (c *Client) queue(msg message) {
|
||||
c.once.Do(c.startLoop)
|
||||
msg.setMessageId(c.uid())
|
||||
msg.setTimestamp(timestamp(c.now()))
|
||||
c.msgs <- msg
|
||||
}
|
||||
|
||||
// Close and flush metrics.
|
||||
func (c *Client) Close() error {
|
||||
c.once.Do(c.startLoop)
|
||||
c.quit <- struct{}{}
|
||||
close(c.msgs)
|
||||
<-c.shutdown
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) sendAsync(msgs []interface{}) {
|
||||
c.upmtx.Lock()
|
||||
for c.upcount == 1000 {
|
||||
c.upcond.Wait()
|
||||
}
|
||||
c.upcount++
|
||||
c.upmtx.Unlock()
|
||||
c.wg.Add(1)
|
||||
go func() {
|
||||
err := c.send(msgs)
|
||||
if err != nil {
|
||||
c.logf(err.Error())
|
||||
}
|
||||
c.upmtx.Lock()
|
||||
c.upcount--
|
||||
c.upcond.Signal()
|
||||
c.upmtx.Unlock()
|
||||
c.wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Send batch request.
|
||||
func (c *Client) send(msgs []interface{}) error {
|
||||
if len(msgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
batch := new(Batch)
|
||||
batch.Messages = msgs
|
||||
batch.MessageId = c.uid()
|
||||
batch.SentAt = timestamp(c.now())
|
||||
batch.Context = DefaultContext
|
||||
|
||||
b, err := json.Marshal(batch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling msgs: %s", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
if err = c.upload(b); err == nil {
|
||||
return nil
|
||||
}
|
||||
Backo.Sleep(i)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Upload serialized batch message.
|
||||
func (c *Client) upload(b []byte) error {
|
||||
url := c.Endpoint + "/v1/batch"
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating request: %s", err)
|
||||
}
|
||||
|
||||
req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Content-Length", string(len(b)))
|
||||
req.SetBasicAuth(c.key, "")
|
||||
|
||||
res, err := c.Client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error sending request: %s", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode < 400 {
|
||||
c.verbose("response %s", res.Status)
|
||||
return nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading response body: %s", err)
|
||||
}
|
||||
|
||||
return fmt.Errorf("response %s: %d – %s", res.Status, res.StatusCode, string(body))
|
||||
}
|
||||
|
||||
// Batch loop.
|
||||
func (c *Client) loop() {
|
||||
var msgs []interface{}
|
||||
tick := time.NewTicker(c.Interval)
|
||||
|
||||
for {
|
||||
select {
|
||||
case msg := <-c.msgs:
|
||||
c.verbose("buffer (%d/%d) %v", len(msgs), c.Size, msg)
|
||||
msgs = append(msgs, msg)
|
||||
if len(msgs) == c.Size {
|
||||
c.verbose("exceeded %d messages – flushing", c.Size)
|
||||
c.sendAsync(msgs)
|
||||
msgs = make([]interface{}, 0, c.Size)
|
||||
}
|
||||
case <-tick.C:
|
||||
if len(msgs) > 0 {
|
||||
c.verbose("interval reached - flushing %d", len(msgs))
|
||||
c.sendAsync(msgs)
|
||||
msgs = make([]interface{}, 0, c.Size)
|
||||
} else {
|
||||
c.verbose("interval reached – nothing to send")
|
||||
}
|
||||
case <-c.quit:
|
||||
tick.Stop()
|
||||
c.verbose("exit requested – draining msgs")
|
||||
// drain the msg channel.
|
||||
for msg := range c.msgs {
|
||||
c.verbose("buffer (%d/%d) %v", len(msgs), c.Size, msg)
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
c.verbose("exit requested – flushing %d", len(msgs))
|
||||
c.sendAsync(msgs)
|
||||
c.wg.Wait()
|
||||
c.verbose("exit")
|
||||
c.shutdown <- struct{}{}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verbose log.
|
||||
func (c *Client) verbose(msg string, args ...interface{}) {
|
||||
if c.Verbose {
|
||||
c.Logger.Printf(msg, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Unconditional log.
|
||||
func (c *Client) logf(msg string, args ...interface{}) {
|
||||
c.Logger.Printf(msg, args...)
|
||||
}
|
||||
|
||||
// Set message timestamp if one is not already set.
|
||||
func (m *Message) setTimestamp(s string) {
|
||||
if m.Timestamp == "" {
|
||||
m.Timestamp = s
|
||||
}
|
||||
}
|
||||
|
||||
// Set message id.
|
||||
func (m *Message) setMessageId(s string) {
|
||||
if m.MessageId == "" {
|
||||
m.MessageId = s
|
||||
}
|
||||
}
|
||||
|
||||
// Return formatted timestamp.
|
||||
func timestamp(t time.Time) string {
|
||||
return strftime.Format("%Y-%m-%dT%H:%M:%S%z", t)
|
||||
}
|
||||
|
||||
// Return uuid string.
|
||||
func uid() string {
|
||||
return uuid.NewRandom().String()
|
||||
}
|
||||
478
vendor/github.com/segmentio/analytics-go/analytics_test.go
generated
vendored
Normal file
478
vendor/github.com/segmentio/analytics-go/analytics_test.go
generated
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
package analytics
|
||||
|
||||
import "net/http/httptest"
|
||||
import "encoding/json"
|
||||
import "net/http"
|
||||
import "testing"
|
||||
import "bytes"
|
||||
import "time"
|
||||
import "fmt"
|
||||
import "io"
|
||||
|
||||
func mockId() string { return "I'm unique" }
|
||||
|
||||
func mockTime() time.Time {
|
||||
// time.Unix(0, 0) fails on Circle
|
||||
return time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
}
|
||||
|
||||
func mockServer() (chan []byte, *httptest.Server) {
|
||||
done := make(chan []byte, 1)
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
io.Copy(buf, r.Body)
|
||||
|
||||
var v interface{}
|
||||
err := json.Unmarshal(buf.Bytes(), &v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
done <- b
|
||||
}))
|
||||
|
||||
return done, server
|
||||
}
|
||||
|
||||
func ExampleTrack() {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
|
||||
client := New("h97jamjwbh")
|
||||
client.Endpoint = server.URL
|
||||
client.now = mockTime
|
||||
client.uid = mockId
|
||||
client.Size = 1
|
||||
|
||||
client.Track(&Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": "1.1.0",
|
||||
"platform": "osx",
|
||||
},
|
||||
})
|
||||
|
||||
fmt.Printf("%s\n", <-body)
|
||||
// Output:
|
||||
// {
|
||||
// "batch": [
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "platform": "osx",
|
||||
// "version": "1.1.0"
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// }
|
||||
// ],
|
||||
// "context": {
|
||||
// "library": {
|
||||
// "name": "analytics-go",
|
||||
// "version": "2.1.0"
|
||||
// }
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "sentAt": "2009-11-10T23:00:00+0000"
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleClose() {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
|
||||
client := New("h97jamjwbh")
|
||||
client.Endpoint = server.URL
|
||||
client.now = mockTime
|
||||
client.uid = mockId
|
||||
|
||||
client.Track(&Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": "1.1.0",
|
||||
"platform": "osx",
|
||||
},
|
||||
})
|
||||
|
||||
client.Close()
|
||||
|
||||
fmt.Printf("%s\n", <-body)
|
||||
// Output:
|
||||
// {
|
||||
// "batch": [
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "platform": "osx",
|
||||
// "version": "1.1.0"
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// }
|
||||
// ],
|
||||
// "context": {
|
||||
// "library": {
|
||||
// "name": "analytics-go",
|
||||
// "version": "2.1.0"
|
||||
// }
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "sentAt": "2009-11-10T23:00:00+0000"
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleInterval() {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
|
||||
client := New("h97jamjwbh")
|
||||
client.Endpoint = server.URL
|
||||
client.now = mockTime
|
||||
client.uid = mockId
|
||||
|
||||
client.Track(&Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": "1.1.0",
|
||||
"platform": "osx",
|
||||
},
|
||||
})
|
||||
|
||||
// Will flush in 5 seconds (default interval).
|
||||
fmt.Printf("%s\n", <-body)
|
||||
// Output:
|
||||
// {
|
||||
// "batch": [
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "platform": "osx",
|
||||
// "version": "1.1.0"
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// }
|
||||
// ],
|
||||
// "context": {
|
||||
// "library": {
|
||||
// "name": "analytics-go",
|
||||
// "version": "2.1.0"
|
||||
// }
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "sentAt": "2009-11-10T23:00:00+0000"
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleTrackWithTimestampSet() {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
|
||||
client := New("h97jamjwbh")
|
||||
client.Endpoint = server.URL
|
||||
client.now = mockTime
|
||||
client.uid = mockId
|
||||
client.Size = 1
|
||||
|
||||
client.Track(&Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": "1.1.0",
|
||||
"platform": "osx",
|
||||
},
|
||||
Message: Message{
|
||||
Timestamp: timestamp(time.Date(2015, time.July, 10, 23, 0, 0, 0, time.UTC)),
|
||||
},
|
||||
})
|
||||
|
||||
fmt.Printf("%s\n", <-body)
|
||||
// Output:
|
||||
// {
|
||||
// "batch": [
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "platform": "osx",
|
||||
// "version": "1.1.0"
|
||||
// },
|
||||
// "timestamp": "2015-07-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// }
|
||||
// ],
|
||||
// "context": {
|
||||
// "library": {
|
||||
// "name": "analytics-go",
|
||||
// "version": "2.1.0"
|
||||
// }
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "sentAt": "2009-11-10T23:00:00+0000"
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleTrackWithMessageIdSet() {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
|
||||
client := New("h97jamjwbh")
|
||||
client.Endpoint = server.URL
|
||||
client.now = mockTime
|
||||
client.uid = mockId
|
||||
client.Size = 1
|
||||
|
||||
client.Track(&Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": "1.1.0",
|
||||
"platform": "osx",
|
||||
},
|
||||
Message: Message{
|
||||
MessageId: "abc",
|
||||
},
|
||||
})
|
||||
|
||||
fmt.Printf("%s\n", <-body)
|
||||
// Output:
|
||||
// {
|
||||
// "batch": [
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "messageId": "abc",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "platform": "osx",
|
||||
// "version": "1.1.0"
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// }
|
||||
// ],
|
||||
// "context": {
|
||||
// "library": {
|
||||
// "name": "analytics-go",
|
||||
// "version": "2.1.0"
|
||||
// }
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "sentAt": "2009-11-10T23:00:00+0000"
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleTrack_context() {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
|
||||
client := New("h97jamjwbh")
|
||||
client.Endpoint = server.URL
|
||||
client.now = mockTime
|
||||
client.uid = mockId
|
||||
client.Size = 1
|
||||
|
||||
client.Track(&Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": "1.1.0",
|
||||
"platform": "osx",
|
||||
},
|
||||
Context: map[string]interface{}{
|
||||
"whatever": "here",
|
||||
},
|
||||
})
|
||||
|
||||
fmt.Printf("%s\n", <-body)
|
||||
// Output:
|
||||
// {
|
||||
// "batch": [
|
||||
// {
|
||||
// "context": {
|
||||
// "whatever": "here"
|
||||
// },
|
||||
// "event": "Download",
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "platform": "osx",
|
||||
// "version": "1.1.0"
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// }
|
||||
// ],
|
||||
// "context": {
|
||||
// "library": {
|
||||
// "name": "analytics-go",
|
||||
// "version": "2.1.0"
|
||||
// }
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "sentAt": "2009-11-10T23:00:00+0000"
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleTrack_many() {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
|
||||
client := New("h97jamjwbh")
|
||||
client.Endpoint = server.URL
|
||||
client.now = mockTime
|
||||
client.uid = mockId
|
||||
client.Size = 3
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
client.Track(&Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": i,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", <-body)
|
||||
// Output:
|
||||
// {
|
||||
// "batch": [
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "version": 0
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// },
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "version": 1
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// },
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "version": 2
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// }
|
||||
// ],
|
||||
// "context": {
|
||||
// "library": {
|
||||
// "name": "analytics-go",
|
||||
// "version": "2.1.0"
|
||||
// }
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "sentAt": "2009-11-10T23:00:00+0000"
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleTrackWithIntegrations() {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
|
||||
client := New("h97jamjwbh")
|
||||
client.Endpoint = server.URL
|
||||
client.now = mockTime
|
||||
client.uid = mockId
|
||||
client.Size = 1
|
||||
|
||||
client.Track(&Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": "1.1.0",
|
||||
"platform": "osx",
|
||||
},
|
||||
Integrations: map[string]interface{}{
|
||||
"All": true,
|
||||
"Intercom": false,
|
||||
"Mixpanel": true,
|
||||
},
|
||||
})
|
||||
|
||||
fmt.Printf("%s\n", <-body)
|
||||
// Output:
|
||||
// {
|
||||
// "batch": [
|
||||
// {
|
||||
// "event": "Download",
|
||||
// "integrations": {
|
||||
// "All": true,
|
||||
// "Intercom": false,
|
||||
// "Mixpanel": true
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "properties": {
|
||||
// "application": "Segment Desktop",
|
||||
// "platform": "osx",
|
||||
// "version": "1.1.0"
|
||||
// },
|
||||
// "timestamp": "2009-11-10T23:00:00+0000",
|
||||
// "type": "track",
|
||||
// "userId": "123456"
|
||||
// }
|
||||
// ],
|
||||
// "context": {
|
||||
// "library": {
|
||||
// "name": "analytics-go",
|
||||
// "version": "2.1.0"
|
||||
// }
|
||||
// },
|
||||
// "messageId": "I'm unique",
|
||||
// "sentAt": "2009-11-10T23:00:00+0000"
|
||||
// }
|
||||
}
|
||||
|
||||
// Tests that calling Close right after creating the client object doesn't
|
||||
// block.
|
||||
// Bug: https://github.com/segmentio/analytics-go/issues/43
|
||||
func TestCloseFinish(_ *testing.T) {
|
||||
c := New("test")
|
||||
c.Close()
|
||||
}
|
||||
18
vendor/github.com/segmentio/analytics-go/circle.yml
generated
vendored
Normal file
18
vendor/github.com/segmentio/analytics-go/circle.yml
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
machine:
|
||||
environment:
|
||||
IMPORT_PATH: "github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- go get github.com/tools/godep
|
||||
|
||||
override:
|
||||
- mkdir -p "$GOPATH/src/$IMPORT_PATH"
|
||||
- rsync -azC --delete ./ "$GOPATH/src/$IMPORT_PATH/"
|
||||
|
||||
test:
|
||||
pre:
|
||||
- make vet
|
||||
|
||||
override:
|
||||
- make test
|
||||
174
vendor/github.com/segmentio/analytics-go/cli/cli.go
generated
vendored
Normal file
174
vendor/github.com/segmentio/analytics-go/cli/cli.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/segmentio/analytics-go"
|
||||
"github.com/tj/docopt"
|
||||
)
|
||||
|
||||
const Usage = `
|
||||
Analytics Go CLI
|
||||
|
||||
Usage:
|
||||
analytics track <event> [--properties=<properties>] [--context=<context>] [--writeKey=<writeKey>] [--userId=<userId>] [--anonymousId=<anonymousId>] [--integrations=<integrations>] [--timestamp=<timestamp>]
|
||||
analytics screen <name> [--properties=<properties>] [--context=<context>] [--writeKey=<writeKey>] [--userId=<userId>] [--anonymousId=<anonymousId>] [--integrations=<integrations>] [--timestamp=<timestamp>]
|
||||
analytics page <name> [--properties=<properties>] [--context=<context>] [--writeKey=<writeKey>] [--userId=<userId>] [--anonymousId=<anonymousId>] [--integrations=<integrations>] [--timestamp=<timestamp>]
|
||||
analytics identify [--traits=<traits>] [--context=<context>] [--writeKey=<writeKey>] [--userId=<userId>] [--anonymousId=<anonymousId>] [--integrations=<integrations>] [--timestamp=<timestamp>]
|
||||
analytics group --groupId=<groupId> [--traits=<traits>] [--properties=<properties>] [--context=<context>] [--writeKey=<writeKey>] [--userId=<userId>] [--anonymousId=<anonymousId>] [--integrations=<integrations>] [--timestamp=<timestamp>]
|
||||
analytics alias --userId=<userId> --previousId=<previousId> [--traits=<traits>] [--properties=<properties>] [--context=<context>] [--writeKey=<writeKey>] [--anonymousId=<anonymousId>] [--integrations=<integrations>] [--timestamp=<timestamp>]
|
||||
analytics -h | --help
|
||||
analytics --version
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Show version.
|
||||
`
|
||||
|
||||
func main() {
|
||||
arguments, err := docopt.Parse(Usage, nil, true, "Anaytics Go CLI", false)
|
||||
check(err)
|
||||
|
||||
writeKey := getOptionalString(arguments, "--writeKey")
|
||||
if writeKey == "" {
|
||||
writeKey = os.Getenv("SEGMENT_WRITE_KEY")
|
||||
if writeKey == "" {
|
||||
log.Fatal("either $SEGMENT_WRITE_KEY or --writeKey must be provided")
|
||||
}
|
||||
}
|
||||
|
||||
client := analytics.New(writeKey)
|
||||
client.Size = 1
|
||||
client.Verbose = true
|
||||
|
||||
if arguments["track"].(bool) {
|
||||
m := &analytics.Track{
|
||||
Event: arguments["<event>"].(string),
|
||||
}
|
||||
properties := getOptionalString(arguments, "--properties")
|
||||
if properties != "" {
|
||||
var parsedProperties map[string]interface{}
|
||||
err := json.Unmarshal([]byte(properties), &parsedProperties)
|
||||
check(err)
|
||||
m.Properties = parsedProperties
|
||||
}
|
||||
|
||||
setCommonFields(m, arguments)
|
||||
|
||||
check(client.Track(m))
|
||||
}
|
||||
|
||||
if arguments["screen"].(bool) || arguments["page"].(bool) {
|
||||
m := &analytics.Page{
|
||||
Name: arguments["<name>"].(string),
|
||||
}
|
||||
/* Bug in Go library - page has traits not properties.
|
||||
properties := getOptionalString(arguments, "--properties")
|
||||
if properties != "" {
|
||||
var parsedProperties map[string]interface{}
|
||||
err := json.Unmarshal([]byte(properties), &parsedProperties)
|
||||
check(err)
|
||||
t.Properties = parsedProperties
|
||||
}
|
||||
*/
|
||||
|
||||
setCommonFields(m, arguments)
|
||||
|
||||
check(client.Page(m))
|
||||
}
|
||||
|
||||
if arguments["identify"].(bool) {
|
||||
m := &analytics.Identify{}
|
||||
traits := getOptionalString(arguments, "--traits")
|
||||
if traits != "" {
|
||||
var parsedTraits map[string]interface{}
|
||||
err := json.Unmarshal([]byte(traits), &parsedTraits)
|
||||
check(err)
|
||||
m.Traits = parsedTraits
|
||||
}
|
||||
|
||||
setCommonFields(m, arguments)
|
||||
|
||||
check(client.Identify(m))
|
||||
}
|
||||
|
||||
if arguments["group"].(bool) {
|
||||
m := &analytics.Group{
|
||||
GroupId: arguments["--groupId"].(string),
|
||||
}
|
||||
traits := getOptionalString(arguments, "--traits")
|
||||
if traits != "" {
|
||||
var parsedTraits map[string]interface{}
|
||||
err := json.Unmarshal([]byte(traits), &parsedTraits)
|
||||
check(err)
|
||||
m.Traits = parsedTraits
|
||||
}
|
||||
|
||||
setCommonFields(m, arguments)
|
||||
|
||||
check(client.Group(m))
|
||||
}
|
||||
|
||||
if arguments["alias"].(bool) {
|
||||
m := &analytics.Alias{
|
||||
PreviousId: arguments["--previousId"].(string),
|
||||
}
|
||||
|
||||
setCommonFields(m, arguments)
|
||||
|
||||
check(client.Alias(m))
|
||||
}
|
||||
|
||||
client.Close()
|
||||
}
|
||||
|
||||
func setCommonFields(message interface{}, arguments map[string]interface{}) {
|
||||
userId := getOptionalString(arguments, "--userId")
|
||||
if userId != "" {
|
||||
setFieldValue(message, "UserId", userId)
|
||||
}
|
||||
anonymousId := getOptionalString(arguments, "--anonymousId")
|
||||
if anonymousId != "" {
|
||||
setFieldValue(message, "AnonymousId", anonymousId)
|
||||
}
|
||||
integrations := getOptionalString(arguments, "--integrations")
|
||||
if integrations != "" {
|
||||
var parsedIntegrations map[string]interface{}
|
||||
err := json.Unmarshal([]byte(integrations), &parsedIntegrations)
|
||||
check(err)
|
||||
setFieldValue(message, "Integrations", parsedIntegrations)
|
||||
}
|
||||
context := getOptionalString(arguments, "--context")
|
||||
if context != "" {
|
||||
var parsedContext map[string]interface{}
|
||||
err := json.Unmarshal([]byte(context), &parsedContext)
|
||||
check(err)
|
||||
setFieldValue(message, "Context", parsedContext)
|
||||
|
||||
}
|
||||
timestamp := getOptionalString(arguments, "--timestamp")
|
||||
if timestamp != "" {
|
||||
setFieldValue(message, "Timestamp", timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
func setFieldValue(target interface{}, field string, value interface{}) {
|
||||
reflect.ValueOf(target).Elem().FieldByName(field).Set(reflect.ValueOf(value))
|
||||
}
|
||||
|
||||
func getOptionalString(m map[string]interface{}, k string) string {
|
||||
v := m[k]
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return v.(string)
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
36
vendor/github.com/segmentio/analytics-go/examples/track.go
generated
vendored
Normal file
36
vendor/github.com/segmentio/analytics-go/examples/track.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import "github.com/segmentio/analytics-go"
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
client := analytics.New("h97jamjwbh")
|
||||
client.Interval = 30 * time.Second
|
||||
client.Size = 100
|
||||
client.Verbose = true
|
||||
|
||||
done := time.After(3 * time.Second)
|
||||
tick := time.Tick(50 * time.Millisecond)
|
||||
|
||||
out:
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
println("exiting")
|
||||
break out
|
||||
case <-tick:
|
||||
client.Track(&analytics.Track{
|
||||
Event: "Download",
|
||||
UserId: "123456",
|
||||
Properties: map[string]interface{}{
|
||||
"application": "Segment Desktop",
|
||||
"version": "1.1.0",
|
||||
"platform": "osx",
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
println("flushing")
|
||||
client.Close()
|
||||
}
|
||||
80
vendor/github.com/segmentio/backo-go/README.md
generated
vendored
Normal file
80
vendor/github.com/segmentio/backo-go/README.md
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
Backo [](http://godoc.org/github.com/segmentio/backo-go)
|
||||
-----
|
||||
|
||||
Exponential backoff for Go (Go port of segmentio/backo).
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
```go
|
||||
import "github.com/segmentio/backo-go"
|
||||
|
||||
// Create a Backo instance.
|
||||
backo := backo.NewBacko(milliseconds(100), 2, 1, milliseconds(10*1000))
|
||||
// OR with defaults.
|
||||
backo := backo.DefaultBacko()
|
||||
|
||||
// Use the ticker API.
|
||||
ticker := b.NewTicker()
|
||||
for {
|
||||
timeout := time.After(5 * time.Minute)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
fmt.Println("ticked")
|
||||
case <- timeout:
|
||||
fmt.Println("timed out")
|
||||
}
|
||||
}
|
||||
|
||||
// Or simply work with backoff intervals directly.
|
||||
for i := 0; i < n; i++ {
|
||||
// Sleep the current goroutine.
|
||||
backo.Sleep(i)
|
||||
// Retrieve the duration manually.
|
||||
duration := backo.Duration(i)
|
||||
}
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
```
|
||||
WWWWWW||WWWWWW
|
||||
W W W||W W W
|
||||
||
|
||||
( OO )__________
|
||||
/ | \
|
||||
/o o| MIT \
|
||||
\___/||_||__||_|| *
|
||||
|| || || ||
|
||||
_||_|| _||_||
|
||||
(__|__|(__|__|
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Segment, Inc.
|
||||
|
||||
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.
|
||||
```
|
||||
|
||||
|
||||
|
||||
[1]: http://github.com/segmentio/backo-java
|
||||
[2]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.segment.backo&a=backo&v=LATEST
|
||||
83
vendor/github.com/segmentio/backo-go/backo.go
generated
vendored
Normal file
83
vendor/github.com/segmentio/backo-go/backo.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package backo
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Backo struct {
|
||||
base time.Duration
|
||||
factor uint8
|
||||
jitter float64
|
||||
cap time.Duration
|
||||
}
|
||||
|
||||
// Creates a backo instance with the given parameters
|
||||
func NewBacko(base time.Duration, factor uint8, jitter float64, cap time.Duration) *Backo {
|
||||
return &Backo{base, factor, jitter, cap}
|
||||
}
|
||||
|
||||
// Creates a backo instance with the following defaults:
|
||||
// base: 100 milliseconds
|
||||
// factor: 2
|
||||
// jitter: 0
|
||||
// cap: 10 seconds
|
||||
func DefaultBacko() *Backo {
|
||||
return NewBacko(time.Millisecond*100, 2, 0, time.Second*10)
|
||||
}
|
||||
|
||||
// Duration returns the backoff interval for the given attempt.
|
||||
func (backo *Backo) Duration(attempt int) time.Duration {
|
||||
duration := float64(backo.base) * math.Pow(float64(backo.factor), float64(attempt))
|
||||
|
||||
if backo.jitter != 0 {
|
||||
random := rand.Float64()
|
||||
deviation := math.Floor(random * backo.jitter * duration)
|
||||
if (int(math.Floor(random*10)) & 1) == 0 {
|
||||
duration = duration - deviation
|
||||
} else {
|
||||
duration = duration + deviation
|
||||
}
|
||||
}
|
||||
|
||||
duration = math.Min(float64(duration), float64(backo.cap))
|
||||
return time.Duration(duration)
|
||||
}
|
||||
|
||||
// Sleep pauses the current goroutine for the backoff interval for the given attempt.
|
||||
func (backo *Backo) Sleep(attempt int) {
|
||||
duration := backo.Duration(attempt)
|
||||
time.Sleep(duration)
|
||||
}
|
||||
|
||||
type Ticker struct {
|
||||
done chan struct{}
|
||||
C <-chan time.Time
|
||||
}
|
||||
|
||||
func (b *Backo) NewTicker() *Ticker {
|
||||
c := make(chan time.Time, 1)
|
||||
ticker := &Ticker{
|
||||
done: make(chan struct{}, 1),
|
||||
C: c,
|
||||
}
|
||||
|
||||
go func() {
|
||||
for i := 0; ; i++ {
|
||||
select {
|
||||
case t := <-time.After(b.Duration(i)):
|
||||
c <- t
|
||||
case <-ticker.done:
|
||||
close(c)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return ticker
|
||||
}
|
||||
|
||||
func (t *Ticker) Stop() {
|
||||
t.done <- struct{}{}
|
||||
}
|
||||
77
vendor/github.com/segmentio/backo-go/backo_test.go
generated
vendored
Normal file
77
vendor/github.com/segmentio/backo-go/backo_test.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package backo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bmizerany/assert"
|
||||
)
|
||||
|
||||
// Tests default backo behaviour.
|
||||
func TestDefaults(t *testing.T) {
|
||||
backo := DefaultBacko()
|
||||
|
||||
assert.Equal(t, milliseconds(100), backo.Duration(0))
|
||||
assert.Equal(t, milliseconds(200), backo.Duration(1))
|
||||
assert.Equal(t, milliseconds(400), backo.Duration(2))
|
||||
assert.Equal(t, milliseconds(800), backo.Duration(3))
|
||||
}
|
||||
|
||||
// Tests backo does not exceed cap.
|
||||
func TestCap(t *testing.T) {
|
||||
backo := NewBacko(milliseconds(100), 2, 0, milliseconds(600))
|
||||
|
||||
assert.Equal(t, milliseconds(100), backo.Duration(0))
|
||||
assert.Equal(t, milliseconds(200), backo.Duration(1))
|
||||
assert.Equal(t, milliseconds(400), backo.Duration(2))
|
||||
assert.Equal(t, milliseconds(600), backo.Duration(3))
|
||||
}
|
||||
|
||||
// Tests that jitter adds randomness.
|
||||
func TestJitter(t *testing.T) {
|
||||
defaultBacko := NewBacko(milliseconds(100), 2, 1, milliseconds(10*1000))
|
||||
jitterBacko := NewBacko(milliseconds(100), 2, 1, milliseconds(10*1000))
|
||||
|
||||
// TODO: Check jittered durations are within a range.
|
||||
assert.NotEqual(t, jitterBacko.Duration(0), defaultBacko.Duration(0))
|
||||
assert.NotEqual(t, jitterBacko.Duration(1), defaultBacko.Duration(1))
|
||||
assert.NotEqual(t, jitterBacko.Duration(2), defaultBacko.Duration(2))
|
||||
assert.NotEqual(t, jitterBacko.Duration(3), defaultBacko.Duration(3))
|
||||
}
|
||||
|
||||
func ExampleBacko_BackoffDefault() {
|
||||
b := DefaultBacko()
|
||||
ticker := b.NewTicker()
|
||||
|
||||
for i := 0; i < 6; i++ {
|
||||
start := time.Now()
|
||||
select {
|
||||
case t := <-ticker.C:
|
||||
fmt.Println(nearest10Millis(t.Sub(start)))
|
||||
}
|
||||
}
|
||||
|
||||
ticker.Stop()
|
||||
|
||||
// Output:
|
||||
// 100
|
||||
// 200
|
||||
// 400
|
||||
// 800
|
||||
// 1600
|
||||
// 3200
|
||||
}
|
||||
|
||||
func nearest10Millis(d time.Duration) float64 {
|
||||
// Typically d is something like 11 or 21, so do some magic to round the
|
||||
// durations to the nearest 10. We divide d by 10, floor it, and multiply it
|
||||
// by 10 again.
|
||||
return math.Floor(float64(d/time.Millisecond/10) * 10)
|
||||
}
|
||||
|
||||
// Returns the given milliseconds as time.Duration
|
||||
func milliseconds(ms int64) time.Duration {
|
||||
return time.Duration(ms * 1000 * 1000)
|
||||
}
|
||||
5
vendor/github.com/xtgo/uuid/AUTHORS
generated
vendored
Normal file
5
vendor/github.com/xtgo/uuid/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# This source file refers to The gocql Authors for copyright purposes.
|
||||
|
||||
Christoph Hack <christoph@tux21b.org>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Thorsten von Eicken <tve@rightscale.com>
|
||||
27
vendor/github.com/xtgo/uuid/LICENSE
generated
vendored
Normal file
27
vendor/github.com/xtgo/uuid/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 The gocql Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
204
vendor/github.com/xtgo/uuid/uuid.go
generated
vendored
Normal file
204
vendor/github.com/xtgo/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright (c) 2012 The gocql 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 uuid can be used to generate and parse universally unique
|
||||
// identifiers, a standardized format in the form of a 128 bit number.
|
||||
//
|
||||
// http://tools.ietf.org/html/rfc4122
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UUID [16]byte
|
||||
|
||||
var hardwareAddr []byte
|
||||
|
||||
const (
|
||||
VariantNCSCompat = 0
|
||||
VariantIETF = 2
|
||||
VariantMicrosoft = 6
|
||||
VariantFuture = 7
|
||||
)
|
||||
|
||||
func init() {
|
||||
if interfaces, err := net.Interfaces(); err == nil {
|
||||
for _, i := range interfaces {
|
||||
if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 {
|
||||
hardwareAddr = i.HardwareAddr
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if hardwareAddr == nil {
|
||||
// If we failed to obtain the MAC address of the current computer,
|
||||
// we will use a randomly generated 6 byte sequence instead and set
|
||||
// the multicast bit as recommended in RFC 4122.
|
||||
hardwareAddr = make([]byte, 6)
|
||||
_, err := io.ReadFull(rand.Reader, hardwareAddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
hardwareAddr[0] = hardwareAddr[0] | 0x01
|
||||
}
|
||||
}
|
||||
|
||||
// Parse parses a 32 digit hexadecimal number (that might contain hyphens)
|
||||
// representing an UUID.
|
||||
func Parse(input string) (UUID, error) {
|
||||
var u UUID
|
||||
j := 0
|
||||
for i := 0; i < len(input); i++ {
|
||||
b := input[i]
|
||||
switch {
|
||||
default:
|
||||
fallthrough
|
||||
case j == 32:
|
||||
goto err
|
||||
case b == '-':
|
||||
continue
|
||||
case '0' <= b && b <= '9':
|
||||
b -= '0'
|
||||
case 'a' <= b && b <= 'f':
|
||||
b -= 'a' - 10
|
||||
case 'A' <= b && b <= 'F':
|
||||
b -= 'A' - 10
|
||||
}
|
||||
u[j/2] |= b << byte(^j&1<<2)
|
||||
j++
|
||||
}
|
||||
if j == 32 {
|
||||
return u, nil
|
||||
}
|
||||
err:
|
||||
return UUID{}, errors.New("invalid UUID " + strconv.Quote(input))
|
||||
}
|
||||
|
||||
// FromBytes converts a raw byte slice to an UUID. It will panic if the slice
|
||||
// isn't exactly 16 bytes long.
|
||||
func FromBytes(input []byte) UUID {
|
||||
var u UUID
|
||||
if len(input) != 16 {
|
||||
panic("UUIDs must be exactly 16 bytes long")
|
||||
}
|
||||
copy(u[:], input)
|
||||
return u
|
||||
}
|
||||
|
||||
// NewRandom generates a totally random UUID (version 4) as described in
|
||||
// RFC 4122.
|
||||
func NewRandom() UUID {
|
||||
var u UUID
|
||||
io.ReadFull(rand.Reader, u[:])
|
||||
u[6] &= 0x0F // clear version
|
||||
u[6] |= 0x40 // set version to 4 (random uuid)
|
||||
u[8] &= 0x3F // clear variant
|
||||
u[8] |= 0x80 // set to IETF variant
|
||||
return u
|
||||
}
|
||||
|
||||
var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
|
||||
|
||||
// NewTime generates a new time based UUID (version 1) as described in RFC
|
||||
// 4122. This UUID contains the MAC address of the node that generated the
|
||||
// UUID, a timestamp and a sequence number.
|
||||
func NewTime() UUID {
|
||||
var u UUID
|
||||
|
||||
now := time.Now().In(time.UTC)
|
||||
t := uint64(now.Unix()-timeBase)*10000000 + uint64(now.Nanosecond()/100)
|
||||
u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
|
||||
u[4], u[5] = byte(t>>40), byte(t>>32)
|
||||
u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)
|
||||
|
||||
var clockSeq [2]byte
|
||||
io.ReadFull(rand.Reader, clockSeq[:])
|
||||
u[8] = clockSeq[1]
|
||||
u[9] = clockSeq[0]
|
||||
|
||||
copy(u[10:], hardwareAddr)
|
||||
|
||||
u[6] |= 0x10 // set version to 1 (time based uuid)
|
||||
u[8] &= 0x3F // clear variant
|
||||
u[8] |= 0x80 // set to IETF variant
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// String returns the UUID in it's canonical form, a 32 digit hexadecimal
|
||||
// number in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
|
||||
func (u UUID) String() string {
|
||||
buf := [36]byte{8: '-', 13: '-', 18: '-', 23: '-'}
|
||||
hex.Encode(buf[0:], u[0:4])
|
||||
hex.Encode(buf[9:], u[4:6])
|
||||
hex.Encode(buf[14:], u[6:8])
|
||||
hex.Encode(buf[19:], u[8:10])
|
||||
hex.Encode(buf[24:], u[10:])
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
// Bytes returns the raw byte slice for this UUID. A UUID is always 128 bits
|
||||
// (16 bytes) long.
|
||||
func (u UUID) Bytes() []byte {
|
||||
return u[:]
|
||||
}
|
||||
|
||||
// Variant returns the variant of this UUID. This package will only generate
|
||||
// UUIDs in the IETF variant.
|
||||
func (u UUID) Variant() int {
|
||||
x := u[8]
|
||||
switch byte(0) {
|
||||
case x & 0x80:
|
||||
return VariantNCSCompat
|
||||
case x & 0x40:
|
||||
return VariantIETF
|
||||
case x & 0x20:
|
||||
return VariantMicrosoft
|
||||
}
|
||||
return VariantFuture
|
||||
}
|
||||
|
||||
// Version extracts the version of this UUID variant. The RFC 4122 describes
|
||||
// five kinds of UUIDs.
|
||||
func (u UUID) Version() int {
|
||||
return int(u[6] & 0xF0 >> 4)
|
||||
}
|
||||
|
||||
// Node extracts the MAC address of the node who generated this UUID. It will
|
||||
// return nil if the UUID is not a time based UUID (version 1).
|
||||
func (u UUID) Node() []byte {
|
||||
if u.Version() != 1 {
|
||||
return nil
|
||||
}
|
||||
return u[10:]
|
||||
}
|
||||
|
||||
// Timestamp extracts the timestamp information from a time based UUID
|
||||
// (version 1).
|
||||
func (u UUID) Timestamp() uint64 {
|
||||
if u.Version() != 1 {
|
||||
return 0
|
||||
}
|
||||
return uint64(u[0])<<24 + uint64(u[1])<<16 + uint64(u[2])<<8 +
|
||||
uint64(u[3]) + uint64(u[4])<<40 + uint64(u[5])<<32 +
|
||||
uint64(u[7])<<48 + uint64(u[6]&0x0F)<<56
|
||||
}
|
||||
|
||||
// Time is like Timestamp, except that it returns a time.Time.
|
||||
func (u UUID) Time() time.Time {
|
||||
t := u.Timestamp()
|
||||
if t == 0 {
|
||||
return time.Time{}
|
||||
}
|
||||
sec := t / 10000000
|
||||
nsec := t - sec
|
||||
return time.Unix(int64(sec)+timeBase, int64(nsec))
|
||||
}
|
||||
102
vendor/github.com/xtgo/uuid/uuid_test.go
generated
vendored
Normal file
102
vendor/github.com/xtgo/uuid/uuid_test.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2012 The gocql 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 uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNil(t *testing.T) {
|
||||
var uuid UUID
|
||||
want, got := "00000000-0000-0000-0000-000000000000", uuid.String()
|
||||
if want != got {
|
||||
t.Fatalf("TestNil: expected %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
input string
|
||||
variant int
|
||||
version int
|
||||
}{
|
||||
{"b4f00409-cef8-4822-802c-deb20704c365", VariantIETF, 4},
|
||||
{"f81d4fae-7dec-11d0-a765-00a0c91e6bf6", VariantIETF, 1},
|
||||
{"00000000-7dec-11d0-a765-00a0c91e6bf6", VariantIETF, 1},
|
||||
{"3051a8d7-aea7-1801-e0bf-bc539dd60cf3", VariantFuture, 1},
|
||||
{"3051a8d7-aea7-2801-e0bf-bc539dd60cf3", VariantFuture, 2},
|
||||
{"3051a8d7-aea7-3801-e0bf-bc539dd60cf3", VariantFuture, 3},
|
||||
{"3051a8d7-aea7-4801-e0bf-bc539dd60cf3", VariantFuture, 4},
|
||||
{"3051a8d7-aea7-3801-e0bf-bc539dd60cf3", VariantFuture, 5},
|
||||
{"d0e817e1-e4b1-1801-3fe6-b4b60ccecf9d", VariantNCSCompat, 0},
|
||||
{"d0e817e1-e4b1-1801-bfe6-b4b60ccecf9d", VariantIETF, 1},
|
||||
{"d0e817e1-e4b1-1801-dfe6-b4b60ccecf9d", VariantMicrosoft, 0},
|
||||
{"d0e817e1-e4b1-1801-ffe6-b4b60ccecf9d", VariantFuture, 0},
|
||||
}
|
||||
|
||||
func TestPredefined(t *testing.T) {
|
||||
for i := range tests {
|
||||
uuid, err := Parse(tests[i].input)
|
||||
if err != nil {
|
||||
t.Errorf("Parse #%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if str := uuid.String(); str != tests[i].input {
|
||||
t.Errorf("String #%d: expected %q got %q", i, tests[i].input, str)
|
||||
continue
|
||||
}
|
||||
|
||||
if variant := uuid.Variant(); variant != tests[i].variant {
|
||||
t.Errorf("Variant #%d: expected %d got %d", i, tests[i].variant, variant)
|
||||
}
|
||||
|
||||
if tests[i].variant == VariantIETF {
|
||||
if version := uuid.Version(); version != tests[i].version {
|
||||
t.Errorf("Version #%d: expected %d got %d", i, tests[i].version, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRandom(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
uuid := NewRandom()
|
||||
|
||||
if variant := uuid.Variant(); variant != VariantIETF {
|
||||
t.Errorf("wrong variant. expected %d got %d", VariantIETF, variant)
|
||||
}
|
||||
if version := uuid.Version(); version != 4 {
|
||||
t.Errorf("wrong version. expected %d got %d", 4, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTime(t *testing.T) {
|
||||
var node []byte
|
||||
timestamp := uint64(0)
|
||||
for i := 0; i < 20; i++ {
|
||||
uuid := NewTime()
|
||||
|
||||
if variant := uuid.Variant(); variant != VariantIETF {
|
||||
t.Errorf("wrong variant. expected %d got %d", VariantIETF, variant)
|
||||
}
|
||||
if version := uuid.Version(); version != 1 {
|
||||
t.Errorf("wrong version. expected %d got %d", 1, version)
|
||||
}
|
||||
|
||||
if n := uuid.Node(); !bytes.Equal(n, node) && i > 0 {
|
||||
t.Errorf("wrong node. expected %x, got %x", node, n)
|
||||
} else if i == 0 {
|
||||
node = n
|
||||
}
|
||||
|
||||
ts := uuid.Timestamp()
|
||||
if ts < timestamp {
|
||||
t.Errorf("timestamps must grow")
|
||||
}
|
||||
timestamp = ts
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user