Switch to golang/dep to manage the dependencies of source code

Used golang/dep to regenerate the code in /vendor directory.
Also edited `CONTRIBUTING.md` to explain the process for dependency
management.
This commit is contained in:
Tan Jiang 2017-12-20 23:27:00 +08:00
parent 068d6a35df
commit 1bd7d5b719
2186 changed files with 573914 additions and 559 deletions

View File

@ -34,6 +34,9 @@ Please submit a PR to contain changes bit by bit. A PR consisting of a lot featu
You can propose new designs for existing Harbor features. You can also design
entirely new features. Please do open an issue on Github for discussion first. This is necessary to ensure the overall architecture is consistent and to avoid duplicated work in the roadmap.
### Dependency management
Harbor uses [dep](https://github.com/golang/dep) for dependency management of go code. The official maintainers will take the responsibility for managing the code in `vendor` directory. Please don't try to submit PR to update the dependency code, open an issue instead. If your PR requires a change in the vendor code please make sure you discuss it with maintainers in advance.
### Conventions
Fork Harbor's repository and make changes on your own fork in a new branch. The branch should be named XXX-description where XXX is the number of the issue. Please run the full test suite on your branch before creating a PR.

250
src/Gopkg.lock generated Normal file
View File

@ -0,0 +1,250 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/Sirupsen/logrus"
packages = ["."]
revision = "a283a10442df8dc09befd873fab202bf8a253d6a"
[[projects]]
name = "github.com/Unknwon/goconfig"
packages = ["."]
revision = "5f601ca6ef4d5cea8d52be2f8b3a420ee4b574a5"
[[projects]]
branch = "master"
name = "github.com/agl/ed25519"
packages = [
".",
"edwards25519"
]
revision = "5312a61534124124185d41f09206b9fef1d88403"
[[projects]]
name = "github.com/astaxie/beego"
packages = [
".",
"cache",
"config",
"context",
"grace",
"logs",
"orm",
"session",
"session/redis",
"toolbox",
"utils",
"validation"
]
revision = "1aeb3d90512734def678c7aa9f612fe6f659e6b5"
version = "v1.6.1"
[[projects]]
name = "github.com/beego/i18n"
packages = ["."]
revision = "e87155e8f0c05bf323d0b13470e1b97af0cb5652"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
name = "github.com/dghubble/sling"
packages = ["."]
revision = "eb56e89ac5088bebb12eef3cb4b293300f43608b"
version = "v1.1.0"
[[projects]]
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
revision = "d2709f9f1f31ebcda9651b03077758c1f3a0018c"
version = "v3.0.0"
[[projects]]
name = "github.com/docker/distribution"
packages = [
".",
"context",
"digest",
"manifest",
"manifest/schema1",
"manifest/schema2",
"reference",
"registry/auth",
"registry/auth/token",
"registry/client/auth/challenge",
"uuid"
]
revision = "325b0804fef3a66309d962357aac3c2ce3f4d329"
version = "v2.6.0"
[[projects]]
branch = "master"
name = "github.com/docker/go"
packages = ["canonical/json"]
revision = "d30aec9fd63c35133f8f79c3412ad91a3b08be06"
[[projects]]
branch = "master"
name = "github.com/docker/libtrust"
packages = ["."]
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
[[projects]]
name = "github.com/docker/notary"
packages = [
".",
"client",
"client/changelist",
"cryptoservice",
"storage",
"trustmanager",
"trustmanager/yubikey",
"trustpinning",
"tuf",
"tuf/data",
"tuf/signed",
"tuf/utils",
"tuf/validation"
]
revision = "c04e3e6d05881045def11167c51d4a8baa34899a"
[[projects]]
name = "github.com/garyburd/redigo"
packages = [
"internal",
"redis"
]
revision = "47dc60e71eed504e3ef8e77ee3c6fe720f3be57f"
version = "v1.3.0"
[[projects]]
name = "github.com/go-sql-driver/mysql"
packages = ["."]
revision = "a732e14c62dde3285440047bba97581bc472ae18"
version = "v1.2"
[[projects]]
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "130e6b02ab059e7b717a096f397c5b60111cae74"
[[projects]]
branch = "master"
name = "github.com/google/go-querystring"
packages = ["query"]
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
[[projects]]
name = "github.com/gorilla/context"
packages = ["."]
revision = "aed02d124ae4a0e94fea4541c8effd05bf0c8296"
[[projects]]
name = "github.com/gorilla/handlers"
packages = ["."]
revision = "13d73096a474cac93275c679c7b8a2dc17ddba82"
[[projects]]
name = "github.com/gorilla/mux"
packages = ["."]
revision = "780415097119f6f61c55475fe59b66f3c3e9ea53"
[[projects]]
name = "github.com/lib/pq"
packages = [
".",
"oid"
]
revision = "dd1fe2071026ce53f36a39112e645b4d4f5793a4"
[[projects]]
name = "github.com/mattn/go-sqlite3"
packages = ["."]
revision = "3fb7a0e792edd47bf0cf1e919dfc14e2be412e15"
[[projects]]
name = "github.com/miekg/pkcs11"
packages = ["."]
revision = "7283ca79f35edb89bc1b4ecae7f86a3680ce737f"
[[projects]]
name = "github.com/opencontainers/go-digest"
packages = ["."]
revision = "aa2ec055abd10d26d539eb630a92241b781ce4bc"
version = "v1.0.0-rc0"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
name = "github.com/stretchr/testify"
packages = [
"assert",
"require"
]
revision = "4d4bfba8f1d1027c4fdbe371823030df51419987"
[[projects]]
name = "golang.org/x/crypto"
packages = ["pbkdf2"]
revision = "5f961cd492ac9d43fc33a8ef646bae79d113fd97"
[[projects]]
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp"
]
revision = "075e191f18186a8ff2becaf64478e30f4545cdad"
[[projects]]
name = "golang.org/x/oauth2"
packages = [
".",
"internal"
]
revision = "bb50c06baba3d0c76f9d125c0719093e315b5b44"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "571f7bbbe08da2a8955aed9d4db316e78630e9a3"
[[projects]]
name = "google.golang.org/appengine"
packages = [
"internal",
"internal/base",
"internal/datastore",
"internal/log",
"internal/remote_api",
"internal/urlfetch",
"urlfetch"
]
revision = "24e4144ec923c2374f6b06610c0df16a9222c3d9"
[[projects]]
name = "gopkg.in/asn1-ber.v1"
packages = ["."]
revision = "4e86f4367175e39f69d9358a5f17b4dda270378d"
version = "v1.1"
[[projects]]
name = "gopkg.in/ldap.v2"
packages = ["."]
revision = "8168ee085ee43257585e50c6441aadf54ecb2c9f"
version = "v2.5.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "9c0f8cd26043afa12693fed0005998c7194c4ea77c8dae19c4363ebadfd600ef"
solver-name = "gps-cdcl"
solver-version = 1

53
src/Gopkg.toml Normal file
View File

@ -0,0 +1,53 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# 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]]
name = "github.com/astaxie/beego"
version = "1.6.1"
[[constraint]]
name = "github.com/dghubble/sling"
version = "1.1.0"
[[constraint]]
name = "github.com/dgrijalva/jwt-go"
version = "3.0.0"
[[constraint]]
name = "github.com/docker/distribution"
version = "2.6.0"
[[constraint]]
branch = "master"
name = "github.com/docker/libtrust"
[[constraint]]
name = "github.com/go-sql-driver/mysql"
version = "1.2.0"
[[constraint]]
name = "github.com/opencontainers/go-digest"
version = "1.0.0-rc0"
[[constraint]]
name = "gopkg.in/ldap.v2"
version = "2.5.0"

1
src/vendor/github.com/Sirupsen/logrus/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
logrus

10
src/vendor/github.com/Sirupsen/logrus/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,10 @@
language: go
go:
- 1.3
- 1.4
- 1.5
- 1.6
- tip
install:
- go get -t ./...
script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...

74
src/vendor/github.com/Sirupsen/logrus/alt_exit_test.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
package logrus
import (
"io/ioutil"
"os/exec"
"testing"
"time"
)
func TestRegister(t *testing.T) {
current := len(handlers)
RegisterExitHandler(func() {})
if len(handlers) != current+1 {
t.Fatalf("can't add handler")
}
}
func TestHandler(t *testing.T) {
gofile := "/tmp/testprog.go"
if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil {
t.Fatalf("can't create go file")
}
outfile := "/tmp/testprog.out"
arg := time.Now().UTC().String()
err := exec.Command("go", "run", gofile, outfile, arg).Run()
if err == nil {
t.Fatalf("completed normally, should have failed")
}
data, err := ioutil.ReadFile(outfile)
if err != nil {
t.Fatalf("can't read output file %s", outfile)
}
if string(data) != arg {
t.Fatalf("bad data")
}
}
var testprog = []byte(`
// Test program for atexit, gets output file and data as arguments and writes
// data to output file in atexit handler.
package main
import (
"github.com/Sirupsen/logrus"
"flag"
"fmt"
"io/ioutil"
)
var outfile = ""
var data = ""
func handler() {
ioutil.WriteFile(outfile, []byte(data), 0666)
}
func badHandler() {
n := 0
fmt.Println(1/n)
}
func main() {
flag.Parse()
outfile = flag.Arg(0)
data = flag.Arg(1)
logrus.RegisterExitHandler(handler)
logrus.RegisterExitHandler(badHandler)
logrus.Fatal("Bye bye")
}
`)

77
src/vendor/github.com/Sirupsen/logrus/entry_test.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
package logrus
import (
"bytes"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEntryWithError(t *testing.T) {
assert := assert.New(t)
defer func() {
ErrorKey = "error"
}()
err := fmt.Errorf("kaboom at layer %d", 4711)
assert.Equal(err, WithError(err).Data["error"])
logger := New()
logger.Out = &bytes.Buffer{}
entry := NewEntry(logger)
assert.Equal(err, entry.WithError(err).Data["error"])
ErrorKey = "err"
assert.Equal(err, entry.WithError(err).Data["err"])
}
func TestEntryPanicln(t *testing.T) {
errBoom := fmt.Errorf("boom time")
defer func() {
p := recover()
assert.NotNil(t, p)
switch pVal := p.(type) {
case *Entry:
assert.Equal(t, "kaboom", pVal.Message)
assert.Equal(t, errBoom, pVal.Data["err"])
default:
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
}
}()
logger := New()
logger.Out = &bytes.Buffer{}
entry := NewEntry(logger)
entry.WithField("err", errBoom).Panicln("kaboom")
}
func TestEntryPanicf(t *testing.T) {
errBoom := fmt.Errorf("boom again")
defer func() {
p := recover()
assert.NotNil(t, p)
switch pVal := p.(type) {
case *Entry:
assert.Equal(t, "kaboom true", pVal.Message)
assert.Equal(t, errBoom, pVal.Data["err"])
default:
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
}
}()
logger := New()
logger.Out = &bytes.Buffer{}
entry := NewEntry(logger)
entry.WithField("err", errBoom).Panicf("kaboom %v", true)
}

View File

@ -0,0 +1,50 @@
package main
import (
"github.com/Sirupsen/logrus"
)
var log = logrus.New()
func init() {
log.Formatter = new(logrus.JSONFormatter)
log.Formatter = new(logrus.TextFormatter) // default
log.Level = logrus.DebugLevel
}
func main() {
defer func() {
err := recover()
if err != nil {
log.WithFields(logrus.Fields{
"omg": true,
"err": err,
"number": 100,
}).Fatal("The ice breaks!")
}
}()
log.WithFields(logrus.Fields{
"animal": "walrus",
"number": 8,
}).Debug("Started observing beach")
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(logrus.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(logrus.Fields{
"temperature": -4,
}).Debug("Temperature changes")
log.WithFields(logrus.Fields{
"animal": "orca",
"size": 9009,
}).Panic("It's over 9000!")
}

View File

@ -0,0 +1,30 @@
package main
import (
"github.com/Sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2"
)
var log = logrus.New()
func init() {
log.Formatter = new(logrus.TextFormatter) // default
log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
}
func main() {
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(logrus.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(logrus.Fields{
"omg": true,
"number": 100,
}).Fatal("The ice breaks!")
}

View File

@ -0,0 +1,98 @@
package logrus
import (
"fmt"
"testing"
"time"
)
// smallFields is a small size data set for benchmarking
var smallFields = Fields{
"foo": "bar",
"baz": "qux",
"one": "two",
"three": "four",
}
// largeFields is a large size data set for benchmarking
var largeFields = Fields{
"foo": "bar",
"baz": "qux",
"one": "two",
"three": "four",
"five": "six",
"seven": "eight",
"nine": "ten",
"eleven": "twelve",
"thirteen": "fourteen",
"fifteen": "sixteen",
"seventeen": "eighteen",
"nineteen": "twenty",
"a": "b",
"c": "d",
"e": "f",
"g": "h",
"i": "j",
"k": "l",
"m": "n",
"o": "p",
"q": "r",
"s": "t",
"u": "v",
"w": "x",
"y": "z",
"this": "will",
"make": "thirty",
"entries": "yeah",
}
var errorFields = Fields{
"foo": fmt.Errorf("bar"),
"baz": fmt.Errorf("qux"),
}
func BenchmarkErrorTextFormatter(b *testing.B) {
doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields)
}
func BenchmarkSmallTextFormatter(b *testing.B) {
doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
}
func BenchmarkLargeTextFormatter(b *testing.B) {
doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
}
func BenchmarkSmallColoredTextFormatter(b *testing.B) {
doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
}
func BenchmarkLargeColoredTextFormatter(b *testing.B) {
doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
}
func BenchmarkSmallJSONFormatter(b *testing.B) {
doBenchmark(b, &JSONFormatter{}, smallFields)
}
func BenchmarkLargeJSONFormatter(b *testing.B) {
doBenchmark(b, &JSONFormatter{}, largeFields)
}
func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
entry := &Entry{
Time: time.Time{},
Level: InfoLevel,
Message: "message",
Data: fields,
}
var d []byte
var err error
for i := 0; i < b.N; i++ {
d, err = formatter.Format(entry)
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(d)))
}
}

122
src/vendor/github.com/Sirupsen/logrus/hook_test.go generated vendored Normal file
View File

@ -0,0 +1,122 @@
package logrus
import (
"testing"
"github.com/stretchr/testify/assert"
)
type TestHook struct {
Fired bool
}
func (hook *TestHook) Fire(entry *Entry) error {
hook.Fired = true
return nil
}
func (hook *TestHook) Levels() []Level {
return []Level{
DebugLevel,
InfoLevel,
WarnLevel,
ErrorLevel,
FatalLevel,
PanicLevel,
}
}
func TestHookFires(t *testing.T) {
hook := new(TestHook)
LogAndAssertJSON(t, func(log *Logger) {
log.Hooks.Add(hook)
assert.Equal(t, hook.Fired, false)
log.Print("test")
}, func(fields Fields) {
assert.Equal(t, hook.Fired, true)
})
}
type ModifyHook struct {
}
func (hook *ModifyHook) Fire(entry *Entry) error {
entry.Data["wow"] = "whale"
return nil
}
func (hook *ModifyHook) Levels() []Level {
return []Level{
DebugLevel,
InfoLevel,
WarnLevel,
ErrorLevel,
FatalLevel,
PanicLevel,
}
}
func TestHookCanModifyEntry(t *testing.T) {
hook := new(ModifyHook)
LogAndAssertJSON(t, func(log *Logger) {
log.Hooks.Add(hook)
log.WithField("wow", "elephant").Print("test")
}, func(fields Fields) {
assert.Equal(t, fields["wow"], "whale")
})
}
func TestCanFireMultipleHooks(t *testing.T) {
hook1 := new(ModifyHook)
hook2 := new(TestHook)
LogAndAssertJSON(t, func(log *Logger) {
log.Hooks.Add(hook1)
log.Hooks.Add(hook2)
log.WithField("wow", "elephant").Print("test")
}, func(fields Fields) {
assert.Equal(t, fields["wow"], "whale")
assert.Equal(t, hook2.Fired, true)
})
}
type ErrorHook struct {
Fired bool
}
func (hook *ErrorHook) Fire(entry *Entry) error {
hook.Fired = true
return nil
}
func (hook *ErrorHook) Levels() []Level {
return []Level{
ErrorLevel,
}
}
func TestErrorHookShouldntFireOnInfo(t *testing.T) {
hook := new(ErrorHook)
LogAndAssertJSON(t, func(log *Logger) {
log.Hooks.Add(hook)
log.Info("test")
}, func(fields Fields) {
assert.Equal(t, hook.Fired, false)
})
}
func TestErrorHookShouldFireOnError(t *testing.T) {
hook := new(ErrorHook)
LogAndAssertJSON(t, func(log *Logger) {
log.Hooks.Add(hook)
log.Error("test")
}, func(fields Fields) {
assert.Equal(t, hook.Fired, true)
})
}

View File

@ -0,0 +1,39 @@
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
## Usage
```go
import (
"log/syslog"
"github.com/Sirupsen/logrus"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
)
func main() {
log := logrus.New()
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err == nil {
log.Hooks.Add(hook)
}
}
```
If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following.
```go
import (
"log/syslog"
"github.com/Sirupsen/logrus"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
)
func main() {
log := logrus.New()
hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
if err == nil {
log.Hooks.Add(hook)
}
}
```

View File

@ -0,0 +1,54 @@
// +build !windows,!nacl,!plan9
package logrus_syslog
import (
"fmt"
"github.com/Sirupsen/logrus"
"log/syslog"
"os"
)
// SyslogHook to send logs via syslog.
type SyslogHook struct {
Writer *syslog.Writer
SyslogNetwork string
SyslogRaddr string
}
// Creates a hook to be added to an instance of logger. This is called with
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
// `if err == nil { log.Hooks.Add(hook) }`
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
w, err := syslog.Dial(network, raddr, priority, tag)
return &SyslogHook{w, network, raddr}, err
}
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
line, err := entry.String()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
return err
}
switch entry.Level {
case logrus.PanicLevel:
return hook.Writer.Crit(line)
case logrus.FatalLevel:
return hook.Writer.Crit(line)
case logrus.ErrorLevel:
return hook.Writer.Err(line)
case logrus.WarnLevel:
return hook.Writer.Warning(line)
case logrus.InfoLevel:
return hook.Writer.Info(line)
case logrus.DebugLevel:
return hook.Writer.Debug(line)
default:
return nil
}
}
func (hook *SyslogHook) Levels() []logrus.Level {
return logrus.AllLevels
}

View File

@ -0,0 +1,26 @@
package logrus_syslog
import (
"github.com/Sirupsen/logrus"
"log/syslog"
"testing"
)
func TestLocalhostAddAndPrint(t *testing.T) {
log := logrus.New()
hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err != nil {
t.Errorf("Unable to connect to local syslog.")
}
log.Hooks.Add(hook)
for _, level := range hook.Levels() {
if len(log.Hooks[level]) != 1 {
t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
}
}
log.Info("Congratulations!")
}

View File

@ -0,0 +1,67 @@
package test
import (
"io/ioutil"
"github.com/Sirupsen/logrus"
)
// test.Hook is a hook designed for dealing with logs in test scenarios.
type Hook struct {
Entries []*logrus.Entry
}
// Installs a test hook for the global logger.
func NewGlobal() *Hook {
hook := new(Hook)
logrus.AddHook(hook)
return hook
}
// Installs a test hook for a given local logger.
func NewLocal(logger *logrus.Logger) *Hook {
hook := new(Hook)
logger.Hooks.Add(hook)
return hook
}
// Creates a discarding logger and installs the test hook.
func NewNullLogger() (*logrus.Logger, *Hook) {
logger := logrus.New()
logger.Out = ioutil.Discard
return logger, NewLocal(logger)
}
func (t *Hook) Fire(e *logrus.Entry) error {
t.Entries = append(t.Entries, e)
return nil
}
func (t *Hook) Levels() []logrus.Level {
return logrus.AllLevels
}
// LastEntry returns the last entry that was logged or nil.
func (t *Hook) LastEntry() (l *logrus.Entry) {
if i := len(t.Entries) - 1; i < 0 {
return nil
} else {
return t.Entries[i]
}
}
// Reset removes all Entries from this test hook.
func (t *Hook) Reset() {
t.Entries = make([]*logrus.Entry, 0)
}

View File

@ -0,0 +1,39 @@
package test
import (
"testing"
"github.com/Sirupsen/logrus"
"github.com/stretchr/testify/assert"
)
func TestAllHooks(t *testing.T) {
assert := assert.New(t)
logger, hook := NewNullLogger()
assert.Nil(hook.LastEntry())
assert.Equal(0, len(hook.Entries))
logger.Error("Hello error")
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
assert.Equal("Hello error", hook.LastEntry().Message)
assert.Equal(1, len(hook.Entries))
logger.Warn("Hello warning")
assert.Equal(logrus.WarnLevel, hook.LastEntry().Level)
assert.Equal("Hello warning", hook.LastEntry().Message)
assert.Equal(2, len(hook.Entries))
hook.Reset()
assert.Nil(hook.LastEntry())
assert.Equal(0, len(hook.Entries))
hook = NewGlobal()
logrus.Error("Hello error")
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
assert.Equal("Hello error", hook.LastEntry().Message)
assert.Equal(1, len(hook.Entries))
}

View File

@ -0,0 +1,120 @@
package logrus
import (
"encoding/json"
"errors"
"testing"
)
func TestErrorNotLost(t *testing.T) {
formatter := &JSONFormatter{}
b, err := formatter.Format(WithField("error", errors.New("wild walrus")))
if err != nil {
t.Fatal("Unable to format entry: ", err)
}
entry := make(map[string]interface{})
err = json.Unmarshal(b, &entry)
if err != nil {
t.Fatal("Unable to unmarshal formatted entry: ", err)
}
if entry["error"] != "wild walrus" {
t.Fatal("Error field not set")
}
}
func TestErrorNotLostOnFieldNotNamedError(t *testing.T) {
formatter := &JSONFormatter{}
b, err := formatter.Format(WithField("omg", errors.New("wild walrus")))
if err != nil {
t.Fatal("Unable to format entry: ", err)
}
entry := make(map[string]interface{})
err = json.Unmarshal(b, &entry)
if err != nil {
t.Fatal("Unable to unmarshal formatted entry: ", err)
}
if entry["omg"] != "wild walrus" {
t.Fatal("Error field not set")
}
}
func TestFieldClashWithTime(t *testing.T) {
formatter := &JSONFormatter{}
b, err := formatter.Format(WithField("time", "right now!"))
if err != nil {
t.Fatal("Unable to format entry: ", err)
}
entry := make(map[string]interface{})
err = json.Unmarshal(b, &entry)
if err != nil {
t.Fatal("Unable to unmarshal formatted entry: ", err)
}
if entry["fields.time"] != "right now!" {
t.Fatal("fields.time not set to original time field")
}
if entry["time"] != "0001-01-01T00:00:00Z" {
t.Fatal("time field not set to current time, was: ", entry["time"])
}
}
func TestFieldClashWithMsg(t *testing.T) {
formatter := &JSONFormatter{}
b, err := formatter.Format(WithField("msg", "something"))
if err != nil {
t.Fatal("Unable to format entry: ", err)
}
entry := make(map[string]interface{})
err = json.Unmarshal(b, &entry)
if err != nil {
t.Fatal("Unable to unmarshal formatted entry: ", err)
}
if entry["fields.msg"] != "something" {
t.Fatal("fields.msg not set to original msg field")
}
}
func TestFieldClashWithLevel(t *testing.T) {
formatter := &JSONFormatter{}
b, err := formatter.Format(WithField("level", "something"))
if err != nil {
t.Fatal("Unable to format entry: ", err)
}
entry := make(map[string]interface{})
err = json.Unmarshal(b, &entry)
if err != nil {
t.Fatal("Unable to unmarshal formatted entry: ", err)
}
if entry["fields.level"] != "something" {
t.Fatal("fields.level not set to original level field")
}
}
func TestJSONEntryEndsWithNewline(t *testing.T) {
formatter := &JSONFormatter{}
b, err := formatter.Format(WithField("level", "something"))
if err != nil {
t.Fatal("Unable to format entry: ", err)
}
if b[len(b)-1] != '\n' {
t.Fatal("Expected JSON log entry to end with a newline")
}
}

361
src/vendor/github.com/Sirupsen/logrus/logrus_test.go generated vendored Normal file
View File

@ -0,0 +1,361 @@
package logrus
import (
"bytes"
"encoding/json"
"strconv"
"strings"
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
var buffer bytes.Buffer
var fields Fields
logger := New()
logger.Out = &buffer
logger.Formatter = new(JSONFormatter)
log(logger)
err := json.Unmarshal(buffer.Bytes(), &fields)
assert.Nil(t, err)
assertions(fields)
}
func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
var buffer bytes.Buffer
logger := New()
logger.Out = &buffer
logger.Formatter = &TextFormatter{
DisableColors: true,
}
log(logger)
fields := make(map[string]string)
for _, kv := range strings.Split(buffer.String(), " ") {
if !strings.Contains(kv, "=") {
continue
}
kvArr := strings.Split(kv, "=")
key := strings.TrimSpace(kvArr[0])
val := kvArr[1]
if kvArr[1][0] == '"' {
var err error
val, err = strconv.Unquote(val)
assert.NoError(t, err)
}
fields[key] = val
}
assertions(fields)
}
func TestPrint(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Print("test")
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
assert.Equal(t, fields["level"], "info")
})
}
func TestInfo(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Info("test")
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
assert.Equal(t, fields["level"], "info")
})
}
func TestWarn(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Warn("test")
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
assert.Equal(t, fields["level"], "warning")
})
}
func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Infoln("test", "test")
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test test")
})
}
func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Infoln("test", 10)
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test 10")
})
}
func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Infoln(10, 10)
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "10 10")
})
}
func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Infoln(10, 10)
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "10 10")
})
}
func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Info("test", 10)
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test10")
})
}
func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.Info("test", "test")
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "testtest")
})
}
func TestWithFieldsShouldAllowAssignments(t *testing.T) {
var buffer bytes.Buffer
var fields Fields
logger := New()
logger.Out = &buffer
logger.Formatter = new(JSONFormatter)
localLog := logger.WithFields(Fields{
"key1": "value1",
})
localLog.WithField("key2", "value2").Info("test")
err := json.Unmarshal(buffer.Bytes(), &fields)
assert.Nil(t, err)
assert.Equal(t, "value2", fields["key2"])
assert.Equal(t, "value1", fields["key1"])
buffer = bytes.Buffer{}
fields = Fields{}
localLog.Info("test")
err = json.Unmarshal(buffer.Bytes(), &fields)
assert.Nil(t, err)
_, ok := fields["key2"]
assert.Equal(t, false, ok)
assert.Equal(t, "value1", fields["key1"])
}
func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.WithField("msg", "hello").Info("test")
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
})
}
func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.WithField("msg", "hello").Info("test")
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
assert.Equal(t, fields["fields.msg"], "hello")
})
}
func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.WithField("time", "hello").Info("test")
}, func(fields Fields) {
assert.Equal(t, fields["fields.time"], "hello")
})
}
func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.WithField("level", 1).Info("test")
}, func(fields Fields) {
assert.Equal(t, fields["level"], "info")
assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only
})
}
func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
LogAndAssertText(t, func(log *Logger) {
ll := log.WithField("herp", "derp")
ll.Info("hello")
ll.Info("bye")
}, func(fields map[string]string) {
for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
if _, ok := fields[fieldName]; ok {
t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
}
}
})
}
func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
var buffer bytes.Buffer
var fields Fields
logger := New()
logger.Out = &buffer
logger.Formatter = new(JSONFormatter)
llog := logger.WithField("context", "eating raw fish")
llog.Info("looks delicious")
err := json.Unmarshal(buffer.Bytes(), &fields)
assert.NoError(t, err, "should have decoded first message")
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
assert.Equal(t, fields["msg"], "looks delicious")
assert.Equal(t, fields["context"], "eating raw fish")
buffer.Reset()
llog.Warn("omg it is!")
err = json.Unmarshal(buffer.Bytes(), &fields)
assert.NoError(t, err, "should have decoded second message")
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
assert.Equal(t, fields["msg"], "omg it is!")
assert.Equal(t, fields["context"], "eating raw fish")
assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
}
func TestConvertLevelToString(t *testing.T) {
assert.Equal(t, "debug", DebugLevel.String())
assert.Equal(t, "info", InfoLevel.String())
assert.Equal(t, "warning", WarnLevel.String())
assert.Equal(t, "error", ErrorLevel.String())
assert.Equal(t, "fatal", FatalLevel.String())
assert.Equal(t, "panic", PanicLevel.String())
}
func TestParseLevel(t *testing.T) {
l, err := ParseLevel("panic")
assert.Nil(t, err)
assert.Equal(t, PanicLevel, l)
l, err = ParseLevel("PANIC")
assert.Nil(t, err)
assert.Equal(t, PanicLevel, l)
l, err = ParseLevel("fatal")
assert.Nil(t, err)
assert.Equal(t, FatalLevel, l)
l, err = ParseLevel("FATAL")
assert.Nil(t, err)
assert.Equal(t, FatalLevel, l)
l, err = ParseLevel("error")
assert.Nil(t, err)
assert.Equal(t, ErrorLevel, l)
l, err = ParseLevel("ERROR")
assert.Nil(t, err)
assert.Equal(t, ErrorLevel, l)
l, err = ParseLevel("warn")
assert.Nil(t, err)
assert.Equal(t, WarnLevel, l)
l, err = ParseLevel("WARN")
assert.Nil(t, err)
assert.Equal(t, WarnLevel, l)
l, err = ParseLevel("warning")
assert.Nil(t, err)
assert.Equal(t, WarnLevel, l)
l, err = ParseLevel("WARNING")
assert.Nil(t, err)
assert.Equal(t, WarnLevel, l)
l, err = ParseLevel("info")
assert.Nil(t, err)
assert.Equal(t, InfoLevel, l)
l, err = ParseLevel("INFO")
assert.Nil(t, err)
assert.Equal(t, InfoLevel, l)
l, err = ParseLevel("debug")
assert.Nil(t, err)
assert.Equal(t, DebugLevel, l)
l, err = ParseLevel("DEBUG")
assert.Nil(t, err)
assert.Equal(t, DebugLevel, l)
l, err = ParseLevel("invalid")
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
}
func TestGetSetLevelRace(t *testing.T) {
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
if i%2 == 0 {
SetLevel(InfoLevel)
} else {
GetLevel()
}
}(i)
}
wg.Wait()
}
func TestLoggingRace(t *testing.T) {
logger := New()
var wg sync.WaitGroup
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
logger.Info("info")
wg.Done()
}()
}
wg.Wait()
}
// Compile test
func TestLogrusInterface(t *testing.T) {
var buffer bytes.Buffer
fn := func(l FieldLogger) {
b := l.WithField("key", "value")
b.Debug("Test")
}
// test logger
logger := New()
logger.Out = &buffer
fn(logger)
// test Entry
e := logger.WithField("another", "value")
fn(e)
}

View File

@ -0,0 +1,61 @@
package logrus
import (
"bytes"
"errors"
"testing"
"time"
)
func TestQuoting(t *testing.T) {
tf := &TextFormatter{DisableColors: true}
checkQuoting := func(q bool, value interface{}) {
b, _ := tf.Format(WithField("test", value))
idx := bytes.Index(b, ([]byte)("test="))
cont := bytes.Contains(b[idx+5:], []byte{'"'})
if cont != q {
if q {
t.Errorf("quoting expected for: %#v", value)
} else {
t.Errorf("quoting not expected for: %#v", value)
}
}
}
checkQuoting(false, "abcd")
checkQuoting(false, "v1.0")
checkQuoting(false, "1234567890")
checkQuoting(true, "/foobar")
checkQuoting(true, "x y")
checkQuoting(true, "x,y")
checkQuoting(false, errors.New("invalid"))
checkQuoting(true, errors.New("invalid argument"))
}
func TestTimestampFormat(t *testing.T) {
checkTimeStr := func(format string) {
customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format}
customStr, _ := customFormatter.Format(WithField("test", "test"))
timeStart := bytes.Index(customStr, ([]byte)("time="))
timeEnd := bytes.Index(customStr, ([]byte)("level="))
timeStr := customStr[timeStart+5 : timeEnd-1]
if timeStr[0] == '"' && timeStr[len(timeStr)-1] == '"' {
timeStr = timeStr[1 : len(timeStr)-1]
}
if format == "" {
format = time.RFC3339
}
_, e := time.Parse(format, (string)(timeStr))
if e != nil {
t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e)
}
}
checkTimeStr("2006-01-02T15:04:05.000000000Z07:00")
checkTimeStr("Mon Jan _2 15:04:05 2006")
checkTimeStr("")
}
// TODO add tests for sorting etc., this requires a parser for the text
// formatter output.

3
src/vendor/github.com/Unknwon/goconfig/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
.DS_Store
*.iml
.idea

398
src/vendor/github.com/Unknwon/goconfig/goconfig_test.go generated vendored Normal file
View File

@ -0,0 +1,398 @@
// Copyright 2013 Unknwon
//
// 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 goconfig
import (
"bytes"
"fmt"
"io/ioutil"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestLoadConfigFile(t *testing.T) {
Convey("Load a single configuration file that does exist", t, func() {
c, err := LoadConfigFile("testdata/conf.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
Convey("Test GetSectionList", func() {
So(c.GetSectionList(), ShouldResemble,
[]string{"DEFAULT", "Demo", "What's this?", "url", "parent",
"parent.child", "parent.child.child", "auto increment"})
})
Convey("Get value that does exist", func() {
v, err := c.GetValue("Demo", "key2")
So(err, ShouldBeNil)
So(v, ShouldEqual, "test data")
})
Convey("Get value that does not exist", func() {
_, err := c.GetValue("Demo", "key4")
So(err, ShouldNotBeNil)
})
Convey("Get value that has empty value", func() {
_, err := c.GetValue("What's this?", "empty_value")
So(err, ShouldBeNil)
})
Convey("Get value that section does not exist", func() {
_, err := c.GetValue("Demo404", "key4")
So(err, ShouldNotBeNil)
})
Convey("Get value use parent-child feature", func() {
v, err := c.GetValue("parent.child", "sex")
So(err, ShouldBeNil)
So(v, ShouldEqual, "male")
})
Convey("Get value use recursive feature", func() {
v, err := c.GetValue("", "search")
So(err, ShouldBeNil)
So(v, ShouldEqual, "http://www.google.com")
v, err = c.GetValue("url", "google_url")
So(err, ShouldBeNil)
So(v, ShouldEqual, "http://www.google.fake")
})
Convey("Set value that does exist", func() {
So(c.SetValue("Demo", "key2", "hello man!"), ShouldBeFalse)
v, err := c.GetValue("Demo", "key2")
So(err, ShouldBeNil)
So(v, ShouldEqual, "hello man!")
})
Convey("Set value that does not exist", func() {
So(c.SetValue("Demo", "key4", "hello girl!"), ShouldBeTrue)
v, err := c.GetValue("Demo", "key4")
So(err, ShouldBeNil)
So(v, ShouldEqual, "hello girl!")
So(c.SetValue("", "gowalker", "https://gowalker.org"), ShouldBeTrue)
})
Convey("Test GetKeyList", func() {
So(c.GetKeyList("Demo"), ShouldResemble,
[]string{"key1", "key2", "key3", "quote", "key:1",
"key:2=key:1", "中国", "chinese-var", "array_key"})
})
Convey("Delete a key", func() {
So(c.DeleteKey("", "key404"), ShouldBeFalse)
So(c.DeleteKey("Demo", "key404"), ShouldBeFalse)
So(c.DeleteKey("Demo", "中国"), ShouldBeTrue)
_, err := c.GetValue("Demo", "中国")
So(err, ShouldNotBeNil)
So(c.DeleteKey("404", "key"), ShouldBeFalse)
})
Convey("Delete all the keys", func() {
for _, key := range c.GetKeyList("Demo") {
So(c.DeleteKey("Demo", key), ShouldBeTrue)
}
So(c.GetKeyList("Demo"), ShouldResemble, []string{})
So(len(c.GetKeyList("Demo")), ShouldEqual, 0)
})
Convey("Delete section that does not exist", func() {
So(c.DeleteSection(""), ShouldBeTrue)
So(c.DeleteSection("404"), ShouldBeFalse)
})
Convey("Get section that exists", func() {
_, err = c.GetSection("")
So(err, ShouldBeNil)
})
Convey("Get section that does not exist", func() {
_, err = c.GetSection("404")
So(err, ShouldNotBeNil)
})
Convey("Set section comments", func() {
So(c.SetSectionComments("", "default section comments"), ShouldBeTrue)
})
Convey("Get section comments", func() {
So(c.GetSectionComments(""), ShouldEqual, "")
})
Convey("Set key comments", func() {
So(c.SetKeyComments("", "search", "search comments"), ShouldBeTrue)
So(c.SetKeyComments("404", "search", ""), ShouldBeTrue)
})
Convey("Get key comments", func() {
So(c.GetKeyComments("", "google"), ShouldEqual, "; Google")
})
Convey("Delete all the sections", func() {
for _, sec := range c.GetSectionList() {
So(c.DeleteSection(sec), ShouldBeTrue)
}
So(c.GetSectionList(), ShouldResemble, []string{})
So(len(c.GetSectionList()), ShouldEqual, 0)
})
})
Convey("Load a single configuration file that does not exist", t, func() {
_, err := LoadConfigFile("testdata/conf404.ini")
So(err, ShouldNotBeNil)
})
Convey("Load multiple configuration files", t, func() {
c, err := LoadConfigFile("testdata/conf.ini", "testdata/conf2.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
Convey("Get value that does not exist in 1st file", func() {
v, err := c.GetValue("new section", "key1")
So(err, ShouldBeNil)
So(v, ShouldEqual, "conf.ini does not have this key")
})
Convey("Get value that overwrited in 2nd file", func() {
v, err := c.GetValue("Demo", "key2")
So(err, ShouldBeNil)
So(v, ShouldEqual, "rewrite this key of conf.ini")
})
})
}
func TestGetKeyList(t *testing.T) {
Convey("Get key list", t, func() {
c, err := LoadConfigFile("testdata/conf.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
Convey("Get ket list that does exist", func() {
So(c.GetKeyList("Demo"), ShouldResemble,
[]string{"key1", "key2", "key3", "quote", "key:1",
"key:2=key:1", "中国", "chinese-var", "array_key"})
So(c.GetKeyList(""), ShouldResemble, []string{"google", "search"})
})
Convey("Get key list that not exist", func() {
So(c.GetKeyList("404"), ShouldBeNil)
})
})
}
func TestSaveConfigFile(t *testing.T) {
Convey("Save a ConfigFile to file system", t, func() {
c, err := LoadConfigFile("testdata/conf.ini", "testdata/conf2.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
c.SetValue("", "", "empty")
So(SaveConfigFile(c, "testdata/conf_test.ini"), ShouldBeNil)
})
}
func TestSaveConfigData(t *testing.T) {
Convey("Save a ConfigFile to file system", t, func() {
c, err := LoadConfigFile("testdata/conf.ini", "testdata/conf2.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
c.SetValue("", "", "empty")
var dst bytes.Buffer
So(SaveConfigData(c, &dst), ShouldBeNil)
So(dst.Len(), ShouldNotEqual, 0)
})
}
func TestReload(t *testing.T) {
Convey("Reload a configuration file", t, func() {
c, err := LoadConfigFile("testdata/conf.ini", "testdata/conf2.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
So(c.Reload(), ShouldBeNil)
})
}
func TestReloadData(t *testing.T) {
Convey("Reload a configuration file", t, func() {
data, err := ioutil.ReadFile("testdata/conf.ini")
So(err, ShouldBeNil)
c, err := LoadFromReader(bytes.NewBuffer(data))
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
So(c.ReloadData(bytes.NewBuffer(data)), ShouldBeNil)
})
}
func TestAppendFiles(t *testing.T) {
Convey("Reload a configuration file", t, func() {
c, err := LoadConfigFile("testdata/conf.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
So(c.AppendFiles("testdata/conf2.ini"), ShouldBeNil)
})
}
func TestTypes(t *testing.T) {
Convey("Return with types", t, func() {
c, err := LoadConfigFile("testdata/conf.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
Convey("Return bool", func() {
v, err := c.Bool("parent.child", "married")
So(err, ShouldBeNil)
So(v, ShouldBeTrue)
_, err = c.Bool("parent.child", "died")
So(err, ShouldNotBeNil)
})
Convey("Return float64", func() {
v, err := c.Float64("parent", "money")
So(err, ShouldBeNil)
So(v, ShouldEqual, 1.25)
_, err = c.Float64("parent", "balance")
So(err, ShouldNotBeNil)
})
Convey("Return int", func() {
v, err := c.Int("parent", "age")
So(err, ShouldBeNil)
So(v, ShouldEqual, 32)
_, err = c.Int("parent", "children")
So(err, ShouldNotBeNil)
})
Convey("Return int64", func() {
v, err := c.Int64("parent", "age")
So(err, ShouldBeNil)
So(v, ShouldEqual, 32)
_, err = c.Int64("parent", "children")
So(err, ShouldNotBeNil)
})
})
}
func TestMust(t *testing.T) {
Convey("Must return with type", t, func() {
c, err := LoadConfigFile("testdata/conf.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
Convey("Return string", func() {
So(c.MustValue("parent.child", "name"), ShouldEqual, "john")
So(c.MustValue("parent.child", "died"), ShouldEqual, "")
So(c.MustValue("parent.child", "died", "no"), ShouldEqual, "no")
})
Convey("Return string and bool", func() {
val, ok := c.MustValueSet("parent.child", "died")
So(val, ShouldEqual, "")
So(ok, ShouldBeFalse)
val, ok = c.MustValueSet("parent.child", "died", "no")
So(val, ShouldEqual, "no")
So(ok, ShouldBeTrue)
})
Convey("Return bool", func() {
So(c.MustBool("parent.child", "married"), ShouldBeTrue)
So(c.MustBool("parent.child", "died"), ShouldBeFalse)
So(c.MustBool("parent.child", "died", true), ShouldBeTrue)
})
Convey("Return float64", func() {
So(c.MustFloat64("parent", "money"), ShouldEqual, 1.25)
So(c.MustFloat64("parent", "balance"), ShouldEqual, 0.0)
So(c.MustFloat64("parent", "balance", 1.25), ShouldEqual, 1.25)
})
Convey("Return int", func() {
So(c.MustInt("parent", "age"), ShouldEqual, 32)
So(c.MustInt("parent", "children"), ShouldEqual, 0)
So(c.MustInt("parent", "children", 3), ShouldEqual, 3)
})
Convey("Return int64", func() {
So(c.MustInt64("parent", "age"), ShouldEqual, 32)
So(c.MustInt64("parent", "children"), ShouldEqual, 0)
So(c.MustInt64("parent", "children", 3), ShouldEqual, 3)
})
})
}
func TestRange(t *testing.T) {
Convey("Must return with range", t, func() {
c, err := LoadConfigFile("testdata/conf.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
So(c.MustValueRange("What's this?", "name", "joe", []string{"hello"}), ShouldEqual, "joe")
So(c.MustValueRange("What's this?", "name404", "joe", []string{"hello"}), ShouldEqual, "joe")
So(c.MustValueRange("What's this?", "name", "joe", []string{"hello", "try one more value ^-^"}),
ShouldEqual, "try one more value ^-^")
})
}
func TestArray(t *testing.T) {
Convey("Must return with string array", t, func() {
c, err := LoadConfigFile("testdata/conf.ini")
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
So(fmt.Sprintf("%s", c.MustValueArray("Demo", "array_key", ",")), ShouldEqual, "[1 2 3 4 5]")
So(fmt.Sprintf("%s", c.MustValueArray("Demo", "array_key404", ",")), ShouldEqual, "[]")
})
}
func TestLoadFromData(t *testing.T) {
Convey("Load config file from data", t, func() {
c, err := LoadFromData([]byte(""))
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
})
}
func TestLoadFromReader(t *testing.T) {
Convey("Load config file from reader", t, func() {
c, err := LoadFromReader(bytes.NewBuffer([]byte("")))
So(err, ShouldBeNil)
So(c, ShouldNotBeNil)
})
}
func Benchmark_GetValue(b *testing.B) {
c, _ := LoadConfigFile("testdata/conf.ini")
c.BlockMode = false
for i := 0; i < b.N; i++ {
c.GetValue("parent", "money")
}
}
func Benchmark_SetValue(b *testing.B) {
c, _ := LoadConfigFile("testdata/conf.ini")
for i := 0; i < b.N; i++ {
c.SetValue("parent", "money", "10")
}
}

View File

@ -0,0 +1,46 @@
; Google
google = www.google.com
search = http://%(google)s
; Here are Comments
; Second line
[Demo]
# This symbol can also make this line to be comments
key1 = Let's us goconfig!!!
key2 = test data
key3 = this is based on key2:%(key2)s
quote = "special case for quote
"key:1" = This is the value of "key:1"
"key:2=key:1" = this is based on "key:2=key:1" => %(key:1)s
中国 = China
chinese-var = hello %(中国)s!
array_key = 1,2,3,4,5
[What's this?]
; Not Enough Comments!!
name = try one more value ^-^
empty_value =
[url]
google_fake = www.google.fake
google_url = http://%(google_fake)s
[parent]
name = john
relation = father
sex = male
age = 32
money = 1.25
[parent.child]
age = 3
married = true
[parent.child.child]
; Auto increment by setting key to "-"
[auto increment]
- = hello
- = go
- = config

View File

@ -0,0 +1,37 @@
; Google
google = www.google.com
search = http://%(google)s
; Here are Comments
; Second line
[Demo]
# This symbol can also make this line to be comments
key1 = Let's us goconfig!!!
key2 = rewrite this key of conf.ini
key3 = this is based on key2:%(key2)s
"key:1" = This is the value of "key:1"
"""key:2"""="""this is based on "key:1" => `%(key:1)s`"""
[What's this?]
; Not Enough Comments!!
name = try one more value ^-^
[parent]
name = john
relation = father
sex = male
age = 32
[parent.child]
age = 3
[parent.child.child]
; Auto increment by setting key to "-"
[auto increment]
- = hello
- = go
- = config
[new section]
key1 = conf.ini does not have this key

View File

@ -0,0 +1,50 @@
; Google
google = www.google.com
search = http://%(google)s
; Here are Comments
; Second line
[Demo]
# This symbol can also make this line to be comments
key1 = Let's us goconfig!!!
key2 = rewrite this key of conf.ini
key3 = this is based on key2:%(key2)s
quote = "special case for quote
`key:1` = This is the value of "key:1"
`key:2=key:1` = this is based on "key:2=key:1" => %(key:1)s
中国 = China
chinese-var = hello %(中国)s!
array_key = 1,2,3,4,5
`key:2` = """this is based on "key:1" => `%(key:1)s`"""
[What's this?]
; Not Enough Comments!!
name = try one more value ^-^
empty_value =
[url]
google_fake = www.google.fake
google_url = http://%(google_fake)s
[parent]
name = john
relation = father
sex = male
age = 32
money = 1.25
[parent.child]
age = 3
married = true
[parent.child.child]
; Auto increment by setting key to "-"
[auto increment]
- = hello
- = go
- = config
[new section]
key1 = conf.ini does not have this key

160
src/vendor/github.com/agl/ed25519/ed25519_test.go generated vendored Normal file
View File

@ -0,0 +1,160 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ed25519
import (
"bufio"
"bytes"
"compress/gzip"
"crypto/rand"
"encoding/hex"
"io"
"os"
"strings"
"testing"
"github.com/agl/ed25519/edwards25519"
)
type zeroReader struct{}
func (zeroReader) Read(buf []byte) (int, error) {
for i := range buf {
buf[i] = 0
}
return len(buf), nil
}
func TestUnmarshalMarshal(t *testing.T) {
pub, _, _ := GenerateKey(rand.Reader)
var A edwards25519.ExtendedGroupElement
if !A.FromBytes(pub) {
t.Fatalf("ExtendedGroupElement.FromBytes failed")
}
var pub2 [32]byte
A.ToBytes(&pub2)
if *pub != pub2 {
t.Errorf("FromBytes(%v)->ToBytes does not round-trip, got %x\n", *pub, pub2)
}
}
func TestSignVerify(t *testing.T) {
var zero zeroReader
public, private, _ := GenerateKey(zero)
message := []byte("test message")
sig := Sign(private, message)
if !Verify(public, message, sig) {
t.Errorf("valid signature rejected")
}
wrongMessage := []byte("wrong message")
if Verify(public, wrongMessage, sig) {
t.Errorf("signature of different message accepted")
}
}
func TestGolden(t *testing.T) {
// sign.input.gz is a selection of test cases from
// http://ed25519.cr.yp.to/python/sign.input
testDataZ, err := os.Open("testdata/sign.input.gz")
if err != nil {
t.Fatal(err)
}
defer testDataZ.Close()
testData, err := gzip.NewReader(testDataZ)
if err != nil {
t.Fatal(err)
}
defer testData.Close()
in := bufio.NewReaderSize(testData, 1<<12)
lineNo := 0
for {
lineNo++
lineBytes, isPrefix, err := in.ReadLine()
if isPrefix {
t.Fatal("bufio buffer too small")
}
if err != nil {
if err == io.EOF {
break
}
t.Fatalf("error reading test data: %s", err)
}
line := string(lineBytes)
parts := strings.Split(line, ":")
if len(parts) != 5 {
t.Fatalf("bad number of parts on line %d", lineNo)
}
privBytes, _ := hex.DecodeString(parts[0])
pubKeyBytes, _ := hex.DecodeString(parts[1])
msg, _ := hex.DecodeString(parts[2])
sig, _ := hex.DecodeString(parts[3])
// The signatures in the test vectors also include the message
// at the end, but we just want R and S.
sig = sig[:SignatureSize]
if l := len(pubKeyBytes); l != PublicKeySize {
t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
}
var priv [PrivateKeySize]byte
copy(priv[:], privBytes)
copy(priv[32:], pubKeyBytes)
sig2 := Sign(&priv, msg)
if !bytes.Equal(sig, sig2[:]) {
t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
}
var pubKey [PublicKeySize]byte
copy(pubKey[:], pubKeyBytes)
if !Verify(&pubKey, msg, sig2) {
t.Errorf("signature failed to verify on line %d", lineNo)
}
}
}
func BenchmarkKeyGeneration(b *testing.B) {
var zero zeroReader
for i := 0; i < b.N; i++ {
if _, _, err := GenerateKey(zero); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkSigning(b *testing.B) {
var zero zeroReader
_, priv, err := GenerateKey(zero)
if err != nil {
b.Fatal(err)
}
message := []byte("Hello, world!")
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sign(priv, message)
}
}
func BenchmarkVerification(b *testing.B) {
var zero zeroReader
pub, priv, err := GenerateKey(zero)
if err != nil {
b.Fatal(err)
}
message := []byte("Hello, world!")
signature := Sign(priv, message)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Verify(pub, message, signature)
}
}

View File

@ -0,0 +1,340 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package extra25519
import (
"crypto/sha512"
"github.com/agl/ed25519/edwards25519"
)
// PrivateKeyToCurve25519 converts an ed25519 private key into a corresponding
// curve25519 private key such that the resulting curve25519 public key will
// equal the result from PublicKeyToCurve25519.
func PrivateKeyToCurve25519(curve25519Private *[32]byte, privateKey *[64]byte) {
h := sha512.New()
h.Write(privateKey[:32])
digest := h.Sum(nil)
digest[0] &= 248
digest[31] &= 127
digest[31] |= 64
copy(curve25519Private[:], digest)
}
func edwardsToMontgomeryX(outX, y *edwards25519.FieldElement) {
// We only need the x-coordinate of the curve25519 point, which I'll
// call u. The isomorphism is u=(y+1)/(1-y), since y=Y/Z, this gives
// u=(Y+Z)/(Z-Y). We know that Z=1, thus u=(Y+1)/(1-Y).
var oneMinusY edwards25519.FieldElement
edwards25519.FeOne(&oneMinusY)
edwards25519.FeSub(&oneMinusY, &oneMinusY, y)
edwards25519.FeInvert(&oneMinusY, &oneMinusY)
edwards25519.FeOne(outX)
edwards25519.FeAdd(outX, outX, y)
edwards25519.FeMul(outX, outX, &oneMinusY)
}
// PublicKeyToCurve25519 converts an Ed25519 public key into the curve25519
// public key that would be generated from the same private key.
func PublicKeyToCurve25519(curve25519Public *[32]byte, publicKey *[32]byte) bool {
var A edwards25519.ExtendedGroupElement
if !A.FromBytes(publicKey) {
return false
}
// A.Z = 1 as a postcondition of FromBytes.
var x edwards25519.FieldElement
edwardsToMontgomeryX(&x, &A.Y)
edwards25519.FeToBytes(curve25519Public, &x)
return true
}
// sqrtMinusAPlus2 is sqrt(-(486662+2))
var sqrtMinusAPlus2 = edwards25519.FieldElement{
-12222970, -8312128, -11511410, 9067497, -15300785, -241793, 25456130, 14121551, -12187136, 3972024,
}
// sqrtMinusHalf is sqrt(-1/2)
var sqrtMinusHalf = edwards25519.FieldElement{
-17256545, 3971863, 28865457, -1750208, 27359696, -16640980, 12573105, 1002827, -163343, 11073975,
}
// halfQMinus1Bytes is (2^255-20)/2 expressed in little endian form.
var halfQMinus1Bytes = [32]byte{
0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
}
// feBytesLess returns one if a <= b and zero otherwise.
func feBytesLE(a, b *[32]byte) int32 {
equalSoFar := int32(-1)
greater := int32(0)
for i := uint(31); i < 32; i-- {
x := int32(a[i])
y := int32(b[i])
greater = (^equalSoFar & greater) | (equalSoFar & ((x - y) >> 31))
equalSoFar = equalSoFar & (((x ^ y) - 1) >> 31)
}
return int32(^equalSoFar & 1 & greater)
}
// ScalarBaseMult computes a curve25519 public key from a private key and also
// a uniform representative for that public key. Note that this function will
// fail and return false for about half of private keys.
// See http://elligator.cr.yp.to/elligator-20130828.pdf.
func ScalarBaseMult(publicKey, representative, privateKey *[32]byte) bool {
var maskedPrivateKey [32]byte
copy(maskedPrivateKey[:], privateKey[:])
maskedPrivateKey[0] &= 248
maskedPrivateKey[31] &= 127
maskedPrivateKey[31] |= 64
var A edwards25519.ExtendedGroupElement
edwards25519.GeScalarMultBase(&A, &maskedPrivateKey)
var inv1 edwards25519.FieldElement
edwards25519.FeSub(&inv1, &A.Z, &A.Y)
edwards25519.FeMul(&inv1, &inv1, &A.X)
edwards25519.FeInvert(&inv1, &inv1)
var t0, u edwards25519.FieldElement
edwards25519.FeMul(&u, &inv1, &A.X)
edwards25519.FeAdd(&t0, &A.Y, &A.Z)
edwards25519.FeMul(&u, &u, &t0)
var v edwards25519.FieldElement
edwards25519.FeMul(&v, &t0, &inv1)
edwards25519.FeMul(&v, &v, &A.Z)
edwards25519.FeMul(&v, &v, &sqrtMinusAPlus2)
var b edwards25519.FieldElement
edwards25519.FeAdd(&b, &u, &edwards25519.A)
var c, b3, b7, b8 edwards25519.FieldElement
edwards25519.FeSquare(&b3, &b) // 2
edwards25519.FeMul(&b3, &b3, &b) // 3
edwards25519.FeSquare(&c, &b3) // 6
edwards25519.FeMul(&b7, &c, &b) // 7
edwards25519.FeMul(&b8, &b7, &b) // 8
edwards25519.FeMul(&c, &b7, &u)
q58(&c, &c)
var chi edwards25519.FieldElement
edwards25519.FeSquare(&chi, &c)
edwards25519.FeSquare(&chi, &chi)
edwards25519.FeSquare(&t0, &u)
edwards25519.FeMul(&chi, &chi, &t0)
edwards25519.FeSquare(&t0, &b7) // 14
edwards25519.FeMul(&chi, &chi, &t0)
edwards25519.FeNeg(&chi, &chi)
var chiBytes [32]byte
edwards25519.FeToBytes(&chiBytes, &chi)
// chi[1] is either 0 or 0xff
if chiBytes[1] == 0xff {
return false
}
// Calculate r1 = sqrt(-u/(2*(u+A)))
var r1 edwards25519.FieldElement
edwards25519.FeMul(&r1, &c, &u)
edwards25519.FeMul(&r1, &r1, &b3)
edwards25519.FeMul(&r1, &r1, &sqrtMinusHalf)
var maybeSqrtM1 edwards25519.FieldElement
edwards25519.FeSquare(&t0, &r1)
edwards25519.FeMul(&t0, &t0, &b)
edwards25519.FeAdd(&t0, &t0, &t0)
edwards25519.FeAdd(&t0, &t0, &u)
edwards25519.FeOne(&maybeSqrtM1)
edwards25519.FeCMove(&maybeSqrtM1, &edwards25519.SqrtM1, edwards25519.FeIsNonZero(&t0))
edwards25519.FeMul(&r1, &r1, &maybeSqrtM1)
// Calculate r = sqrt(-(u+A)/(2u))
var r edwards25519.FieldElement
edwards25519.FeSquare(&t0, &c) // 2
edwards25519.FeMul(&t0, &t0, &c) // 3
edwards25519.FeSquare(&t0, &t0) // 6
edwards25519.FeMul(&r, &t0, &c) // 7
edwards25519.FeSquare(&t0, &u) // 2
edwards25519.FeMul(&t0, &t0, &u) // 3
edwards25519.FeMul(&r, &r, &t0)
edwards25519.FeSquare(&t0, &b8) // 16
edwards25519.FeMul(&t0, &t0, &b8) // 24
edwards25519.FeMul(&t0, &t0, &b) // 25
edwards25519.FeMul(&r, &r, &t0)
edwards25519.FeMul(&r, &r, &sqrtMinusHalf)
edwards25519.FeSquare(&t0, &r)
edwards25519.FeMul(&t0, &t0, &u)
edwards25519.FeAdd(&t0, &t0, &t0)
edwards25519.FeAdd(&t0, &t0, &b)
edwards25519.FeOne(&maybeSqrtM1)
edwards25519.FeCMove(&maybeSqrtM1, &edwards25519.SqrtM1, edwards25519.FeIsNonZero(&t0))
edwards25519.FeMul(&r, &r, &maybeSqrtM1)
var vBytes [32]byte
edwards25519.FeToBytes(&vBytes, &v)
vInSquareRootImage := feBytesLE(&vBytes, &halfQMinus1Bytes)
edwards25519.FeCMove(&r, &r1, vInSquareRootImage)
edwards25519.FeToBytes(publicKey, &u)
edwards25519.FeToBytes(representative, &r)
return true
}
// q58 calculates out = z^((p-5)/8).
func q58(out, z *edwards25519.FieldElement) {
var t1, t2, t3 edwards25519.FieldElement
var i int
edwards25519.FeSquare(&t1, z) // 2^1
edwards25519.FeMul(&t1, &t1, z) // 2^1 + 2^0
edwards25519.FeSquare(&t1, &t1) // 2^2 + 2^1
edwards25519.FeSquare(&t2, &t1) // 2^3 + 2^2
edwards25519.FeSquare(&t2, &t2) // 2^4 + 2^3
edwards25519.FeMul(&t2, &t2, &t1) // 4,3,2,1
edwards25519.FeMul(&t1, &t2, z) // 4..0
edwards25519.FeSquare(&t2, &t1) // 5..1
for i = 1; i < 5; i++ { // 9,8,7,6,5
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t1, &t2, &t1) // 9,8,7,6,5,4,3,2,1,0
edwards25519.FeSquare(&t2, &t1) // 10..1
for i = 1; i < 10; i++ { // 19..10
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t2, &t2, &t1) // 19..0
edwards25519.FeSquare(&t3, &t2) // 20..1
for i = 1; i < 20; i++ { // 39..20
edwards25519.FeSquare(&t3, &t3)
}
edwards25519.FeMul(&t2, &t3, &t2) // 39..0
edwards25519.FeSquare(&t2, &t2) // 40..1
for i = 1; i < 10; i++ { // 49..10
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t1, &t2, &t1) // 49..0
edwards25519.FeSquare(&t2, &t1) // 50..1
for i = 1; i < 50; i++ { // 99..50
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t2, &t2, &t1) // 99..0
edwards25519.FeSquare(&t3, &t2) // 100..1
for i = 1; i < 100; i++ { // 199..100
edwards25519.FeSquare(&t3, &t3)
}
edwards25519.FeMul(&t2, &t3, &t2) // 199..0
edwards25519.FeSquare(&t2, &t2) // 200..1
for i = 1; i < 50; i++ { // 249..50
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t1, &t2, &t1) // 249..0
edwards25519.FeSquare(&t1, &t1) // 250..1
edwards25519.FeSquare(&t1, &t1) // 251..2
edwards25519.FeMul(out, &t1, z) // 251..2,0
}
// chi calculates out = z^((p-1)/2). The result is either 1, 0, or -1 depending
// on whether z is a non-zero square, zero, or a non-square.
func chi(out, z *edwards25519.FieldElement) {
var t0, t1, t2, t3 edwards25519.FieldElement
var i int
edwards25519.FeSquare(&t0, z) // 2^1
edwards25519.FeMul(&t1, &t0, z) // 2^1 + 2^0
edwards25519.FeSquare(&t0, &t1) // 2^2 + 2^1
edwards25519.FeSquare(&t2, &t0) // 2^3 + 2^2
edwards25519.FeSquare(&t2, &t2) // 4,3
edwards25519.FeMul(&t2, &t2, &t0) // 4,3,2,1
edwards25519.FeMul(&t1, &t2, z) // 4..0
edwards25519.FeSquare(&t2, &t1) // 5..1
for i = 1; i < 5; i++ { // 9,8,7,6,5
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t1, &t2, &t1) // 9,8,7,6,5,4,3,2,1,0
edwards25519.FeSquare(&t2, &t1) // 10..1
for i = 1; i < 10; i++ { // 19..10
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t2, &t2, &t1) // 19..0
edwards25519.FeSquare(&t3, &t2) // 20..1
for i = 1; i < 20; i++ { // 39..20
edwards25519.FeSquare(&t3, &t3)
}
edwards25519.FeMul(&t2, &t3, &t2) // 39..0
edwards25519.FeSquare(&t2, &t2) // 40..1
for i = 1; i < 10; i++ { // 49..10
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t1, &t2, &t1) // 49..0
edwards25519.FeSquare(&t2, &t1) // 50..1
for i = 1; i < 50; i++ { // 99..50
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t2, &t2, &t1) // 99..0
edwards25519.FeSquare(&t3, &t2) // 100..1
for i = 1; i < 100; i++ { // 199..100
edwards25519.FeSquare(&t3, &t3)
}
edwards25519.FeMul(&t2, &t3, &t2) // 199..0
edwards25519.FeSquare(&t2, &t2) // 200..1
for i = 1; i < 50; i++ { // 249..50
edwards25519.FeSquare(&t2, &t2)
}
edwards25519.FeMul(&t1, &t2, &t1) // 249..0
edwards25519.FeSquare(&t1, &t1) // 250..1
for i = 1; i < 4; i++ { // 253..4
edwards25519.FeSquare(&t1, &t1)
}
edwards25519.FeMul(out, &t1, &t0) // 253..4,2,1
}
// RepresentativeToPublicKey converts a uniform representative value for a
// curve25519 public key, as produced by ScalarBaseMult, to a curve25519 public
// key.
func RepresentativeToPublicKey(publicKey, representative *[32]byte) {
var rr2, v, e edwards25519.FieldElement
edwards25519.FeFromBytes(&rr2, representative)
edwards25519.FeSquare2(&rr2, &rr2)
rr2[0]++
edwards25519.FeInvert(&rr2, &rr2)
edwards25519.FeMul(&v, &edwards25519.A, &rr2)
edwards25519.FeNeg(&v, &v)
var v2, v3 edwards25519.FieldElement
edwards25519.FeSquare(&v2, &v)
edwards25519.FeMul(&v3, &v, &v2)
edwards25519.FeAdd(&e, &v3, &v)
edwards25519.FeMul(&v2, &v2, &edwards25519.A)
edwards25519.FeAdd(&e, &v2, &e)
chi(&e, &e)
var eBytes [32]byte
edwards25519.FeToBytes(&eBytes, &e)
// eBytes[1] is either 0 (for e = 1) or 0xff (for e = -1)
eIsMinus1 := int32(eBytes[1]) & 1
var negV edwards25519.FieldElement
edwards25519.FeNeg(&negV, &v)
edwards25519.FeCMove(&v, &negV, eIsMinus1)
edwards25519.FeZero(&v2)
edwards25519.FeCMove(&v2, &edwards25519.A, eIsMinus1)
edwards25519.FeSub(&v, &v, &v2)
edwards25519.FeToBytes(publicKey, &v)
}

View File

@ -0,0 +1,78 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package extra25519
import (
"bytes"
"crypto/rand"
"testing"
"github.com/agl/ed25519"
"golang.org/x/crypto/curve25519"
)
func TestCurve25519Conversion(t *testing.T) {
public, private, _ := ed25519.GenerateKey(rand.Reader)
var curve25519Public, curve25519Public2, curve25519Private [32]byte
PrivateKeyToCurve25519(&curve25519Private, private)
curve25519.ScalarBaseMult(&curve25519Public, &curve25519Private)
if !PublicKeyToCurve25519(&curve25519Public2, public) {
t.Fatalf("PublicKeyToCurve25519 failed")
}
if !bytes.Equal(curve25519Public[:], curve25519Public2[:]) {
t.Errorf("Values didn't match: curve25519 produced %x, conversion produced %x", curve25519Public[:], curve25519Public2[:])
}
}
func TestElligator(t *testing.T) {
var publicKey, publicKey2, publicKey3, representative, privateKey [32]byte
for i := 0; i < 1000; i++ {
rand.Reader.Read(privateKey[:])
if !ScalarBaseMult(&publicKey, &representative, &privateKey) {
continue
}
RepresentativeToPublicKey(&publicKey2, &representative)
if !bytes.Equal(publicKey[:], publicKey2[:]) {
t.Fatal("The resulting public key doesn't match the initial one.")
}
curve25519.ScalarBaseMult(&publicKey3, &privateKey)
if !bytes.Equal(publicKey[:], publicKey3[:]) {
t.Fatal("The public key doesn't match the value that curve25519 produced.")
}
}
}
func BenchmarkKeyGeneration(b *testing.B) {
var publicKey, representative, privateKey [32]byte
// Find the private key that results in a point that's in the image of the map.
for {
rand.Reader.Read(privateKey[:])
if ScalarBaseMult(&publicKey, &representative, &privateKey) {
break
}
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
ScalarBaseMult(&publicKey, &representative, &privateKey)
}
}
func BenchmarkMap(b *testing.B) {
var publicKey, representative [32]byte
rand.Reader.Read(representative[:])
b.ResetTimer()
for i := 0; i < b.N; i++ {
RepresentativeToPublicKey(&publicKey, &representative)
}
}

Binary file not shown.

5
src/vendor/github.com/astaxie/beego/.gitignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
.idea
.DS_Store
*.swp
*.swo
beego.iml

51
src/vendor/github.com/astaxie/beego/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,51 @@
language: go
go:
- tip
- 1.6.0
- 1.5.3
- 1.4.3
services:
- redis-server
- mysql
- postgresql
- memcached
env:
- ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db
- ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8"
- ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
before_install:
- git clone git://github.com/ideawu/ssdb.git
- cd ssdb
- make
- cd ..
install:
- go get github.com/lib/pq
- go get github.com/go-sql-driver/mysql
- go get github.com/mattn/go-sqlite3
- go get github.com/bradfitz/gomemcache/memcache
- go get github.com/garyburd/redigo/redis
- go get github.com/beego/x2j
- go get github.com/couchbase/go-couchbase
- go get github.com/beego/goyaml2
- go get github.com/belogik/goes
- go get github.com/siddontang/ledisdb/config
- go get github.com/siddontang/ledisdb/ledis
- go get golang.org/x/tools/cmd/vet
- go get github.com/golang/lint/golint
- go get github.com/ssdb/gossdb/ssdb
before_script:
- sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
- sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi"
- sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi"
- mkdir -p res/var
- ./ssdb/ssdb-server ./ssdb/ssdb.conf -d
after_script:
-killall -w ssdb-server
- rm -rf ./res/var/*
script:
- go vet -x ./...
- $HOME/gopath/bin/golint ./...
- go test -v ./...
notifications:
webhooks: https://hooks.pubu.im/services/z7m9bvybl3rgtg9

168
src/vendor/github.com/astaxie/beego/cache/cache_test.go generated vendored Normal file
View File

@ -0,0 +1,168 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 cache
import (
"os"
"testing"
"time"
)
func TestCache(t *testing.T) {
bm, err := NewCache("memory", `{"interval":20}`)
if err != nil {
t.Error("init err")
}
timeoutDuration := 10 * time.Second
if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie") {
t.Error("check err")
}
if v := bm.Get("astaxie"); v.(int) != 1 {
t.Error("get err")
}
time.Sleep(30 * time.Second)
if bm.IsExist("astaxie") {
t.Error("check err")
}
if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
t.Error("set Error", err)
}
if err = bm.Incr("astaxie"); err != nil {
t.Error("Incr Error", err)
}
if v := bm.Get("astaxie"); v.(int) != 2 {
t.Error("get err")
}
if err = bm.Decr("astaxie"); err != nil {
t.Error("Decr Error", err)
}
if v := bm.Get("astaxie"); v.(int) != 1 {
t.Error("get err")
}
bm.Delete("astaxie")
if bm.IsExist("astaxie") {
t.Error("delete err")
}
//test GetMulti
if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie") {
t.Error("check err")
}
if v := bm.Get("astaxie"); v.(string) != "author" {
t.Error("get err")
}
if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie1") {
t.Error("check err")
}
vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
if len(vv) != 2 {
t.Error("GetMulti ERROR")
}
if vv[0].(string) != "author" {
t.Error("GetMulti ERROR")
}
if vv[1].(string) != "author1" {
t.Error("GetMulti ERROR")
}
}
func TestFileCache(t *testing.T) {
bm, err := NewCache("file", `{"CachePath":"cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`)
if err != nil {
t.Error("init err")
}
timeoutDuration := 10 * time.Second
if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie") {
t.Error("check err")
}
if v := bm.Get("astaxie"); v.(int) != 1 {
t.Error("get err")
}
if err = bm.Incr("astaxie"); err != nil {
t.Error("Incr Error", err)
}
if v := bm.Get("astaxie"); v.(int) != 2 {
t.Error("get err")
}
if err = bm.Decr("astaxie"); err != nil {
t.Error("Decr Error", err)
}
if v := bm.Get("astaxie"); v.(int) != 1 {
t.Error("get err")
}
bm.Delete("astaxie")
if bm.IsExist("astaxie") {
t.Error("delete err")
}
//test string
if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie") {
t.Error("check err")
}
if v := bm.Get("astaxie"); v.(string) != "author" {
t.Error("get err")
}
//test GetMulti
if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie1") {
t.Error("check err")
}
vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
if len(vv) != 2 {
t.Error("GetMulti ERROR")
}
if vv[0].(string) != "author" {
t.Error("GetMulti ERROR")
}
if vv[1].(string) != "author1" {
t.Error("GetMulti ERROR")
}
os.RemoveAll("cache")
}

143
src/vendor/github.com/astaxie/beego/cache/conv_test.go generated vendored Normal file
View File

@ -0,0 +1,143 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 cache
import (
"testing"
)
func TestGetString(t *testing.T) {
var t1 = "test1"
if "test1" != GetString(t1) {
t.Error("get string from string error")
}
var t2 = []byte("test2")
if "test2" != GetString(t2) {
t.Error("get string from byte array error")
}
var t3 = 1
if "1" != GetString(t3) {
t.Error("get string from int error")
}
var t4 int64 = 1
if "1" != GetString(t4) {
t.Error("get string from int64 error")
}
var t5 = 1.1
if "1.1" != GetString(t5) {
t.Error("get string from float64 error")
}
if "" != GetString(nil) {
t.Error("get string from nil error")
}
}
func TestGetInt(t *testing.T) {
var t1 = 1
if 1 != GetInt(t1) {
t.Error("get int from int error")
}
var t2 int32 = 32
if 32 != GetInt(t2) {
t.Error("get int from int32 error")
}
var t3 int64 = 64
if 64 != GetInt(t3) {
t.Error("get int from int64 error")
}
var t4 = "128"
if 128 != GetInt(t4) {
t.Error("get int from num string error")
}
if 0 != GetInt(nil) {
t.Error("get int from nil error")
}
}
func TestGetInt64(t *testing.T) {
var i int64 = 1
var t1 = 1
if i != GetInt64(t1) {
t.Error("get int64 from int error")
}
var t2 int32 = 1
if i != GetInt64(t2) {
t.Error("get int64 from int32 error")
}
var t3 int64 = 1
if i != GetInt64(t3) {
t.Error("get int64 from int64 error")
}
var t4 = "1"
if i != GetInt64(t4) {
t.Error("get int64 from num string error")
}
if 0 != GetInt64(nil) {
t.Error("get int64 from nil")
}
}
func TestGetFloat64(t *testing.T) {
var f = 1.11
var t1 float32 = 1.11
if f != GetFloat64(t1) {
t.Error("get float64 from float32 error")
}
var t2 = 1.11
if f != GetFloat64(t2) {
t.Error("get float64 from float64 error")
}
var t3 = "1.11"
if f != GetFloat64(t3) {
t.Error("get float64 from string error")
}
var f2 float64 = 1
var t4 = 1
if f2 != GetFloat64(t4) {
t.Error("get float64 from int error")
}
if 0 != GetFloat64(nil) {
t.Error("get float64 from nil error")
}
}
func TestGetBool(t *testing.T) {
var t1 = true
if true != GetBool(t1) {
t.Error("get bool from bool error")
}
var t2 = "true"
if true != GetBool(t2) {
t.Error("get bool from string error")
}
if false != GetBool(nil) {
t.Error("get bool from nil error")
}
}
func byteArrayEquals(a []byte, b []byte) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}

View File

@ -0,0 +1,190 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 memcache for cache provider
//
// depend on github.com/bradfitz/gomemcache/memcache
//
// go install github.com/bradfitz/gomemcache/memcache
//
// Usage:
// import(
// _ "github.com/astaxie/beego/cache/memcache"
// "github.com/astaxie/beego/cache"
// )
//
// bm, err := cache.NewCache("memcache", `{"conn":"127.0.0.1:11211"}`)
//
// more docs http://beego.me/docs/module/cache.md
package memcache
import (
"encoding/json"
"errors"
"strings"
"github.com/bradfitz/gomemcache/memcache"
"time"
"github.com/astaxie/beego/cache"
)
// Cache Memcache adapter.
type Cache struct {
conn *memcache.Client
conninfo []string
}
// NewMemCache create new memcache adapter.
func NewMemCache() cache.Cache {
return &Cache{}
}
// Get get value from memcache.
func (rc *Cache) Get(key string) interface{} {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
if item, err := rc.conn.Get(key); err == nil {
return string(item.Value)
}
return nil
}
// GetMulti get value from memcache.
func (rc *Cache) GetMulti(keys []string) []interface{} {
size := len(keys)
var rv []interface{}
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
for i := 0; i < size; i++ {
rv = append(rv, err)
}
return rv
}
}
mv, err := rc.conn.GetMulti(keys)
if err == nil {
for _, v := range mv {
rv = append(rv, string(v.Value))
}
return rv
}
for i := 0; i < size; i++ {
rv = append(rv, err)
}
return rv
}
// Put put value to memcache. only support string.
func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
v, ok := val.(string)
if !ok {
return errors.New("val must string")
}
item := memcache.Item{Key: key, Value: []byte(v), Expiration: int32(timeout / time.Second)}
return rc.conn.Set(&item)
}
// Delete delete value in memcache.
func (rc *Cache) Delete(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
return rc.conn.Delete(key)
}
// Incr increase counter.
func (rc *Cache) Incr(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
_, err := rc.conn.Increment(key, 1)
return err
}
// Decr decrease counter.
func (rc *Cache) Decr(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
_, err := rc.conn.Decrement(key, 1)
return err
}
// IsExist check value exists in memcache.
func (rc *Cache) IsExist(key string) bool {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return false
}
}
_, err := rc.conn.Get(key)
if err != nil {
return false
}
return true
}
// ClearAll clear all cached in memcache.
func (rc *Cache) ClearAll() error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
return rc.conn.FlushAll()
}
// StartAndGC start memcache adapter.
// config string is like {"conn":"connection info"}.
// if connecting error, return.
func (rc *Cache) StartAndGC(config string) error {
var cf map[string]string
json.Unmarshal([]byte(config), &cf)
if _, ok := cf["conn"]; !ok {
return errors.New("config has no conn key")
}
rc.conninfo = strings.Split(cf["conn"], ";")
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
return nil
}
// connect to memcache and keep the connection.
func (rc *Cache) connectInit() error {
rc.conn = memcache.New(rc.conninfo...)
return nil
}
func init() {
cache.Register("memcache", NewMemCache)
}

View File

@ -0,0 +1,108 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 memcache
import (
_ "github.com/bradfitz/gomemcache/memcache"
"strconv"
"testing"
"time"
"github.com/astaxie/beego/cache"
)
func TestMemcacheCache(t *testing.T) {
bm, err := cache.NewCache("memcache", `{"conn": "127.0.0.1:11211"}`)
if err != nil {
t.Error("init err")
}
timeoutDuration := 10 * time.Second
if err = bm.Put("astaxie", "1", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie") {
t.Error("check err")
}
time.Sleep(11 * time.Second)
if bm.IsExist("astaxie") {
t.Error("check err")
}
if err = bm.Put("astaxie", "1", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if v, err := strconv.Atoi(bm.Get("astaxie").(string)); err != nil || v != 1 {
t.Error("get err")
}
if err = bm.Incr("astaxie"); err != nil {
t.Error("Incr Error", err)
}
if v, err := strconv.Atoi(bm.Get("astaxie").(string)); err != nil || v != 2 {
t.Error("get err")
}
if err = bm.Decr("astaxie"); err != nil {
t.Error("Decr Error", err)
}
if v, err := strconv.Atoi(bm.Get("astaxie").(string)); err != nil || v != 1 {
t.Error("get err")
}
bm.Delete("astaxie")
if bm.IsExist("astaxie") {
t.Error("delete err")
}
//test string
if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie") {
t.Error("check err")
}
if v := bm.Get("astaxie").(string); v != "author" {
t.Error("get err")
}
//test GetMulti
if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie1") {
t.Error("check err")
}
vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
if len(vv) != 2 {
t.Error("GetMulti ERROR")
}
if vv[0].(string) != "author" && vv[0].(string) != "author1" {
t.Error("GetMulti ERROR")
}
if vv[1].(string) != "author1" && vv[1].(string) != "author" {
t.Error("GetMulti ERROR")
}
// test clear all
if err = bm.ClearAll(); err != nil {
t.Error("clear all err")
}
}

View File

@ -0,0 +1,107 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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
import (
"testing"
"time"
"github.com/garyburd/redigo/redis"
"github.com/astaxie/beego/cache"
)
func TestRedisCache(t *testing.T) {
bm, err := cache.NewCache("redis", `{"conn": "127.0.0.1:6379"}`)
if err != nil {
t.Error("init err")
}
timeoutDuration := 10 * time.Second
if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie") {
t.Error("check err")
}
time.Sleep(11 * time.Second)
if bm.IsExist("astaxie") {
t.Error("check err")
}
if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
t.Error("set Error", err)
}
if v, _ := redis.Int(bm.Get("astaxie"), err); v != 1 {
t.Error("get err")
}
if err = bm.Incr("astaxie"); err != nil {
t.Error("Incr Error", err)
}
if v, _ := redis.Int(bm.Get("astaxie"), err); v != 2 {
t.Error("get err")
}
if err = bm.Decr("astaxie"); err != nil {
t.Error("Decr Error", err)
}
if v, _ := redis.Int(bm.Get("astaxie"), err); v != 1 {
t.Error("get err")
}
bm.Delete("astaxie")
if bm.IsExist("astaxie") {
t.Error("delete err")
}
//test string
if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie") {
t.Error("check err")
}
if v, _ := redis.String(bm.Get("astaxie"), err); v != "author" {
t.Error("get err")
}
//test GetMulti
if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !bm.IsExist("astaxie1") {
t.Error("check err")
}
vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
if len(vv) != 2 {
t.Error("GetMulti ERROR")
}
if v, _ := redis.String(vv[0], nil); v != "author" {
t.Error("GetMulti ERROR")
}
if v, _ := redis.String(vv[1], nil); v != "author1" {
t.Error("GetMulti ERROR")
}
// test clear all
if err = bm.ClearAll(); err != nil {
t.Error("clear all err")
}
}

240
src/vendor/github.com/astaxie/beego/cache/ssdb/ssdb.go generated vendored Normal file
View File

@ -0,0 +1,240 @@
package ssdb
import (
"encoding/json"
"errors"
"strconv"
"strings"
"time"
"github.com/ssdb/gossdb/ssdb"
"github.com/astaxie/beego/cache"
)
// Cache SSDB adapter
type Cache struct {
conn *ssdb.Client
conninfo []string
}
//NewSsdbCache create new ssdb adapter.
func NewSsdbCache() cache.Cache {
return &Cache{}
}
// Get get value from memcache.
func (rc *Cache) Get(key string) interface{} {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return nil
}
}
value, err := rc.conn.Get(key)
if err == nil {
return value
}
return nil
}
// GetMulti get value from memcache.
func (rc *Cache) GetMulti(keys []string) []interface{} {
size := len(keys)
var values []interface{}
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
for i := 0; i < size; i++ {
values = append(values, err)
}
return values
}
}
res, err := rc.conn.Do("multi_get", keys)
resSize := len(res)
if err == nil {
for i := 1; i < resSize; i += 2 {
values = append(values, string(res[i+1]))
}
return values
}
for i := 0; i < size; i++ {
values = append(values, err)
}
return values
}
// DelMulti get value from memcache.
func (rc *Cache) DelMulti(keys []string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
_, err := rc.conn.Do("multi_del", keys)
if err != nil {
return err
}
return nil
}
// Put put value to memcache. only support string.
func (rc *Cache) Put(key string, value interface{}, timeout time.Duration) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
v, ok := value.(string)
if !ok {
return errors.New("value must string")
}
var resp []string
var err error
ttl := int(timeout / time.Second)
if ttl < 0 {
resp, err = rc.conn.Do("set", key, v)
} else {
resp, err = rc.conn.Do("setx", key, v, ttl)
}
if err != nil {
return err
}
if len(resp) == 2 && resp[0] == "ok" {
return nil
}
return errors.New("bad response")
}
// Delete delete value in memcache.
func (rc *Cache) Delete(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
_, err := rc.conn.Del(key)
if err != nil {
return err
}
return nil
}
// Incr increase counter.
func (rc *Cache) Incr(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
_, err := rc.conn.Do("incr", key, 1)
return err
}
// Decr decrease counter.
func (rc *Cache) Decr(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
_, err := rc.conn.Do("incr", key, -1)
return err
}
// IsExist check value exists in memcache.
func (rc *Cache) IsExist(key string) bool {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return false
}
}
resp, err := rc.conn.Do("exists", key)
if err != nil {
return false
}
if resp[1] == "1" {
return true
}
return false
}
// ClearAll clear all cached in memcache.
func (rc *Cache) ClearAll() error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
keyStart, keyEnd, limit := "", "", 50
resp, err := rc.Scan(keyStart, keyEnd, limit)
for err == nil {
size := len(resp)
if size == 1 {
return nil
}
keys := []string{}
for i := 1; i < size; i += 2 {
keys = append(keys, string(resp[i]))
}
_, e := rc.conn.Do("multi_del", keys)
if e != nil {
return e
}
keyStart = resp[size-2]
resp, err = rc.Scan(keyStart, keyEnd, limit)
}
return err
}
// Scan key all cached in ssdb.
func (rc *Cache) Scan(keyStart string, keyEnd string, limit int) ([]string, error) {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return nil, err
}
}
resp, err := rc.conn.Do("scan", keyStart, keyEnd, limit)
if err != nil {
return nil, err
}
return resp, nil
}
// StartAndGC start memcache adapter.
// config string is like {"conn":"connection info"}.
// if connecting error, return.
func (rc *Cache) StartAndGC(config string) error {
var cf map[string]string
json.Unmarshal([]byte(config), &cf)
if _, ok := cf["conn"]; !ok {
return errors.New("config has no conn key")
}
rc.conninfo = strings.Split(cf["conn"], ";")
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
}
}
return nil
}
// connect to memcache and keep the connection.
func (rc *Cache) connectInit() error {
conninfoArray := strings.Split(rc.conninfo[0], ":")
host := conninfoArray[0]
port, e := strconv.Atoi(conninfoArray[1])
if e != nil {
return e
}
var err error
rc.conn, err = ssdb.Connect(host, port)
if err != nil {
return err
}
return nil
}
func init() {
cache.Register("ssdb", NewSsdbCache)
}

View File

@ -0,0 +1,103 @@
package ssdb
import (
"github.com/astaxie/beego/cache"
"strconv"
"testing"
"time"
)
func TestSsdbcacheCache(t *testing.T) {
ssdb, err := cache.NewCache("ssdb", `{"conn": "127.0.0.1:8888"}`)
if err != nil {
t.Error("init err")
}
// test put and exist
if ssdb.IsExist("ssdb") {
t.Error("check err")
}
timeoutDuration := 10 * time.Second
//timeoutDuration := -10*time.Second if timeoutDuration is negtive,it means permanent
if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if !ssdb.IsExist("ssdb") {
t.Error("check err")
}
// Get test done
if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if v := ssdb.Get("ssdb"); v != "ssdb" {
t.Error("get Error")
}
//inc/dec test done
if err = ssdb.Put("ssdb", "2", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if err = ssdb.Incr("ssdb"); err != nil {
t.Error("incr Error", err)
}
if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 {
t.Error("get err")
}
if err = ssdb.Decr("ssdb"); err != nil {
t.Error("decr error")
}
// test del
if err = ssdb.Put("ssdb", "3", timeoutDuration); err != nil {
t.Error("set Error", err)
}
if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 {
t.Error("get err")
}
if err := ssdb.Delete("ssdb"); err == nil {
if ssdb.IsExist("ssdb") {
t.Error("delete err")
}
}
//test string
if err = ssdb.Put("ssdb", "ssdb", -10*time.Second); err != nil {
t.Error("set Error", err)
}
if !ssdb.IsExist("ssdb") {
t.Error("check err")
}
if v := ssdb.Get("ssdb").(string); v != "ssdb" {
t.Error("get err")
}
//test GetMulti done
if err = ssdb.Put("ssdb1", "ssdb1", -10*time.Second); err != nil {
t.Error("set Error", err)
}
if !ssdb.IsExist("ssdb1") {
t.Error("check err")
}
vv := ssdb.GetMulti([]string{"ssdb", "ssdb1"})
if len(vv) != 2 {
t.Error("getmulti error")
}
if vv[0].(string) != "ssdb" {
t.Error("getmulti error")
}
if vv[1].(string) != "ssdb1" {
t.Error("getmulti error")
}
// test clear all done
if err = ssdb.ClearAll(); err != nil {
t.Error("clear all err")
}
if ssdb.IsExist("ssdb") || ssdb.IsExist("ssdb1") {
t.Error("check err")
}
}

184
src/vendor/github.com/astaxie/beego/config/ini_test.go generated vendored Normal file
View File

@ -0,0 +1,184 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 config
import (
"fmt"
"io/ioutil"
"os"
"strings"
"testing"
)
func TestIni(t *testing.T) {
var (
inicontext = `
;comment one
#comment two
appname = beeapi
httpport = 8080
mysqlport = 3600
PI = 3.1415976
runmode = "dev"
autorender = false
copyrequestbody = true
session= on
cookieon= off
newreg = OFF
needlogin = ON
enableSession = Y
enableCookie = N
flag = 1
[demo]
key1="asta"
key2 = "xie"
CaseInsensitive = true
peers = one;two;three
`
keyValue = map[string]interface{}{
"appname": "beeapi",
"httpport": 8080,
"mysqlport": int64(3600),
"pi": 3.1415976,
"runmode": "dev",
"autorender": false,
"copyrequestbody": true,
"session": true,
"cookieon": false,
"newreg": false,
"needlogin": true,
"enableSession": true,
"enableCookie": false,
"flag": true,
"demo::key1": "asta",
"demo::key2": "xie",
"demo::CaseInsensitive": true,
"demo::peers": []string{"one", "two", "three"},
"null": "",
"demo2::key1": "",
"error": "",
"emptystrings": []string{},
}
)
f, err := os.Create("testini.conf")
if err != nil {
t.Fatal(err)
}
_, err = f.WriteString(inicontext)
if err != nil {
f.Close()
t.Fatal(err)
}
f.Close()
defer os.Remove("testini.conf")
iniconf, err := NewConfig("ini", "testini.conf")
if err != nil {
t.Fatal(err)
}
for k, v := range keyValue {
var err error
var value interface{}
switch v.(type) {
case int:
value, err = iniconf.Int(k)
case int64:
value, err = iniconf.Int64(k)
case float64:
value, err = iniconf.Float(k)
case bool:
value, err = iniconf.Bool(k)
case []string:
value = iniconf.Strings(k)
case string:
value = iniconf.String(k)
default:
value, err = iniconf.DIY(k)
}
if err != nil {
t.Fatalf("get key %q value fail,err %s", k, err)
} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
t.Fatalf("get key %q value, want %v got %v .", k, v, value)
}
}
if err = iniconf.Set("name", "astaxie"); err != nil {
t.Fatal(err)
}
if iniconf.String("name") != "astaxie" {
t.Fatal("get name error")
}
}
func TestIniSave(t *testing.T) {
const (
inicontext = `
app = app
;comment one
#comment two
# comment three
appname = beeapi
httpport = 8080
# DB Info
# enable db
[dbinfo]
# db type name
# suport mysql,sqlserver
name = mysql
`
saveResult = `
app=app
#comment one
#comment two
# comment three
appname=beeapi
httpport=8080
# DB Info
# enable db
[dbinfo]
# db type name
# suport mysql,sqlserver
name=mysql
`
)
cfg, err := NewConfigData("ini", []byte(inicontext))
if err != nil {
t.Fatal(err)
}
name := "newIniConfig.ini"
if err := cfg.SaveConfigFile(name); err != nil {
t.Fatal(err)
}
defer os.Remove(name)
if data, err := ioutil.ReadFile(name); err != nil {
t.Fatal(err)
} else {
cfgData := string(data)
datas := strings.Split(saveResult, "\n")
for _, line := range datas {
if strings.Contains(cfgData, line+"\n") == false {
t.Fatalf("different after save ini config file. need contains %q", line)
}
}
}
}

216
src/vendor/github.com/astaxie/beego/config/json_test.go generated vendored Normal file
View File

@ -0,0 +1,216 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 config
import (
"fmt"
"os"
"testing"
)
func TestJsonStartsWithArray(t *testing.T) {
const jsoncontextwitharray = `[
{
"url": "user",
"serviceAPI": "http://www.test.com/user"
},
{
"url": "employee",
"serviceAPI": "http://www.test.com/employee"
}
]`
f, err := os.Create("testjsonWithArray.conf")
if err != nil {
t.Fatal(err)
}
_, err = f.WriteString(jsoncontextwitharray)
if err != nil {
f.Close()
t.Fatal(err)
}
f.Close()
defer os.Remove("testjsonWithArray.conf")
jsonconf, err := NewConfig("json", "testjsonWithArray.conf")
if err != nil {
t.Fatal(err)
}
rootArray, err := jsonconf.DIY("rootArray")
if err != nil {
t.Error("array does not exist as element")
}
rootArrayCasted := rootArray.([]interface{})
if rootArrayCasted == nil {
t.Error("array from root is nil")
} else {
elem := rootArrayCasted[0].(map[string]interface{})
if elem["url"] != "user" || elem["serviceAPI"] != "http://www.test.com/user" {
t.Error("array[0] values are not valid")
}
elem2 := rootArrayCasted[1].(map[string]interface{})
if elem2["url"] != "employee" || elem2["serviceAPI"] != "http://www.test.com/employee" {
t.Error("array[1] values are not valid")
}
}
}
func TestJson(t *testing.T) {
var (
jsoncontext = `{
"appname": "beeapi",
"testnames": "foo;bar",
"httpport": 8080,
"mysqlport": 3600,
"PI": 3.1415976,
"runmode": "dev",
"autorender": false,
"copyrequestbody": true,
"session": "on",
"cookieon": "off",
"newreg": "OFF",
"needlogin": "ON",
"enableSession": "Y",
"enableCookie": "N",
"flag": 1,
"database": {
"host": "host",
"port": "port",
"database": "database",
"username": "username",
"password": "password",
"conns":{
"maxconnection":12,
"autoconnect":true,
"connectioninfo":"info"
}
}
}`
keyValue = map[string]interface{}{
"appname": "beeapi",
"testnames": []string{"foo", "bar"},
"httpport": 8080,
"mysqlport": int64(3600),
"PI": 3.1415976,
"runmode": "dev",
"autorender": false,
"copyrequestbody": true,
"session": true,
"cookieon": false,
"newreg": false,
"needlogin": true,
"enableSession": true,
"enableCookie": false,
"flag": true,
"database::host": "host",
"database::port": "port",
"database::database": "database",
"database::password": "password",
"database::conns::maxconnection": 12,
"database::conns::autoconnect": true,
"database::conns::connectioninfo": "info",
"unknown": "",
}
)
f, err := os.Create("testjson.conf")
if err != nil {
t.Fatal(err)
}
_, err = f.WriteString(jsoncontext)
if err != nil {
f.Close()
t.Fatal(err)
}
f.Close()
defer os.Remove("testjson.conf")
jsonconf, err := NewConfig("json", "testjson.conf")
if err != nil {
t.Fatal(err)
}
for k, v := range keyValue {
var err error
var value interface{}
switch v.(type) {
case int:
value, err = jsonconf.Int(k)
case int64:
value, err = jsonconf.Int64(k)
case float64:
value, err = jsonconf.Float(k)
case bool:
value, err = jsonconf.Bool(k)
case []string:
value = jsonconf.Strings(k)
case string:
value = jsonconf.String(k)
default:
value, err = jsonconf.DIY(k)
}
if err != nil {
t.Fatalf("get key %q value fatal,%v err %s", k, v, err)
} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
t.Fatalf("get key %q value, want %v got %v .", k, v, value)
}
}
if err = jsonconf.Set("name", "astaxie"); err != nil {
t.Fatal(err)
}
if jsonconf.String("name") != "astaxie" {
t.Fatal("get name error")
}
if db, err := jsonconf.DIY("database"); err != nil {
t.Fatal(err)
} else if m, ok := db.(map[string]interface{}); !ok {
t.Log(db)
t.Fatal("db not map[string]interface{}")
} else {
if m["host"].(string) != "host" {
t.Fatal("get host err")
}
}
if _, err := jsonconf.Int("unknown"); err == nil {
t.Error("unknown keys should return an error when expecting an Int")
}
if _, err := jsonconf.Int64("unknown"); err == nil {
t.Error("unknown keys should return an error when expecting an Int64")
}
if _, err := jsonconf.Float("unknown"); err == nil {
t.Error("unknown keys should return an error when expecting a Float")
}
if _, err := jsonconf.DIY("unknown"); err == nil {
t.Error("unknown keys should return an error when expecting an interface{}")
}
if val := jsonconf.String("unknown"); val != "" {
t.Error("unknown keys should return an empty string when expecting a String")
}
if _, err := jsonconf.Bool("unknown"); err == nil {
t.Error("unknown keys should return an error when expecting a Bool")
}
if !jsonconf.DefaultBool("unknow", true) {
t.Error("unknown keys with default value wrong")
}
}

236
src/vendor/github.com/astaxie/beego/config/xml/xml.go generated vendored Normal file
View File

@ -0,0 +1,236 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 xml for config provider
//
// depend on github.com/beego/x2j
//
// go install github.com/beego/x2j
//
// Usage:
// import(
// _ "github.com/astaxie/beego/config/xml"
// "github.com/astaxie/beego/config"
// )
//
// cnf, err := config.NewConfig("xml", "config.xml")
//
// more docs http://beego.me/docs/module/config.md
package xml
import (
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"strconv"
"strings"
"sync"
"time"
"github.com/astaxie/beego/config"
"github.com/beego/x2j"
)
// Config is a xml config parser and implements Config interface.
// xml configurations should be included in <config></config> tag.
// only support key/value pair as <key>value</key> as each item.
type Config struct{}
// Parse returns a ConfigContainer with parsed xml config map.
func (xc *Config) Parse(filename string) (config.Configer, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
x := &ConfigContainer{data: make(map[string]interface{})}
content, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
d, err := x2j.DocToMap(string(content))
if err != nil {
return nil, err
}
x.data = d["config"].(map[string]interface{})
return x, nil
}
// ParseData xml data
func (xc *Config) ParseData(data []byte) (config.Configer, error) {
// Save memory data to temporary file
tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond()))
os.MkdirAll(path.Dir(tmpName), os.ModePerm)
if err := ioutil.WriteFile(tmpName, data, 0655); err != nil {
return nil, err
}
return xc.Parse(tmpName)
}
// ConfigContainer A Config represents the xml configuration.
type ConfigContainer struct {
data map[string]interface{}
sync.Mutex
}
// Bool returns the boolean value for a given key.
func (c *ConfigContainer) Bool(key string) (bool, error) {
if v, ok := c.data[key]; ok {
return config.ParseBool(v)
}
return false, fmt.Errorf("not exist key: %q", key)
}
// DefaultBool return the bool value if has no error
// otherwise return the defaultval
func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
v, err := c.Bool(key)
if err != nil {
return defaultval
}
return v
}
// Int returns the integer value for a given key.
func (c *ConfigContainer) Int(key string) (int, error) {
return strconv.Atoi(c.data[key].(string))
}
// DefaultInt returns the integer value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
v, err := c.Int(key)
if err != nil {
return defaultval
}
return v
}
// Int64 returns the int64 value for a given key.
func (c *ConfigContainer) Int64(key string) (int64, error) {
return strconv.ParseInt(c.data[key].(string), 10, 64)
}
// DefaultInt64 returns the int64 value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
v, err := c.Int64(key)
if err != nil {
return defaultval
}
return v
}
// Float returns the float value for a given key.
func (c *ConfigContainer) Float(key string) (float64, error) {
return strconv.ParseFloat(c.data[key].(string), 64)
}
// DefaultFloat returns the float64 value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
v, err := c.Float(key)
if err != nil {
return defaultval
}
return v
}
// String returns the string value for a given key.
func (c *ConfigContainer) String(key string) string {
if v, ok := c.data[key].(string); ok {
return v
}
return ""
}
// DefaultString returns the string value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
v := c.String(key)
if v == "" {
return defaultval
}
return v
}
// Strings returns the []string value for a given key.
func (c *ConfigContainer) Strings(key string) []string {
v := c.String(key)
if v == "" {
return nil
}
return strings.Split(v, ";")
}
// DefaultStrings returns the []string value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
v := c.Strings(key)
if v == nil {
return defaultval
}
return v
}
// GetSection returns map for the given section
func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
if v, ok := c.data[section]; ok {
return v.(map[string]string), nil
}
return nil, errors.New("not exist setction")
}
// SaveConfigFile save the config into file
func (c *ConfigContainer) SaveConfigFile(filename string) (err error) {
// Write configuration file by filename.
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
b, err := xml.MarshalIndent(c.data, " ", " ")
if err != nil {
return err
}
_, err = f.Write(b)
return err
}
// Set writes a new value for key.
func (c *ConfigContainer) Set(key, val string) error {
c.Lock()
defer c.Unlock()
c.data[key] = val
return nil
}
// DIY returns the raw value by a given key.
func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
if v, ok := c.data[key]; ok {
return v, nil
}
return nil, errors.New("not exist key")
}
func init() {
config.Register("xml", &Config{})
}

View File

@ -0,0 +1,88 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 xml
import (
"os"
"testing"
"github.com/astaxie/beego/config"
)
//xml parse should incluce in <config></config> tags
var xmlcontext = `<?xml version="1.0" encoding="UTF-8"?>
<config>
<appname>beeapi</appname>
<httpport>8080</httpport>
<mysqlport>3600</mysqlport>
<PI>3.1415976</PI>
<runmode>dev</runmode>
<autorender>false</autorender>
<copyrequestbody>true</copyrequestbody>
</config>
`
func TestXML(t *testing.T) {
f, err := os.Create("testxml.conf")
if err != nil {
t.Fatal(err)
}
_, err = f.WriteString(xmlcontext)
if err != nil {
f.Close()
t.Fatal(err)
}
f.Close()
defer os.Remove("testxml.conf")
xmlconf, err := config.NewConfig("xml", "testxml.conf")
if err != nil {
t.Fatal(err)
}
if xmlconf.String("appname") != "beeapi" {
t.Fatal("appname not equal to beeapi")
}
if port, err := xmlconf.Int("httpport"); err != nil || port != 8080 {
t.Error(port)
t.Fatal(err)
}
if port, err := xmlconf.Int64("mysqlport"); err != nil || port != 3600 {
t.Error(port)
t.Fatal(err)
}
if pi, err := xmlconf.Float("PI"); err != nil || pi != 3.1415976 {
t.Error(pi)
t.Fatal(err)
}
if xmlconf.String("runmode") != "dev" {
t.Fatal("runmode not equal to dev")
}
if v, err := xmlconf.Bool("autorender"); err != nil || v != false {
t.Error(v)
t.Fatal(err)
}
if v, err := xmlconf.Bool("copyrequestbody"); err != nil || v != true {
t.Error(v)
t.Fatal(err)
}
if err = xmlconf.Set("name", "astaxie"); err != nil {
t.Fatal(err)
}
if xmlconf.String("name") != "astaxie" {
t.Fatal("get name error")
}
if xmlconf.Strings("emptystrings") != nil {
t.Fatal("get emtpy strings error")
}
}

270
src/vendor/github.com/astaxie/beego/config/yaml/yaml.go generated vendored Normal file
View File

@ -0,0 +1,270 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 yaml for config provider
//
// depend on github.com/beego/goyaml2
//
// go install github.com/beego/goyaml2
//
// Usage:
// import(
// _ "github.com/astaxie/beego/config/yaml"
// "github.com/astaxie/beego/config"
// )
//
// cnf, err := config.NewConfig("yaml", "config.yaml")
//
// more docs http://beego.me/docs/module/config.md
package yaml
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path"
"strings"
"sync"
"time"
"github.com/astaxie/beego/config"
"github.com/beego/goyaml2"
)
// Config is a yaml config parser and implements Config interface.
type Config struct{}
// Parse returns a ConfigContainer with parsed yaml config map.
func (yaml *Config) Parse(filename string) (y config.Configer, err error) {
cnf, err := ReadYmlReader(filename)
if err != nil {
return
}
y = &ConfigContainer{
data: cnf,
}
return
}
// ParseData parse yaml data
func (yaml *Config) ParseData(data []byte) (config.Configer, error) {
// Save memory data to temporary file
tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond()))
os.MkdirAll(path.Dir(tmpName), os.ModePerm)
if err := ioutil.WriteFile(tmpName, data, 0655); err != nil {
return nil, err
}
return yaml.Parse(tmpName)
}
// ReadYmlReader Read yaml file to map.
// if json like, use json package, unless goyaml2 package.
func ReadYmlReader(path string) (cnf map[string]interface{}, err error) {
f, err := os.Open(path)
if err != nil {
return
}
defer f.Close()
buf, err := ioutil.ReadAll(f)
if err != nil || len(buf) < 3 {
return
}
if string(buf[0:1]) == "{" {
log.Println("Look like a Json, try json umarshal")
err = json.Unmarshal(buf, &cnf)
if err == nil {
log.Println("It is Json Map")
return
}
}
data, err := goyaml2.Read(bytes.NewBuffer(buf))
if err != nil {
log.Println("Goyaml2 ERR>", string(buf), err)
return
}
if data == nil {
log.Println("Goyaml2 output nil? Pls report bug\n" + string(buf))
return
}
cnf, ok := data.(map[string]interface{})
if !ok {
log.Println("Not a Map? >> ", string(buf), data)
cnf = nil
}
return
}
// ConfigContainer A Config represents the yaml configuration.
type ConfigContainer struct {
data map[string]interface{}
sync.Mutex
}
// Bool returns the boolean value for a given key.
func (c *ConfigContainer) Bool(key string) (bool, error) {
if v, ok := c.data[key]; ok {
return config.ParseBool(v)
}
return false, fmt.Errorf("not exist key: %q", key)
}
// DefaultBool return the bool value if has no error
// otherwise return the defaultval
func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
v, err := c.Bool(key)
if err != nil {
return defaultval
}
return v
}
// Int returns the integer value for a given key.
func (c *ConfigContainer) Int(key string) (int, error) {
if v, ok := c.data[key].(int64); ok {
return int(v), nil
}
return 0, errors.New("not int value")
}
// DefaultInt returns the integer value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
v, err := c.Int(key)
if err != nil {
return defaultval
}
return v
}
// Int64 returns the int64 value for a given key.
func (c *ConfigContainer) Int64(key string) (int64, error) {
if v, ok := c.data[key].(int64); ok {
return v, nil
}
return 0, errors.New("not bool value")
}
// DefaultInt64 returns the int64 value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
v, err := c.Int64(key)
if err != nil {
return defaultval
}
return v
}
// Float returns the float value for a given key.
func (c *ConfigContainer) Float(key string) (float64, error) {
if v, ok := c.data[key].(float64); ok {
return v, nil
}
return 0.0, errors.New("not float64 value")
}
// DefaultFloat returns the float64 value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
v, err := c.Float(key)
if err != nil {
return defaultval
}
return v
}
// String returns the string value for a given key.
func (c *ConfigContainer) String(key string) string {
if v, ok := c.data[key].(string); ok {
return v
}
return ""
}
// DefaultString returns the string value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
v := c.String(key)
if v == "" {
return defaultval
}
return v
}
// Strings returns the []string value for a given key.
func (c *ConfigContainer) Strings(key string) []string {
v := c.String(key)
if v == "" {
return nil
}
return strings.Split(v, ";")
}
// DefaultStrings returns the []string value for a given key.
// if err != nil return defaltval
func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
v := c.Strings(key)
if v == nil {
return defaultval
}
return v
}
// GetSection returns map for the given section
func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
v, ok := c.data[section]
if ok {
return v.(map[string]string), nil
}
return nil, errors.New("not exist setction")
}
// SaveConfigFile save the config into file
func (c *ConfigContainer) SaveConfigFile(filename string) (err error) {
// Write configuration file by filename.
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
err = goyaml2.Write(f, c.data)
return err
}
// Set writes a new value for key.
func (c *ConfigContainer) Set(key, val string) error {
c.Lock()
defer c.Unlock()
c.data[key] = val
return nil
}
// DIY returns the raw value by a given key.
func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
if v, ok := c.data[key]; ok {
return v, nil
}
return nil, errors.New("not exist key")
}
func init() {
config.Register("yaml", &Config{})
}

View File

@ -0,0 +1,86 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 yaml
import (
"os"
"testing"
"github.com/astaxie/beego/config"
)
var yamlcontext = `
"appname": beeapi
"httpport": 8080
"mysqlport": 3600
"PI": 3.1415976
"runmode": dev
"autorender": false
"copyrequestbody": true
`
func TestYaml(t *testing.T) {
f, err := os.Create("testyaml.conf")
if err != nil {
t.Fatal(err)
}
_, err = f.WriteString(yamlcontext)
if err != nil {
f.Close()
t.Fatal(err)
}
f.Close()
defer os.Remove("testyaml.conf")
yamlconf, err := config.NewConfig("yaml", "testyaml.conf")
if err != nil {
t.Fatal(err)
}
if yamlconf.String("appname") != "beeapi" {
t.Fatal("appname not equal to beeapi")
}
if port, err := yamlconf.Int("httpport"); err != nil || port != 8080 {
t.Error(port)
t.Fatal(err)
}
if port, err := yamlconf.Int64("mysqlport"); err != nil || port != 3600 {
t.Error(port)
t.Fatal(err)
}
if pi, err := yamlconf.Float("PI"); err != nil || pi != 3.1415976 {
t.Error(pi)
t.Fatal(err)
}
if yamlconf.String("runmode") != "dev" {
t.Fatal("runmode not equal to dev")
}
if v, err := yamlconf.Bool("autorender"); err != nil || v != false {
t.Error(v)
t.Fatal(err)
}
if v, err := yamlconf.Bool("copyrequestbody"); err != nil || v != true {
t.Error(v)
t.Fatal(err)
}
if err = yamlconf.Set("name", "astaxie"); err != nil {
t.Fatal(err)
}
if yamlconf.String("name") != "astaxie" {
t.Fatal("get name error")
}
if yamlconf.Strings("emptystrings") != nil {
t.Fatal("get emtpy strings error")
}
}

29
src/vendor/github.com/astaxie/beego/config_test.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"testing"
)
func TestDefaults(t *testing.T) {
if BConfig.WebConfig.FlashName != "BEEGO_FLASH" {
t.Errorf("FlashName was not set to default.")
}
if BConfig.WebConfig.FlashSeparator != "BEEGOFLASH" {
t.Errorf("FlashName was not set to default.")
}
}

View File

@ -0,0 +1,44 @@
// Copyright 2015 beego Author. All Rights Reserved.
//
// 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 context
import (
"net/http"
"testing"
)
func Test_ExtractEncoding(t *testing.T) {
if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip,deflate"}}}) != "gzip" {
t.Fail()
}
if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"deflate,gzip"}}}) != "deflate" {
t.Fail()
}
if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=.5,deflate"}}}) != "deflate" {
t.Fail()
}
if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=.5,deflate;q=0.3"}}}) != "gzip" {
t.Fail()
}
if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=0,deflate"}}}) != "deflate" {
t.Fail()
}
if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"deflate;q=0.5,gzip;q=0.5,identity"}}}) != "" {
t.Fail()
}
if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"*"}}}) != "gzip" {
t.Fail()
}
}

View File

@ -0,0 +1,173 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 context
import (
"fmt"
"net/http"
"net/http/httptest"
"reflect"
"testing"
)
func TestParse(t *testing.T) {
r, _ := http.NewRequest("GET", "/?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie", nil)
beegoInput := NewInput()
beegoInput.Context = NewContext()
beegoInput.Context.Reset(httptest.NewRecorder(), r)
beegoInput.ParseFormOrMulitForm(1 << 20)
var id int
err := beegoInput.Bind(&id, "id")
if id != 123 || err != nil {
t.Fatal("id should has int value")
}
fmt.Println(id)
var isok bool
err = beegoInput.Bind(&isok, "isok")
if !isok || err != nil {
t.Fatal("isok should be true")
}
fmt.Println(isok)
var float float64
err = beegoInput.Bind(&float, "ft")
if float != 1.2 || err != nil {
t.Fatal("float should be equal to 1.2")
}
fmt.Println(float)
ol := make([]int, 0, 2)
err = beegoInput.Bind(&ol, "ol")
if len(ol) != 2 || err != nil || ol[0] != 1 || ol[1] != 2 {
t.Fatal("ol should has two elements")
}
fmt.Println(ol)
ul := make([]string, 0, 2)
err = beegoInput.Bind(&ul, "ul")
if len(ul) != 2 || err != nil || ul[0] != "str" || ul[1] != "array" {
t.Fatal("ul should has two elements")
}
fmt.Println(ul)
type User struct {
Name string
}
user := User{}
err = beegoInput.Bind(&user, "user")
if err != nil || user.Name != "astaxie" {
t.Fatal("user should has name")
}
fmt.Println(user)
}
func TestSubDomain(t *testing.T) {
r, _ := http.NewRequest("GET", "http://www.example.com/?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie", nil)
beegoInput := NewInput()
beegoInput.Context = NewContext()
beegoInput.Context.Reset(httptest.NewRecorder(), r)
subdomain := beegoInput.SubDomains()
if subdomain != "www" {
t.Fatal("Subdomain parse error, got" + subdomain)
}
r, _ = http.NewRequest("GET", "http://localhost/", nil)
beegoInput.Context.Request = r
if beegoInput.SubDomains() != "" {
t.Fatal("Subdomain parse error, should be empty, got " + beegoInput.SubDomains())
}
r, _ = http.NewRequest("GET", "http://aa.bb.example.com/", nil)
beegoInput.Context.Request = r
if beegoInput.SubDomains() != "aa.bb" {
t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
}
/* TODO Fix this
r, _ = http.NewRequest("GET", "http://127.0.0.1/", nil)
beegoInput.Request = r
if beegoInput.SubDomains() != "" {
t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
}
*/
r, _ = http.NewRequest("GET", "http://example.com/", nil)
beegoInput.Context.Request = r
if beegoInput.SubDomains() != "" {
t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
}
r, _ = http.NewRequest("GET", "http://aa.bb.cc.dd.example.com/", nil)
beegoInput.Context.Request = r
if beegoInput.SubDomains() != "aa.bb.cc.dd" {
t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
}
}
func TestParams(t *testing.T) {
inp := NewInput()
inp.SetParam("p1", "val1_ver1")
inp.SetParam("p2", "val2_ver1")
inp.SetParam("p3", "val3_ver1")
if l := inp.ParamsLen(); l != 3 {
t.Fatalf("Input.ParamsLen wrong value: %d, expected %d", l, 3)
}
if val := inp.Param("p1"); val != "val1_ver1" {
t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver1")
}
if val := inp.Param("p3"); val != "val3_ver1" {
t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val3_ver1")
}
vals := inp.Params()
expected := map[string]string{
"p1": "val1_ver1",
"p2": "val2_ver1",
"p3": "val3_ver1",
}
if !reflect.DeepEqual(vals, expected) {
t.Fatalf("Input.Params wrong value: %s, expected %s", vals, expected)
}
// overwriting existing params
inp.SetParam("p1", "val1_ver2")
inp.SetParam("p2", "val2_ver2")
expected = map[string]string{
"p1": "val1_ver2",
"p2": "val2_ver2",
"p3": "val3_ver1",
}
vals = inp.Params()
if !reflect.DeepEqual(vals, expected) {
t.Fatalf("Input.Params wrong value: %s, expected %s", vals, expected)
}
if l := inp.ParamsLen(); l != 3 {
t.Fatalf("Input.ParamsLen wrong value: %d, expected %d", l, 3)
}
if val := inp.Param("p1"); val != "val1_ver2" {
t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver2")
}
if val := inp.Param("p2"); val != "val2_ver2" {
t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver2")
}
}

77
src/vendor/github.com/astaxie/beego/controller_test.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"testing"
"github.com/astaxie/beego/context"
)
func TestGetInt(t *testing.T) {
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt("age")
if val != 40 {
t.Errorf("TestGetInt expect 40,get %T,%v", val, val)
}
}
func TestGetInt8(t *testing.T) {
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt8("age")
if val != 40 {
t.Errorf("TestGetInt8 expect 40,get %T,%v", val, val)
}
//Output: int8
}
func TestGetInt16(t *testing.T) {
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt16("age")
if val != 40 {
t.Errorf("TestGetInt16 expect 40,get %T,%v", val, val)
}
}
func TestGetInt32(t *testing.T) {
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt32("age")
if val != 40 {
t.Errorf("TestGetInt32 expect 40,get %T,%v", val, val)
}
}
func TestGetInt64(t *testing.T) {
i := context.NewInput()
i.SetParam("age", "40")
ctx := &context.Context{Input: i}
ctrlr := Controller{Ctx: ctx}
val, _ := ctrlr.GetInt64("age")
if val != 40 {
t.Errorf("TestGeetInt64 expect 40,get %T,%v", val, val)
}
}

74
src/vendor/github.com/astaxie/beego/filter_test.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/logs"
)
func init() {
BeeLogger = logs.NewLogger(10000)
BeeLogger.SetLogger("console", "")
}
var FilterUser = func(ctx *context.Context) {
ctx.Output.Body([]byte("i am " + ctx.Input.Param(":last") + ctx.Input.Param(":first")))
}
func TestFilter(t *testing.T) {
r, _ := http.NewRequest("GET", "/person/asta/Xie", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.InsertFilter("/person/:last/:first", BeforeRouter, FilterUser)
handler.Add("/person/:last/:first", &TestController{})
handler.ServeHTTP(w, r)
if w.Body.String() != "i am astaXie" {
t.Errorf("user define func can't run")
}
}
var FilterAdminUser = func(ctx *context.Context) {
ctx.Output.Body([]byte("i am admin"))
}
// Filter pattern /admin/:all
// all url like /admin/ /admin/xie will all get filter
func TestPatternTwo(t *testing.T) {
r, _ := http.NewRequest("GET", "/admin/", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.InsertFilter("/admin/?:all", BeforeRouter, FilterAdminUser)
handler.ServeHTTP(w, r)
if w.Body.String() != "i am admin" {
t.Errorf("filter /admin/ can't run")
}
}
func TestPatternThree(t *testing.T) {
r, _ := http.NewRequest("GET", "/admin/astaxie", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.InsertFilter("/admin/:all", BeforeRouter, FilterAdminUser)
handler.ServeHTTP(w, r)
if w.Body.String() != "i am admin" {
t.Errorf("filter /admin/astaxie can't run")
}
}

54
src/vendor/github.com/astaxie/beego/flash_test.go generated vendored Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
type TestFlashController struct {
Controller
}
func (t *TestFlashController) TestWriteFlash() {
flash := NewFlash()
flash.Notice("TestFlashString")
flash.Store(&t.Controller)
// we choose to serve json because we don't want to load a template html file
t.ServeJSON(true)
}
func TestFlashHeader(t *testing.T) {
// create fake GET request
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
// setup the handler
handler := NewControllerRegister()
handler.Add("/", &TestFlashController{}, "get:TestWriteFlash")
handler.ServeHTTP(w, r)
// get the Set-Cookie value
sc := w.Header().Get("Set-Cookie")
// match for the expected header
res := strings.Contains(sc, "BEEGO_FLASH=%00notice%23BEEGOFLASH%23TestFlashString%00")
// validate the assertion
if res != true {
t.Errorf("TestFlashHeader() unable to validate flash message")
}
}

97
src/vendor/github.com/astaxie/beego/httplib/README.md generated vendored Normal file
View File

@ -0,0 +1,97 @@
# httplib
httplib is an libs help you to curl remote url.
# How to use?
## GET
you can use Get to crawl data.
import "github.com/astaxie/beego/httplib"
str, err := httplib.Get("http://beego.me/").String()
if err != nil {
// error
}
fmt.Println(str)
## POST
POST data to remote url
req := httplib.Post("http://beego.me/")
req.Param("username","astaxie")
req.Param("password","123456")
str, err := req.String()
if err != nil {
// error
}
fmt.Println(str)
## Set timeout
The default timeout is `60` seconds, function prototype:
SetTimeout(connectTimeout, readWriteTimeout time.Duration)
Exmaple:
// GET
httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
// POST
httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
## Debug
If you want to debug the request info, set the debug on
httplib.Get("http://beego.me/").Debug(true)
## Set HTTP Basic Auth
str, err := Get("http://beego.me/").SetBasicAuth("user", "passwd").String()
if err != nil {
// error
}
fmt.Println(str)
## Set HTTPS
If request url is https, You can set the client support TSL:
httplib.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
More info about the `tls.Config` please visit http://golang.org/pkg/crypto/tls/#Config
## Set HTTP Version
some servers need to specify the protocol version of HTTP
httplib.Get("http://beego.me/").SetProtocolVersion("HTTP/1.1")
## Set Cookie
some http request need setcookie. So set it like this:
cookie := &http.Cookie{}
cookie.Name = "username"
cookie.Value = "astaxie"
httplib.Get("http://beego.me/").SetCookie(cookie)
## Upload file
httplib support mutil file upload, use `req.PostFile()`
req := httplib.Post("http://beego.me/")
req.Param("username","astaxie")
req.PostFile("uploadfile1", "httplib.pdf")
str, err := req.String()
if err != nil {
// error
}
fmt.Println(str)
See godoc for further documentation and examples.
* [godoc.org/github.com/astaxie/beego/httplib](https://godoc.org/github.com/astaxie/beego/httplib)

551
src/vendor/github.com/astaxie/beego/httplib/httplib.go generated vendored Normal file
View File

@ -0,0 +1,551 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 httplib is used as http.Client
// Usage:
//
// import "github.com/astaxie/beego/httplib"
//
// b := httplib.Post("http://beego.me/")
// b.Param("username","astaxie")
// b.Param("password","123456")
// b.PostFile("uploadfile1", "httplib.pdf")
// b.PostFile("uploadfile2", "httplib.txt")
// str, err := b.String()
// if err != nil {
// t.Fatal(err)
// }
// fmt.Println(str)
//
// more docs http://beego.me/docs/module/httplib.md
package httplib
import (
"bytes"
"compress/gzip"
"crypto/tls"
"encoding/json"
"encoding/xml"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net"
"net/http"
"net/http/cookiejar"
"net/http/httputil"
"net/url"
"os"
"strings"
"sync"
"time"
)
var defaultSetting = BeegoHTTPSettings{
UserAgent: "beegoServer",
ConnectTimeout: 60 * time.Second,
ReadWriteTimeout: 60 * time.Second,
Gzip: true,
DumpBody: true,
}
var defaultCookieJar http.CookieJar
var settingMutex sync.Mutex
// createDefaultCookie creates a global cookiejar to store cookies.
func createDefaultCookie() {
settingMutex.Lock()
defer settingMutex.Unlock()
defaultCookieJar, _ = cookiejar.New(nil)
}
// SetDefaultSetting Overwrite default settings
func SetDefaultSetting(setting BeegoHTTPSettings) {
settingMutex.Lock()
defer settingMutex.Unlock()
defaultSetting = setting
}
// NewBeegoRequest return *BeegoHttpRequest with specific method
func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest {
var resp http.Response
u, err := url.Parse(rawurl)
if err != nil {
log.Println("Httplib:", err)
}
req := http.Request{
URL: u,
Method: method,
Header: make(http.Header),
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
}
return &BeegoHTTPRequest{
url: rawurl,
req: &req,
params: map[string][]string{},
files: map[string]string{},
setting: defaultSetting,
resp: &resp,
}
}
// Get returns *BeegoHttpRequest with GET method.
func Get(url string) *BeegoHTTPRequest {
return NewBeegoRequest(url, "GET")
}
// Post returns *BeegoHttpRequest with POST method.
func Post(url string) *BeegoHTTPRequest {
return NewBeegoRequest(url, "POST")
}
// Put returns *BeegoHttpRequest with PUT method.
func Put(url string) *BeegoHTTPRequest {
return NewBeegoRequest(url, "PUT")
}
// Delete returns *BeegoHttpRequest DELETE method.
func Delete(url string) *BeegoHTTPRequest {
return NewBeegoRequest(url, "DELETE")
}
// Head returns *BeegoHttpRequest with HEAD method.
func Head(url string) *BeegoHTTPRequest {
return NewBeegoRequest(url, "HEAD")
}
// BeegoHTTPSettings is the http.Client setting
type BeegoHTTPSettings struct {
ShowDebug bool
UserAgent string
ConnectTimeout time.Duration
ReadWriteTimeout time.Duration
TLSClientConfig *tls.Config
Proxy func(*http.Request) (*url.URL, error)
Transport http.RoundTripper
EnableCookie bool
Gzip bool
DumpBody bool
}
// BeegoHTTPRequest provides more useful methods for requesting one url than http.Request.
type BeegoHTTPRequest struct {
url string
req *http.Request
params map[string][]string
files map[string]string
setting BeegoHTTPSettings
resp *http.Response
body []byte
dump []byte
}
// GetRequest return the request object
func (b *BeegoHTTPRequest) GetRequest() *http.Request {
return b.req
}
// Setting Change request settings
func (b *BeegoHTTPRequest) Setting(setting BeegoHTTPSettings) *BeegoHTTPRequest {
b.setting = setting
return b
}
// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password.
func (b *BeegoHTTPRequest) SetBasicAuth(username, password string) *BeegoHTTPRequest {
b.req.SetBasicAuth(username, password)
return b
}
// SetEnableCookie sets enable/disable cookiejar
func (b *BeegoHTTPRequest) SetEnableCookie(enable bool) *BeegoHTTPRequest {
b.setting.EnableCookie = enable
return b
}
// SetUserAgent sets User-Agent header field
func (b *BeegoHTTPRequest) SetUserAgent(useragent string) *BeegoHTTPRequest {
b.setting.UserAgent = useragent
return b
}
// Debug sets show debug or not when executing request.
func (b *BeegoHTTPRequest) Debug(isdebug bool) *BeegoHTTPRequest {
b.setting.ShowDebug = isdebug
return b
}
// DumpBody setting whether need to Dump the Body.
func (b *BeegoHTTPRequest) DumpBody(isdump bool) *BeegoHTTPRequest {
b.setting.DumpBody = isdump
return b
}
// DumpRequest return the DumpRequest
func (b *BeegoHTTPRequest) DumpRequest() []byte {
return b.dump
}
// SetTimeout sets connect time out and read-write time out for BeegoRequest.
func (b *BeegoHTTPRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHTTPRequest {
b.setting.ConnectTimeout = connectTimeout
b.setting.ReadWriteTimeout = readWriteTimeout
return b
}
// SetTLSClientConfig sets tls connection configurations if visiting https url.
func (b *BeegoHTTPRequest) SetTLSClientConfig(config *tls.Config) *BeegoHTTPRequest {
b.setting.TLSClientConfig = config
return b
}
// Header add header item string in request.
func (b *BeegoHTTPRequest) Header(key, value string) *BeegoHTTPRequest {
b.req.Header.Set(key, value)
return b
}
// SetHost set the request host
func (b *BeegoHTTPRequest) SetHost(host string) *BeegoHTTPRequest {
b.req.Host = host
return b
}
// SetProtocolVersion Set the protocol version for incoming requests.
// Client requests always use HTTP/1.1.
func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest {
if len(vers) == 0 {
vers = "HTTP/1.1"
}
major, minor, ok := http.ParseHTTPVersion(vers)
if ok {
b.req.Proto = vers
b.req.ProtoMajor = major
b.req.ProtoMinor = minor
}
return b
}
// SetCookie add cookie into request.
func (b *BeegoHTTPRequest) SetCookie(cookie *http.Cookie) *BeegoHTTPRequest {
b.req.Header.Add("Cookie", cookie.String())
return b
}
// SetTransport set the setting transport
func (b *BeegoHTTPRequest) SetTransport(transport http.RoundTripper) *BeegoHTTPRequest {
b.setting.Transport = transport
return b
}
// SetProxy set the http proxy
// example:
//
// func(req *http.Request) (*url.URL, error) {
// u, _ := url.ParseRequestURI("http://127.0.0.1:8118")
// return u, nil
// }
func (b *BeegoHTTPRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *BeegoHTTPRequest {
b.setting.Proxy = proxy
return b
}
// Param adds query param in to request.
// params build query string as ?key1=value1&key2=value2...
func (b *BeegoHTTPRequest) Param(key, value string) *BeegoHTTPRequest {
if param, ok := b.params[key]; ok {
b.params[key] = append(param, value)
} else {
b.params[key] = []string{value}
}
return b
}
// PostFile add a post file to the request
func (b *BeegoHTTPRequest) PostFile(formname, filename string) *BeegoHTTPRequest {
b.files[formname] = filename
return b
}
// Body adds request raw body.
// it supports string and []byte.
func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest {
switch t := data.(type) {
case string:
bf := bytes.NewBufferString(t)
b.req.Body = ioutil.NopCloser(bf)
b.req.ContentLength = int64(len(t))
case []byte:
bf := bytes.NewBuffer(t)
b.req.Body = ioutil.NopCloser(bf)
b.req.ContentLength = int64(len(t))
}
return b
}
// JSONBody adds request raw body encoding by JSON.
func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error) {
if b.req.Body == nil && obj != nil {
byts, err := json.Marshal(obj)
if err != nil {
return b, err
}
b.req.Body = ioutil.NopCloser(bytes.NewReader(byts))
b.req.ContentLength = int64(len(byts))
b.req.Header.Set("Content-Type", "application/json")
}
return b, nil
}
func (b *BeegoHTTPRequest) buildURL(paramBody string) {
// build GET url with query string
if b.req.Method == "GET" && len(paramBody) > 0 {
if strings.Index(b.url, "?") != -1 {
b.url += "&" + paramBody
} else {
b.url = b.url + "?" + paramBody
}
return
}
// build POST/PUT/PATCH url and body
if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH") && b.req.Body == nil {
// with files
if len(b.files) > 0 {
pr, pw := io.Pipe()
bodyWriter := multipart.NewWriter(pw)
go func() {
for formname, filename := range b.files {
fileWriter, err := bodyWriter.CreateFormFile(formname, filename)
if err != nil {
log.Println("Httplib:", err)
}
fh, err := os.Open(filename)
if err != nil {
log.Println("Httplib:", err)
}
//iocopy
_, err = io.Copy(fileWriter, fh)
fh.Close()
if err != nil {
log.Println("Httplib:", err)
}
}
for k, v := range b.params {
for _, vv := range v {
bodyWriter.WriteField(k, vv)
}
}
bodyWriter.Close()
pw.Close()
}()
b.Header("Content-Type", bodyWriter.FormDataContentType())
b.req.Body = ioutil.NopCloser(pr)
return
}
// with params
if len(paramBody) > 0 {
b.Header("Content-Type", "application/x-www-form-urlencoded")
b.Body(paramBody)
}
}
}
func (b *BeegoHTTPRequest) getResponse() (*http.Response, error) {
if b.resp.StatusCode != 0 {
return b.resp, nil
}
resp, err := b.DoRequest()
if err != nil {
return nil, err
}
b.resp = resp
return resp, nil
}
// DoRequest will do the client.Do
func (b *BeegoHTTPRequest) DoRequest() (*http.Response, error) {
var paramBody string
if len(b.params) > 0 {
var buf bytes.Buffer
for k, v := range b.params {
for _, vv := range v {
buf.WriteString(url.QueryEscape(k))
buf.WriteByte('=')
buf.WriteString(url.QueryEscape(vv))
buf.WriteByte('&')
}
}
paramBody = buf.String()
paramBody = paramBody[0 : len(paramBody)-1]
}
b.buildURL(paramBody)
url, err := url.Parse(b.url)
if err != nil {
return nil, err
}
b.req.URL = url
trans := b.setting.Transport
if trans == nil {
// create default transport
trans = &http.Transport{
TLSClientConfig: b.setting.TLSClientConfig,
Proxy: b.setting.Proxy,
Dial: TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout),
}
} else {
// if b.transport is *http.Transport then set the settings.
if t, ok := trans.(*http.Transport); ok {
if t.TLSClientConfig == nil {
t.TLSClientConfig = b.setting.TLSClientConfig
}
if t.Proxy == nil {
t.Proxy = b.setting.Proxy
}
if t.Dial == nil {
t.Dial = TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout)
}
}
}
var jar http.CookieJar
if b.setting.EnableCookie {
if defaultCookieJar == nil {
createDefaultCookie()
}
jar = defaultCookieJar
}
client := &http.Client{
Transport: trans,
Jar: jar,
}
if b.setting.UserAgent != "" && b.req.Header.Get("User-Agent") == "" {
b.req.Header.Set("User-Agent", b.setting.UserAgent)
}
if b.setting.ShowDebug {
dump, err := httputil.DumpRequest(b.req, b.setting.DumpBody)
if err != nil {
log.Println(err.Error())
}
b.dump = dump
}
return client.Do(b.req)
}
// String returns the body string in response.
// it calls Response inner.
func (b *BeegoHTTPRequest) String() (string, error) {
data, err := b.Bytes()
if err != nil {
return "", err
}
return string(data), nil
}
// Bytes returns the body []byte in response.
// it calls Response inner.
func (b *BeegoHTTPRequest) Bytes() ([]byte, error) {
if b.body != nil {
return b.body, nil
}
resp, err := b.getResponse()
if err != nil {
return nil, err
}
if resp.Body == nil {
return nil, nil
}
defer resp.Body.Close()
if b.setting.Gzip && resp.Header.Get("Content-Encoding") == "gzip" {
reader, err := gzip.NewReader(resp.Body)
if err != nil {
return nil, err
}
b.body, err = ioutil.ReadAll(reader)
} else {
b.body, err = ioutil.ReadAll(resp.Body)
}
return b.body, err
}
// ToFile saves the body data in response to one file.
// it calls Response inner.
func (b *BeegoHTTPRequest) ToFile(filename string) error {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
resp, err := b.getResponse()
if err != nil {
return err
}
if resp.Body == nil {
return nil
}
defer resp.Body.Close()
_, err = io.Copy(f, resp.Body)
return err
}
// ToJSON returns the map that marshals from the body bytes as json in response .
// it calls Response inner.
func (b *BeegoHTTPRequest) ToJSON(v interface{}) error {
data, err := b.Bytes()
if err != nil {
return err
}
return json.Unmarshal(data, v)
}
// ToXML returns the map that marshals from the body bytes as xml in response .
// it calls Response inner.
func (b *BeegoHTTPRequest) ToXML(v interface{}) error {
data, err := b.Bytes()
if err != nil {
return err
}
return xml.Unmarshal(data, v)
}
// Response executes request client gets response mannually.
func (b *BeegoHTTPRequest) Response() (*http.Response, error) {
return b.getResponse()
}
// TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field.
func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) {
return func(netw, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(netw, addr, cTimeout)
if err != nil {
return nil, err
}
err = conn.SetDeadline(time.Now().Add(rwTimeout))
return conn, err
}
}

View File

@ -0,0 +1,218 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 httplib
import (
"io/ioutil"
"os"
"strings"
"testing"
"time"
)
func TestResponse(t *testing.T) {
req := Get("http://httpbin.org/get")
resp, err := req.Response()
if err != nil {
t.Fatal(err)
}
t.Log(resp)
}
func TestGet(t *testing.T) {
req := Get("http://httpbin.org/get")
b, err := req.Bytes()
if err != nil {
t.Fatal(err)
}
t.Log(b)
s, err := req.String()
if err != nil {
t.Fatal(err)
}
t.Log(s)
if string(b) != s {
t.Fatal("request data not match")
}
}
func TestSimplePost(t *testing.T) {
v := "smallfish"
req := Post("http://httpbin.org/post")
req.Param("username", v)
str, err := req.String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
n := strings.Index(str, v)
if n == -1 {
t.Fatal(v + " not found in post")
}
}
//func TestPostFile(t *testing.T) {
// v := "smallfish"
// req := Post("http://httpbin.org/post")
// req.Debug(true)
// req.Param("username", v)
// req.PostFile("uploadfile", "httplib_test.go")
// str, err := req.String()
// if err != nil {
// t.Fatal(err)
// }
// t.Log(str)
// n := strings.Index(str, v)
// if n == -1 {
// t.Fatal(v + " not found in post")
// }
//}
func TestSimplePut(t *testing.T) {
str, err := Put("http://httpbin.org/put").String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
}
func TestSimpleDelete(t *testing.T) {
str, err := Delete("http://httpbin.org/delete").String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
}
func TestWithCookie(t *testing.T) {
v := "smallfish"
str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
str, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
n := strings.Index(str, v)
if n == -1 {
t.Fatal(v + " not found in cookie")
}
}
func TestWithBasicAuth(t *testing.T) {
str, err := Get("http://httpbin.org/basic-auth/user/passwd").SetBasicAuth("user", "passwd").String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
n := strings.Index(str, "authenticated")
if n == -1 {
t.Fatal("authenticated not found in response")
}
}
func TestWithUserAgent(t *testing.T) {
v := "beego"
str, err := Get("http://httpbin.org/headers").SetUserAgent(v).String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
n := strings.Index(str, v)
if n == -1 {
t.Fatal(v + " not found in user-agent")
}
}
func TestWithSetting(t *testing.T) {
v := "beego"
var setting BeegoHTTPSettings
setting.EnableCookie = true
setting.UserAgent = v
setting.Transport = nil
setting.ReadWriteTimeout = 5 * time.Second
SetDefaultSetting(setting)
str, err := Get("http://httpbin.org/get").String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
n := strings.Index(str, v)
if n == -1 {
t.Fatal(v + " not found in user-agent")
}
}
func TestToJson(t *testing.T) {
req := Get("http://httpbin.org/ip")
resp, err := req.Response()
if err != nil {
t.Fatal(err)
}
t.Log(resp)
// httpbin will return http remote addr
type IP struct {
Origin string `json:"origin"`
}
var ip IP
err = req.ToJSON(&ip)
if err != nil {
t.Fatal(err)
}
t.Log(ip.Origin)
if n := strings.Count(ip.Origin, "."); n != 3 {
t.Fatal("response is not valid ip")
}
}
func TestToFile(t *testing.T) {
f := "beego_testfile"
req := Get("http://httpbin.org/ip")
err := req.ToFile(f)
if err != nil {
t.Fatal(err)
}
defer os.Remove(f)
b, err := ioutil.ReadFile(f)
if n := strings.Index(string(b), "origin"); n == -1 {
t.Fatal(err)
}
}
func TestHeader(t *testing.T) {
req := Get("http://httpbin.org/headers")
req.Header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36")
str, err := req.String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
}

25
src/vendor/github.com/astaxie/beego/logs/conn_test.go generated vendored Normal file
View File

@ -0,0 +1,25 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 logs
import (
"testing"
)
func TestConn(t *testing.T) {
log := NewLogger(1000)
log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`)
log.Informational("informational")
}

View File

@ -0,0 +1,51 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 logs
import (
"testing"
)
// Try each log level in decreasing order of priority.
func testConsoleCalls(bl *BeeLogger) {
bl.Emergency("emergency")
bl.Alert("alert")
bl.Critical("critical")
bl.Error("error")
bl.Warning("warning")
bl.Notice("notice")
bl.Informational("informational")
bl.Debug("debug")
}
// Test console logging by visually comparing the lines being output with and
// without a log level specification.
func TestConsole(t *testing.T) {
log1 := NewLogger(10000)
log1.EnableFuncCallDepth(true)
log1.SetLogger("console", "")
testConsoleCalls(log1)
log2 := NewLogger(100)
log2.SetLogger("console", `{"level":3}`)
testConsoleCalls(log2)
}
// Test console without color
func TestConsoleNoColor(t *testing.T) {
log := NewLogger(100)
log.SetLogger("console", `{"color":false}`)
testConsoleCalls(log)
}

80
src/vendor/github.com/astaxie/beego/logs/es/es.go generated vendored Normal file
View File

@ -0,0 +1,80 @@
package es
import (
"encoding/json"
"errors"
"fmt"
"net"
"net/url"
"time"
"github.com/astaxie/beego/logs"
"github.com/belogik/goes"
)
// NewES return a LoggerInterface
func NewES() logs.Logger {
cw := &esLogger{
Level: logs.LevelDebug,
}
return cw
}
type esLogger struct {
*goes.Connection
DSN string `json:"dsn"`
Level int `json:"level"`
}
// {"dsn":"http://localhost:9200/","level":1}
func (el *esLogger) Init(jsonconfig string) error {
err := json.Unmarshal([]byte(jsonconfig), el)
if err != nil {
return err
}
if el.DSN == "" {
return errors.New("empty dsn")
} else if u, err := url.Parse(el.DSN); err != nil {
return err
} else if u.Path == "" {
return errors.New("missing prefix")
} else if host, port, err := net.SplitHostPort(u.Host); err != nil {
return err
} else {
conn := goes.NewConnection(host, port)
el.Connection = conn
}
return nil
}
// WriteMsg will write the msg and level into es
func (el *esLogger) WriteMsg(when time.Time, msg string, level int) error {
if level > el.Level {
return nil
}
vals := make(map[string]interface{})
vals["@timestamp"] = when.Format(time.RFC3339)
vals["@msg"] = msg
d := goes.Document{
Index: fmt.Sprintf("%04d.%02d.%02d", when.Year(), when.Month(), when.Day()),
Type: "logs",
Fields: vals,
}
_, err := el.Index(d, nil)
return err
}
// Destroy is a empty method
func (el *esLogger) Destroy() {
}
// Flush is a empty method
func (el *esLogger) Flush() {
}
func init() {
logs.Register("es", NewES)
}

173
src/vendor/github.com/astaxie/beego/logs/file_test.go generated vendored Normal file
View File

@ -0,0 +1,173 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 logs
import (
"bufio"
"fmt"
"os"
"strconv"
"testing"
"time"
)
func TestFile1(t *testing.T) {
log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test.log"}`)
log.Debug("debug")
log.Informational("info")
log.Notice("notice")
log.Warning("warning")
log.Error("error")
log.Alert("alert")
log.Critical("critical")
log.Emergency("emergency")
f, err := os.Open("test.log")
if err != nil {
t.Fatal(err)
}
b := bufio.NewReader(f)
lineNum := 0
for {
line, _, err := b.ReadLine()
if err != nil {
break
}
if len(line) > 0 {
lineNum++
}
}
var expected = LevelDebug + 1
if lineNum != expected {
t.Fatal(lineNum, "not "+strconv.Itoa(expected)+" lines")
}
os.Remove("test.log")
}
func TestFile2(t *testing.T) {
log := NewLogger(10000)
log.SetLogger("file", fmt.Sprintf(`{"filename":"test2.log","level":%d}`, LevelError))
log.Debug("debug")
log.Info("info")
log.Notice("notice")
log.Warning("warning")
log.Error("error")
log.Alert("alert")
log.Critical("critical")
log.Emergency("emergency")
f, err := os.Open("test2.log")
if err != nil {
t.Fatal(err)
}
b := bufio.NewReader(f)
lineNum := 0
for {
line, _, err := b.ReadLine()
if err != nil {
break
}
if len(line) > 0 {
lineNum++
}
}
var expected = LevelError + 1
if lineNum != expected {
t.Fatal(lineNum, "not "+strconv.Itoa(expected)+" lines")
}
os.Remove("test2.log")
}
func TestFileRotate(t *testing.T) {
log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`)
log.Debug("debug")
log.Info("info")
log.Notice("notice")
log.Warning("warning")
log.Error("error")
log.Alert("alert")
log.Critical("critical")
log.Emergency("emergency")
rotateName := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) + ".log"
b, err := exists(rotateName)
if !b || err != nil {
os.Remove("test3.log")
t.Fatal("rotate not generated")
}
os.Remove(rotateName)
os.Remove("test3.log")
}
func exists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
func BenchmarkFile(b *testing.B) {
log := NewLogger(100000)
log.SetLogger("file", `{"filename":"test4.log"}`)
for i := 0; i < b.N; i++ {
log.Debug("debug")
}
os.Remove("test4.log")
}
func BenchmarkFileAsynchronous(b *testing.B) {
log := NewLogger(100000)
log.SetLogger("file", `{"filename":"test4.log"}`)
log.Async()
for i := 0; i < b.N; i++ {
log.Debug("debug")
}
os.Remove("test4.log")
}
func BenchmarkFileCallDepth(b *testing.B) {
log := NewLogger(100000)
log.SetLogger("file", `{"filename":"test4.log"}`)
log.EnableFuncCallDepth(true)
log.SetLogFuncCallDepth(2)
for i := 0; i < b.N; i++ {
log.Debug("debug")
}
os.Remove("test4.log")
}
func BenchmarkFileAsynchronousCallDepth(b *testing.B) {
log := NewLogger(100000)
log.SetLogger("file", `{"filename":"test4.log"}`)
log.EnableFuncCallDepth(true)
log.SetLogFuncCallDepth(2)
log.Async()
for i := 0; i < b.N; i++ {
log.Debug("debug")
}
os.Remove("test4.log")
}
func BenchmarkFileOnGoroutine(b *testing.B) {
log := NewLogger(100000)
log.SetLogger("file", `{"filename":"test4.log"}`)
for i := 0; i < b.N; i++ {
go log.Debug("debug")
}
os.Remove("test4.log")
}

View File

@ -0,0 +1,78 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 logs
import (
"bufio"
"os"
"strconv"
"strings"
"testing"
)
func TestFiles_1(t *testing.T) {
log := NewLogger(10000)
log.SetLogger("multifile", `{"filename":"test.log","separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]}`)
log.Debug("debug")
log.Informational("info")
log.Notice("notice")
log.Warning("warning")
log.Error("error")
log.Alert("alert")
log.Critical("critical")
log.Emergency("emergency")
fns := []string{""}
fns = append(fns, levelNames[0:]...)
name := "test"
suffix := ".log"
for _, fn := range fns {
file := name + suffix
if fn != "" {
file = name + "." + fn + suffix
}
f, err := os.Open(file)
if err != nil {
t.Fatal(err)
}
b := bufio.NewReader(f)
lineNum := 0
lastLine := ""
for {
line, _, err := b.ReadLine()
if err != nil {
break
}
if len(line) > 0 {
lastLine = string(line)
lineNum++
}
}
var expected = 1
if fn == "" {
expected = LevelDebug + 1
}
if lineNum != expected {
t.Fatal(file, "has", lineNum, "lines not "+strconv.Itoa(expected)+" lines")
}
if lineNum == 1 {
if !strings.Contains(lastLine, fn) {
t.Fatal(file + " " + lastLine + " not contains the log msg " + fn)
}
}
os.Remove(file)
}
}

27
src/vendor/github.com/astaxie/beego/logs/smtp_test.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 logs
import (
"testing"
"time"
)
func TestSmtp(t *testing.T) {
log := NewLogger(10000)
log.SetLogger("smtp", `{"username":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`)
log.Critical("sendmail critical")
time.Sleep(time.Second * 30)
}

53
src/vendor/github.com/astaxie/beego/migration/ddl.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 migration
// Table store the tablename and Column
type Table struct {
TableName string
Columns []*Column
}
// Create return the create sql
func (t *Table) Create() string {
return ""
}
// Drop return the drop sql
func (t *Table) Drop() string {
return ""
}
// Column define the columns name type and Default
type Column struct {
Name string
Type string
Default interface{}
}
// Create return create sql with the provided tbname and columns
func Create(tbname string, columns ...Column) string {
return ""
}
// Drop return the drop sql with the provided tbname and columns
func Drop(tbname string, columns ...Column) string {
return ""
}
// TableDDL is still in think
func TableDDL(tbname string, columns ...Column) string {
return ""
}

View File

@ -0,0 +1,278 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 migration is used for migration
//
// The table structure is as follow:
//
// CREATE TABLE `migrations` (
// `id_migration` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'surrogate key',
// `name` varchar(255) DEFAULT NULL COMMENT 'migration name, unique',
// `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'date migrated or rolled back',
// `statements` longtext COMMENT 'SQL statements for this migration',
// `rollback_statements` longtext,
// `status` enum('update','rollback') DEFAULT NULL COMMENT 'update indicates it is a normal migration while rollback means this migration is rolled back',
// PRIMARY KEY (`id_migration`)
// ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
package migration
import (
"errors"
"sort"
"strings"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
// const the data format for the bee generate migration datatype
const (
DateFormat = "20060102_150405"
DBDateFormat = "2006-01-02 15:04:05"
)
// Migrationer is an interface for all Migration struct
type Migrationer interface {
Up()
Down()
Reset()
Exec(name, status string) error
GetCreated() int64
}
var (
migrationMap map[string]Migrationer
)
func init() {
migrationMap = make(map[string]Migrationer)
}
// Migration the basic type which will implement the basic type
type Migration struct {
sqls []string
Created string
}
// Up implement in the Inheritance struct for upgrade
func (m *Migration) Up() {
}
// Down implement in the Inheritance struct for down
func (m *Migration) Down() {
}
// SQL add sql want to execute
func (m *Migration) SQL(sql string) {
m.sqls = append(m.sqls, sql)
}
// Reset the sqls
func (m *Migration) Reset() {
m.sqls = make([]string, 0)
}
// Exec execute the sql already add in the sql
func (m *Migration) Exec(name, status string) error {
o := orm.NewOrm()
for _, s := range m.sqls {
beego.Info("exec sql:", s)
r := o.Raw(s)
_, err := r.Exec()
if err != nil {
return err
}
}
return m.addOrUpdateRecord(name, status)
}
func (m *Migration) addOrUpdateRecord(name, status string) error {
o := orm.NewOrm()
if status == "down" {
status = "rollback"
p, err := o.Raw("update migrations set status = ?, rollback_statements = ?, created_at = ? where name = ?").Prepare()
if err != nil {
return nil
}
_, err = p.Exec(status, strings.Join(m.sqls, "; "), time.Now().Format(DBDateFormat), name)
return err
}
status = "update"
p, err := o.Raw("insert into migrations(name, created_at, statements, status) values(?,?,?,?)").Prepare()
if err != nil {
return err
}
_, err = p.Exec(name, time.Now().Format(DBDateFormat), strings.Join(m.sqls, "; "), status)
return err
}
// GetCreated get the unixtime from the Created
func (m *Migration) GetCreated() int64 {
t, err := time.Parse(DateFormat, m.Created)
if err != nil {
return 0
}
return t.Unix()
}
// Register register the Migration in the map
func Register(name string, m Migrationer) error {
if _, ok := migrationMap[name]; ok {
return errors.New("already exist name:" + name)
}
migrationMap[name] = m
return nil
}
// Upgrade upgrate the migration from lasttime
func Upgrade(lasttime int64) error {
sm := sortMap(migrationMap)
i := 0
for _, v := range sm {
if v.created > lasttime {
beego.Info("start upgrade", v.name)
v.m.Reset()
v.m.Up()
err := v.m.Exec(v.name, "up")
if err != nil {
beego.Error("execute error:", err)
time.Sleep(2 * time.Second)
return err
}
beego.Info("end upgrade:", v.name)
i++
}
}
beego.Info("total success upgrade:", i, " migration")
time.Sleep(2 * time.Second)
return nil
}
// Rollback rollback the migration by the name
func Rollback(name string) error {
if v, ok := migrationMap[name]; ok {
beego.Info("start rollback")
v.Reset()
v.Down()
err := v.Exec(name, "down")
if err != nil {
beego.Error("execute error:", err)
time.Sleep(2 * time.Second)
return err
}
beego.Info("end rollback")
time.Sleep(2 * time.Second)
return nil
}
beego.Error("not exist the migrationMap name:" + name)
time.Sleep(2 * time.Second)
return errors.New("not exist the migrationMap name:" + name)
}
// Reset reset all migration
// run all migration's down function
func Reset() error {
sm := sortMap(migrationMap)
i := 0
for j := len(sm) - 1; j >= 0; j-- {
v := sm[j]
if isRollBack(v.name) {
beego.Info("skip the", v.name)
time.Sleep(1 * time.Second)
continue
}
beego.Info("start reset:", v.name)
v.m.Reset()
v.m.Down()
err := v.m.Exec(v.name, "down")
if err != nil {
beego.Error("execute error:", err)
time.Sleep(2 * time.Second)
return err
}
i++
beego.Info("end reset:", v.name)
}
beego.Info("total success reset:", i, " migration")
time.Sleep(2 * time.Second)
return nil
}
// Refresh first Reset, then Upgrade
func Refresh() error {
err := Reset()
if err != nil {
beego.Error("execute error:", err)
time.Sleep(2 * time.Second)
return err
}
err = Upgrade(0)
return err
}
type dataSlice []data
type data struct {
created int64
name string
m Migrationer
}
// Len is part of sort.Interface.
func (d dataSlice) Len() int {
return len(d)
}
// Swap is part of sort.Interface.
func (d dataSlice) Swap(i, j int) {
d[i], d[j] = d[j], d[i]
}
// Less is part of sort.Interface. We use count as the value to sort by
func (d dataSlice) Less(i, j int) bool {
return d[i].created < d[j].created
}
func sortMap(m map[string]Migrationer) dataSlice {
s := make(dataSlice, 0, len(m))
for k, v := range m {
d := data{}
d.created = v.GetCreated()
d.name = k
d.m = v
s = append(s, d)
}
sort.Sort(s)
return s
}
func isRollBack(name string) bool {
o := orm.NewOrm()
var maps []orm.Params
num, err := o.Raw("select * from migrations where `name` = ? order by id_migration desc", name).Values(&maps)
if err != nil {
beego.Info("get name has error", err)
return false
}
if num <= 0 {
return false
}
if maps[0]["status"] == "rollback" {
return true
}
return false
}

171
src/vendor/github.com/astaxie/beego/namespace_test.go generated vendored Normal file
View File

@ -0,0 +1,171 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"net/http"
"net/http/httptest"
"strconv"
"testing"
"github.com/astaxie/beego/context"
)
func TestNamespaceGet(t *testing.T) {
r, _ := http.NewRequest("GET", "/v1/user", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v1")
ns.Get("/user", func(ctx *context.Context) {
ctx.Output.Body([]byte("v1_user"))
})
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Body.String() != "v1_user" {
t.Errorf("TestNamespaceGet can't run, get the response is " + w.Body.String())
}
}
func TestNamespacePost(t *testing.T) {
r, _ := http.NewRequest("POST", "/v1/user/123", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v1")
ns.Post("/user/:id", func(ctx *context.Context) {
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
})
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Body.String() != "123" {
t.Errorf("TestNamespacePost can't run, get the response is " + w.Body.String())
}
}
func TestNamespaceNest(t *testing.T) {
r, _ := http.NewRequest("GET", "/v1/admin/order", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v1")
ns.Namespace(
NewNamespace("/admin").
Get("/order", func(ctx *context.Context) {
ctx.Output.Body([]byte("order"))
}),
)
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Body.String() != "order" {
t.Errorf("TestNamespaceNest can't run, get the response is " + w.Body.String())
}
}
func TestNamespaceNestParam(t *testing.T) {
r, _ := http.NewRequest("GET", "/v1/admin/order/123", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v1")
ns.Namespace(
NewNamespace("/admin").
Get("/order/:id", func(ctx *context.Context) {
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
}),
)
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Body.String() != "123" {
t.Errorf("TestNamespaceNestParam can't run, get the response is " + w.Body.String())
}
}
func TestNamespaceRouter(t *testing.T) {
r, _ := http.NewRequest("GET", "/v1/api/list", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v1")
ns.Router("/api/list", &TestController{}, "*:List")
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Body.String() != "i am list" {
t.Errorf("TestNamespaceRouter can't run, get the response is " + w.Body.String())
}
}
func TestNamespaceAutoFunc(t *testing.T) {
r, _ := http.NewRequest("GET", "/v1/test/list", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v1")
ns.AutoRouter(&TestController{})
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Body.String() != "i am list" {
t.Errorf("user define func can't run")
}
}
func TestNamespaceFilter(t *testing.T) {
r, _ := http.NewRequest("GET", "/v1/user/123", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v1")
ns.Filter("before", func(ctx *context.Context) {
ctx.Output.Body([]byte("this is Filter"))
}).
Get("/user/:id", func(ctx *context.Context) {
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
})
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Body.String() != "this is Filter" {
t.Errorf("TestNamespaceFilter can't run, get the response is " + w.Body.String())
}
}
func TestNamespaceCond(t *testing.T) {
r, _ := http.NewRequest("GET", "/v2/test/list", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v2")
ns.Cond(func(ctx *context.Context) bool {
if ctx.Input.Domain() == "beego.me" {
return true
}
return false
}).
AutoRouter(&TestController{})
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Code != 405 {
t.Errorf("TestNamespaceCond can't run get the result " + strconv.Itoa(w.Code))
}
}
func TestNamespaceInside(t *testing.T) {
r, _ := http.NewRequest("GET", "/v3/shop/order/123", nil)
w := httptest.NewRecorder()
ns := NewNamespace("/v3",
NSAutoRouter(&TestController{}),
NSNamespace("/shop",
NSGet("/order/:id", func(ctx *context.Context) {
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
}),
),
)
AddNamespace(ns)
BeeApp.Handlers.ServeHTTP(w, r)
if w.Body.String() != "123" {
t.Errorf("TestNamespaceInside can't run, get the response is " + w.Body.String())
}
}

457
src/vendor/github.com/astaxie/beego/orm/models_test.go generated vendored Normal file
View File

@ -0,0 +1,457 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 orm
import (
"database/sql"
"encoding/json"
"fmt"
"os"
"strings"
"time"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
// As tidb can't use go get, so disable the tidb testing now
// _ "github.com/pingcap/tidb"
)
// A slice string field.
type SliceStringField []string
func (e SliceStringField) Value() []string {
return []string(e)
}
func (e *SliceStringField) Set(d []string) {
*e = SliceStringField(d)
}
func (e *SliceStringField) Add(v string) {
*e = append(*e, v)
}
func (e *SliceStringField) String() string {
return strings.Join(e.Value(), ",")
}
func (e *SliceStringField) FieldType() int {
return TypeCharField
}
func (e *SliceStringField) SetRaw(value interface{}) error {
switch d := value.(type) {
case []string:
e.Set(d)
case string:
if len(d) > 0 {
parts := strings.Split(d, ",")
v := make([]string, 0, len(parts))
for _, p := range parts {
v = append(v, strings.TrimSpace(p))
}
e.Set(v)
}
default:
return fmt.Errorf("<SliceStringField.SetRaw> unknown value `%v`", value)
}
return nil
}
func (e *SliceStringField) RawValue() interface{} {
return e.String()
}
var _ Fielder = new(SliceStringField)
// A json field.
type JSONField struct {
Name string
Data string
}
func (e *JSONField) String() string {
data, _ := json.Marshal(e)
return string(data)
}
func (e *JSONField) FieldType() int {
return TypeTextField
}
func (e *JSONField) SetRaw(value interface{}) error {
switch d := value.(type) {
case string:
return json.Unmarshal([]byte(d), e)
default:
return fmt.Errorf("<JsonField.SetRaw> unknown value `%v`", value)
}
}
func (e *JSONField) RawValue() interface{} {
return e.String()
}
var _ Fielder = new(JSONField)
type Data struct {
ID int `orm:"column(id)"`
Boolean bool
Char string `orm:"size(50)"`
Text string `orm:"type(text)"`
Date time.Time `orm:"type(date)"`
DateTime time.Time `orm:"column(datetime)"`
Byte byte
Rune rune
Int int
Int8 int8
Int16 int16
Int32 int32
Int64 int64
Uint uint
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
Float32 float32
Float64 float64
Decimal float64 `orm:"digits(8);decimals(4)"`
}
type DataNull struct {
ID int `orm:"column(id)"`
Boolean bool `orm:"null"`
Char string `orm:"null;size(50)"`
Text string `orm:"null;type(text)"`
Date time.Time `orm:"null;type(date)"`
DateTime time.Time `orm:"null;column(datetime)"`
Byte byte `orm:"null"`
Rune rune `orm:"null"`
Int int `orm:"null"`
Int8 int8 `orm:"null"`
Int16 int16 `orm:"null"`
Int32 int32 `orm:"null"`
Int64 int64 `orm:"null"`
Uint uint `orm:"null"`
Uint8 uint8 `orm:"null"`
Uint16 uint16 `orm:"null"`
Uint32 uint32 `orm:"null"`
Uint64 uint64 `orm:"null"`
Float32 float32 `orm:"null"`
Float64 float64 `orm:"null"`
Decimal float64 `orm:"digits(8);decimals(4);null"`
NullString sql.NullString `orm:"null"`
NullBool sql.NullBool `orm:"null"`
NullFloat64 sql.NullFloat64 `orm:"null"`
NullInt64 sql.NullInt64 `orm:"null"`
BooleanPtr *bool `orm:"null"`
CharPtr *string `orm:"null;size(50)"`
TextPtr *string `orm:"null;type(text)"`
BytePtr *byte `orm:"null"`
RunePtr *rune `orm:"null"`
IntPtr *int `orm:"null"`
Int8Ptr *int8 `orm:"null"`
Int16Ptr *int16 `orm:"null"`
Int32Ptr *int32 `orm:"null"`
Int64Ptr *int64 `orm:"null"`
UintPtr *uint `orm:"null"`
Uint8Ptr *uint8 `orm:"null"`
Uint16Ptr *uint16 `orm:"null"`
Uint32Ptr *uint32 `orm:"null"`
Uint64Ptr *uint64 `orm:"null"`
Float32Ptr *float32 `orm:"null"`
Float64Ptr *float64 `orm:"null"`
DecimalPtr *float64 `orm:"digits(8);decimals(4);null"`
}
type String string
type Boolean bool
type Byte byte
type Rune rune
type Int int
type Int8 int8
type Int16 int16
type Int32 int32
type Int64 int64
type Uint uint
type Uint8 uint8
type Uint16 uint16
type Uint32 uint32
type Uint64 uint64
type Float32 float64
type Float64 float64
type DataCustom struct {
ID int `orm:"column(id)"`
Boolean Boolean
Char string `orm:"size(50)"`
Text string `orm:"type(text)"`
Byte Byte
Rune Rune
Int Int
Int8 Int8
Int16 Int16
Int32 Int32
Int64 Int64
Uint Uint
Uint8 Uint8
Uint16 Uint16
Uint32 Uint32
Uint64 Uint64
Float32 Float32
Float64 Float64
Decimal Float64 `orm:"digits(8);decimals(4)"`
}
// only for mysql
type UserBig struct {
ID uint64 `orm:"column(id)"`
Name string
}
type User struct {
ID int `orm:"column(id)"`
UserName string `orm:"size(30);unique"`
Email string `orm:"size(100)"`
Password string `orm:"size(100)"`
Status int16 `orm:"column(Status)"`
IsStaff bool
IsActive bool `orm:"default(true)"`
Created time.Time `orm:"auto_now_add;type(date)"`
Updated time.Time `orm:"auto_now"`
Profile *Profile `orm:"null;rel(one);on_delete(set_null)"`
Posts []*Post `orm:"reverse(many)" json:"-"`
ShouldSkip string `orm:"-"`
Nums int
Langs SliceStringField `orm:"size(100)"`
Extra JSONField `orm:"type(text)"`
unexport bool `orm:"-"`
unexportBool bool
}
func (u *User) TableIndex() [][]string {
return [][]string{
{"Id", "UserName"},
{"Id", "Created"},
}
}
func (u *User) TableUnique() [][]string {
return [][]string{
{"UserName", "Email"},
}
}
func NewUser() *User {
obj := new(User)
return obj
}
type Profile struct {
ID int `orm:"column(id)"`
Age int16
Money float64
User *User `orm:"reverse(one)" json:"-"`
BestPost *Post `orm:"rel(one);null"`
}
func (u *Profile) TableName() string {
return "user_profile"
}
func NewProfile() *Profile {
obj := new(Profile)
return obj
}
type Post struct {
ID int `orm:"column(id)"`
User *User `orm:"rel(fk)"`
Title string `orm:"size(60)"`
Content string `orm:"type(text)"`
Created time.Time `orm:"auto_now_add"`
Updated time.Time `orm:"auto_now"`
Tags []*Tag `orm:"rel(m2m);rel_through(github.com/astaxie/beego/orm.PostTags)"`
}
func (u *Post) TableIndex() [][]string {
return [][]string{
{"Id", "Created"},
}
}
func NewPost() *Post {
obj := new(Post)
return obj
}
type Tag struct {
ID int `orm:"column(id)"`
Name string `orm:"size(30)"`
BestPost *Post `orm:"rel(one);null"`
Posts []*Post `orm:"reverse(many)" json:"-"`
}
func NewTag() *Tag {
obj := new(Tag)
return obj
}
type PostTags struct {
ID int `orm:"column(id)"`
Post *Post `orm:"rel(fk)"`
Tag *Tag `orm:"rel(fk)"`
}
func (m *PostTags) TableName() string {
return "prefix_post_tags"
}
type Comment struct {
ID int `orm:"column(id)"`
Post *Post `orm:"rel(fk);column(post)"`
Content string `orm:"type(text)"`
Parent *Comment `orm:"null;rel(fk)"`
Created time.Time `orm:"auto_now_add"`
}
func NewComment() *Comment {
obj := new(Comment)
return obj
}
type Group struct {
ID int `orm:"column(gid);size(32)"`
Name string
Permissions []*Permission `orm:"reverse(many)" json:"-"`
}
type Permission struct {
ID int `orm:"column(id)"`
Name string
Groups []*Group `orm:"rel(m2m);rel_through(github.com/astaxie/beego/orm.GroupPermissions)"`
}
type GroupPermissions struct {
ID int `orm:"column(id)"`
Group *Group `orm:"rel(fk)"`
Permission *Permission `orm:"rel(fk)"`
}
type ModelID struct {
ID int64
}
type ModelBase struct {
ModelID
Created time.Time `orm:"auto_now_add;type(datetime)"`
Updated time.Time `orm:"auto_now;type(datetime)"`
}
type InLine struct {
// Common Fields
ModelBase
// Other Fields
Name string `orm:"unique"`
Email string
}
func NewInLine() *InLine {
return new(InLine)
}
var DBARGS = struct {
Driver string
Source string
Debug string
}{
os.Getenv("ORM_DRIVER"),
os.Getenv("ORM_SOURCE"),
os.Getenv("ORM_DEBUG"),
}
var (
IsMysql = DBARGS.Driver == "mysql"
IsSqlite = DBARGS.Driver == "sqlite3"
IsPostgres = DBARGS.Driver == "postgres"
IsTidb = DBARGS.Driver == "tidb"
)
var (
dORM Ormer
dDbBaser dbBaser
)
func init() {
Debug, _ = StrTo(DBARGS.Debug).Bool()
if DBARGS.Driver == "" || DBARGS.Source == "" {
fmt.Println(`need driver and source!
Default DB Drivers.
driver: url
mysql: https://github.com/go-sql-driver/mysql
sqlite3: https://github.com/mattn/go-sqlite3
postgres: https://github.com/lib/pq
tidb: https://github.com/pingcap/tidb
usage:
go get -u github.com/astaxie/beego/orm
go get -u github.com/go-sql-driver/mysql
go get -u github.com/mattn/go-sqlite3
go get -u github.com/lib/pq
go get -u github.com/pingcap/tidb
#### MySQL
mysql -u root -e 'create database orm_test;'
export ORM_DRIVER=mysql
export ORM_SOURCE="root:@/orm_test?charset=utf8"
go test -v github.com/astaxie/beego/orm
#### Sqlite3
export ORM_DRIVER=sqlite3
export ORM_SOURCE='file:memory_test?mode=memory'
go test -v github.com/astaxie/beego/orm
#### PostgreSQL
psql -c 'create database orm_test;' -U postgres
export ORM_DRIVER=postgres
export ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
go test -v github.com/astaxie/beego/orm
#### TiDB
export ORM_DRIVER=tidb
export ORM_SOURCE='memory://test/test'
go test -v github.com/astaxie/beego/orm
`)
os.Exit(2)
}
RegisterDataBase("default", DBARGS.Driver, DBARGS.Source, 20)
alias := getDbAlias("default")
if alias.Driver == DRMySQL {
alias.Engine = "INNODB"
}
}

1954
src/vendor/github.com/astaxie/beego/orm/orm_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,180 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 apiauth provides handlers to enable apiauth support.
//
// Simple Usage:
// import(
// "github.com/astaxie/beego"
// "github.com/astaxie/beego/plugins/apiauth"
// )
//
// func main(){
// // apiauth every request
// beego.InsertFilter("*", beego.BeforeRouter,apiauth.APIBaiscAuth("appid","appkey"))
// beego.Run()
// }
//
// Advanced Usage:
//
// func getAppSecret(appid string) string {
// // get appsecret by appid
// // maybe store in configure, maybe in database
// }
//
// beego.InsertFilter("*", beego.BeforeRouter,apiauth.APISecretAuth(getAppSecret, 360))
//
// Infomation:
//
// In the request user should include these params in the query
//
// 1. appid
//
// appid is assigned to the application
//
// 2. signature
//
// get the signature use apiauth.Signature()
//
// when you send to server remember use url.QueryEscape()
//
// 3. timestamp:
//
// send the request time, the format is yyyy-mm-dd HH:ii:ss
//
package apiauth
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"net/url"
"sort"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
)
// AppIDToAppSecret is used to get appsecret throw appid
type AppIDToAppSecret func(string) string
// APIBaiscAuth use the basic appid/appkey as the AppIdToAppSecret
func APIBaiscAuth(appid, appkey string) beego.FilterFunc {
ft := func(aid string) string {
if aid == appid {
return appkey
}
return ""
}
return APISecretAuth(ft, 300)
}
// APISecretAuth use AppIdToAppSecret verify and
func APISecretAuth(f AppIDToAppSecret, timeout int) beego.FilterFunc {
return func(ctx *context.Context) {
if ctx.Input.Query("appid") == "" {
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("miss query param: appid")
return
}
appsecret := f(ctx.Input.Query("appid"))
if appsecret == "" {
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("not exist this appid")
return
}
if ctx.Input.Query("signature") == "" {
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("miss query param: signature")
return
}
if ctx.Input.Query("timestamp") == "" {
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("miss query param: timestamp")
return
}
u, err := time.Parse("2006-01-02 15:04:05", ctx.Input.Query("timestamp"))
if err != nil {
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("timestamp format is error, should 2006-01-02 15:04:05")
return
}
t := time.Now()
if t.Sub(u).Seconds() > float64(timeout) {
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("timeout! the request time is long ago, please try again")
return
}
if ctx.Input.Query("signature") !=
Signature(appsecret, ctx.Input.Method(), ctx.Request.Form, ctx.Input.URI()) {
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("auth failed")
}
}
}
// Signature used to generate signature with the appsecret/method/params/RequestURI
func Signature(appsecret, method string, params url.Values, RequestURI string) (result string) {
var query string
pa := make(map[string]string)
for k, v := range params {
pa[k] = v[0]
}
vs := mapSorter(pa)
vs.Sort()
for i := 0; i < vs.Len(); i++ {
if vs.Keys[i] == "signature" {
continue
}
if vs.Keys[i] != "" && vs.Vals[i] != "" {
query = fmt.Sprintf("%v%v%v", query, vs.Keys[i], vs.Vals[i])
}
}
stringToSign := fmt.Sprintf("%v\n%v\n%v\n", method, query, RequestURI)
sha256 := sha256.New
hash := hmac.New(sha256, []byte(appsecret))
hash.Write([]byte(stringToSign))
return base64.StdEncoding.EncodeToString(hash.Sum(nil))
}
type valSorter struct {
Keys []string
Vals []string
}
func mapSorter(m map[string]string) *valSorter {
vs := &valSorter{
Keys: make([]string, 0, len(m)),
Vals: make([]string, 0, len(m)),
}
for k, v := range m {
vs.Keys = append(vs.Keys, k)
vs.Vals = append(vs.Vals, v)
}
return vs
}
func (vs *valSorter) Sort() {
sort.Sort(vs)
}
func (vs *valSorter) Len() int { return len(vs.Keys) }
func (vs *valSorter) Less(i, j int) bool { return vs.Keys[i] < vs.Keys[j] }
func (vs *valSorter) Swap(i, j int) {
vs.Vals[i], vs.Vals[j] = vs.Vals[j], vs.Vals[i]
vs.Keys[i], vs.Keys[j] = vs.Keys[j], vs.Keys[i]
}

View File

@ -0,0 +1,107 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 auth provides handlers to enable basic auth support.
// Simple Usage:
// import(
// "github.com/astaxie/beego"
// "github.com/astaxie/beego/plugins/auth"
// )
//
// func main(){
// // authenticate every request
// beego.InsertFilter("*", beego.BeforeRouter,auth.Basic("username","secretpassword"))
// beego.Run()
// }
//
//
// Advanced Usage:
//
// func SecretAuth(username, password string) bool {
// return username == "astaxie" && password == "helloBeego"
// }
// authPlugin := auth.NewBasicAuthenticator(SecretAuth, "Authorization Required")
// beego.InsertFilter("*", beego.BeforeRouter,authPlugin)
package auth
import (
"encoding/base64"
"net/http"
"strings"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
)
var defaultRealm = "Authorization Required"
// Basic is the http basic auth
func Basic(username string, password string) beego.FilterFunc {
secrets := func(user, pass string) bool {
return user == username && pass == password
}
return NewBasicAuthenticator(secrets, defaultRealm)
}
// NewBasicAuthenticator return the BasicAuth
func NewBasicAuthenticator(secrets SecretProvider, Realm string) beego.FilterFunc {
return func(ctx *context.Context) {
a := &BasicAuth{Secrets: secrets, Realm: Realm}
if username := a.CheckAuth(ctx.Request); username == "" {
a.RequireAuth(ctx.ResponseWriter, ctx.Request)
}
}
}
// SecretProvider is the SecretProvider function
type SecretProvider func(user, pass string) bool
// BasicAuth store the SecretProvider and Realm
type BasicAuth struct {
Secrets SecretProvider
Realm string
}
// CheckAuth Checks the username/password combination from the request. Returns
// either an empty string (authentication failed) or the name of the
// authenticated user.
// Supports MD5 and SHA1 password entries
func (a *BasicAuth) CheckAuth(r *http.Request) string {
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
if len(s) != 2 || s[0] != "Basic" {
return ""
}
b, err := base64.StdEncoding.DecodeString(s[1])
if err != nil {
return ""
}
pair := strings.SplitN(string(b), ":", 2)
if len(pair) != 2 {
return ""
}
if a.Secrets(pair[0], pair[1]) {
return pair[0]
}
return ""
}
// RequireAuth http.Handler for BasicAuth which initiates the authentication process
// (or requires reauthentication).
func (a *BasicAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
w.Header().Set("WWW-Authenticate", `Basic realm="`+a.Realm+`"`)
w.WriteHeader(401)
w.Write([]byte("401 Unauthorized\n"))
}

View File

@ -0,0 +1,228 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 cors provides handlers to enable CORS support.
// Usage
// import (
// "github.com/astaxie/beego"
// "github.com/astaxie/beego/plugins/cors"
// )
//
// func main() {
// // CORS for https://foo.* origins, allowing:
// // - PUT and PATCH methods
// // - Origin header
// // - Credentials share
// beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
// AllowOrigins: []string{"https://*.foo.com"},
// AllowMethods: []string{"PUT", "PATCH"},
// AllowHeaders: []string{"Origin"},
// ExposeHeaders: []string{"Content-Length"},
// AllowCredentials: true,
// }))
// beego.Run()
// }
package cors
import (
"net/http"
"regexp"
"strconv"
"strings"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
)
const (
headerAllowOrigin = "Access-Control-Allow-Origin"
headerAllowCredentials = "Access-Control-Allow-Credentials"
headerAllowHeaders = "Access-Control-Allow-Headers"
headerAllowMethods = "Access-Control-Allow-Methods"
headerExposeHeaders = "Access-Control-Expose-Headers"
headerMaxAge = "Access-Control-Max-Age"
headerOrigin = "Origin"
headerRequestMethod = "Access-Control-Request-Method"
headerRequestHeaders = "Access-Control-Request-Headers"
)
var (
defaultAllowHeaders = []string{"Origin", "Accept", "Content-Type", "Authorization"}
// Regex patterns are generated from AllowOrigins. These are used and generated internally.
allowOriginPatterns = []string{}
)
// Options represents Access Control options.
type Options struct {
// If set, all origins are allowed.
AllowAllOrigins bool
// A list of allowed origins. Wild cards and FQDNs are supported.
AllowOrigins []string
// If set, allows to share auth credentials such as cookies.
AllowCredentials bool
// A list of allowed HTTP methods.
AllowMethods []string
// A list of allowed HTTP headers.
AllowHeaders []string
// A list of exposed HTTP headers.
ExposeHeaders []string
// Max age of the CORS headers.
MaxAge time.Duration
}
// Header converts options into CORS headers.
func (o *Options) Header(origin string) (headers map[string]string) {
headers = make(map[string]string)
// if origin is not allowed, don't extend the headers
// with CORS headers.
if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) {
return
}
// add allow origin
if o.AllowAllOrigins {
headers[headerAllowOrigin] = "*"
} else {
headers[headerAllowOrigin] = origin
}
// add allow credentials
headers[headerAllowCredentials] = strconv.FormatBool(o.AllowCredentials)
// add allow methods
if len(o.AllowMethods) > 0 {
headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",")
}
// add allow headers
if len(o.AllowHeaders) > 0 {
headers[headerAllowHeaders] = strings.Join(o.AllowHeaders, ",")
}
// add exposed header
if len(o.ExposeHeaders) > 0 {
headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",")
}
// add a max age header
if o.MaxAge > time.Duration(0) {
headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10)
}
return
}
// PreflightHeader converts options into CORS headers for a preflight response.
func (o *Options) PreflightHeader(origin, rMethod, rHeaders string) (headers map[string]string) {
headers = make(map[string]string)
if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) {
return
}
// verify if requested method is allowed
for _, method := range o.AllowMethods {
if method == rMethod {
headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",")
break
}
}
// verify if requested headers are allowed
var allowed []string
for _, rHeader := range strings.Split(rHeaders, ",") {
rHeader = strings.TrimSpace(rHeader)
lookupLoop:
for _, allowedHeader := range o.AllowHeaders {
if strings.ToLower(rHeader) == strings.ToLower(allowedHeader) {
allowed = append(allowed, rHeader)
break lookupLoop
}
}
}
headers[headerAllowCredentials] = strconv.FormatBool(o.AllowCredentials)
// add allow origin
if o.AllowAllOrigins {
headers[headerAllowOrigin] = "*"
} else {
headers[headerAllowOrigin] = origin
}
// add allowed headers
if len(allowed) > 0 {
headers[headerAllowHeaders] = strings.Join(allowed, ",")
}
// add exposed headers
if len(o.ExposeHeaders) > 0 {
headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",")
}
// add a max age header
if o.MaxAge > time.Duration(0) {
headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10)
}
return
}
// IsOriginAllowed looks up if the origin matches one of the patterns
// generated from Options.AllowOrigins patterns.
func (o *Options) IsOriginAllowed(origin string) (allowed bool) {
for _, pattern := range allowOriginPatterns {
allowed, _ = regexp.MatchString(pattern, origin)
if allowed {
return
}
}
return
}
// Allow enables CORS for requests those match the provided options.
func Allow(opts *Options) beego.FilterFunc {
// Allow default headers if nothing is specified.
if len(opts.AllowHeaders) == 0 {
opts.AllowHeaders = defaultAllowHeaders
}
for _, origin := range opts.AllowOrigins {
pattern := regexp.QuoteMeta(origin)
pattern = strings.Replace(pattern, "\\*", ".*", -1)
pattern = strings.Replace(pattern, "\\?", ".", -1)
allowOriginPatterns = append(allowOriginPatterns, "^"+pattern+"$")
}
return func(ctx *context.Context) {
var (
origin = ctx.Input.Header(headerOrigin)
requestedMethod = ctx.Input.Header(headerRequestMethod)
requestedHeaders = ctx.Input.Header(headerRequestHeaders)
// additional headers to be added
// to the response.
headers map[string]string
)
if ctx.Input.Method() == "OPTIONS" &&
(requestedMethod != "" || requestedHeaders != "") {
headers = opts.PreflightHeader(origin, requestedMethod, requestedHeaders)
for key, value := range headers {
ctx.Output.Header(key, value)
}
ctx.ResponseWriter.WriteHeader(http.StatusOK)
return
}
headers = opts.Header(origin)
for key, value := range headers {
ctx.Output.Header(key, value)
}
}
}

View File

@ -0,0 +1,253 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 cors
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
)
// HTTPHeaderGuardRecorder is httptest.ResponseRecorder with own http.Header
type HTTPHeaderGuardRecorder struct {
*httptest.ResponseRecorder
savedHeaderMap http.Header
}
// NewRecorder return HttpHeaderGuardRecorder
func NewRecorder() *HTTPHeaderGuardRecorder {
return &HTTPHeaderGuardRecorder{httptest.NewRecorder(), nil}
}
func (gr *HTTPHeaderGuardRecorder) WriteHeader(code int) {
gr.ResponseRecorder.WriteHeader(code)
gr.savedHeaderMap = gr.ResponseRecorder.Header()
}
func (gr *HTTPHeaderGuardRecorder) Header() http.Header {
if gr.savedHeaderMap != nil {
// headers were written. clone so we don't get updates
clone := make(http.Header)
for k, v := range gr.savedHeaderMap {
clone[k] = v
}
return clone
}
return gr.ResponseRecorder.Header()
}
func Test_AllowAll(t *testing.T) {
recorder := httptest.NewRecorder()
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{
AllowAllOrigins: true,
}))
handler.Any("/foo", func(ctx *context.Context) {
ctx.Output.SetStatus(500)
})
r, _ := http.NewRequest("PUT", "/foo", nil)
handler.ServeHTTP(recorder, r)
if recorder.HeaderMap.Get(headerAllowOrigin) != "*" {
t.Errorf("Allow-Origin header should be *")
}
}
func Test_AllowRegexMatch(t *testing.T) {
recorder := httptest.NewRecorder()
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{
AllowOrigins: []string{"https://aaa.com", "https://*.foo.com"},
}))
handler.Any("/foo", func(ctx *context.Context) {
ctx.Output.SetStatus(500)
})
origin := "https://bar.foo.com"
r, _ := http.NewRequest("PUT", "/foo", nil)
r.Header.Add("Origin", origin)
handler.ServeHTTP(recorder, r)
headerValue := recorder.HeaderMap.Get(headerAllowOrigin)
if headerValue != origin {
t.Errorf("Allow-Origin header should be %v, found %v", origin, headerValue)
}
}
func Test_AllowRegexNoMatch(t *testing.T) {
recorder := httptest.NewRecorder()
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{
AllowOrigins: []string{"https://*.foo.com"},
}))
handler.Any("/foo", func(ctx *context.Context) {
ctx.Output.SetStatus(500)
})
origin := "https://ww.foo.com.evil.com"
r, _ := http.NewRequest("PUT", "/foo", nil)
r.Header.Add("Origin", origin)
handler.ServeHTTP(recorder, r)
headerValue := recorder.HeaderMap.Get(headerAllowOrigin)
if headerValue != "" {
t.Errorf("Allow-Origin header should not exist, found %v", headerValue)
}
}
func Test_OtherHeaders(t *testing.T) {
recorder := httptest.NewRecorder()
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{
AllowAllOrigins: true,
AllowCredentials: true,
AllowMethods: []string{"PATCH", "GET"},
AllowHeaders: []string{"Origin", "X-whatever"},
ExposeHeaders: []string{"Content-Length", "Hello"},
MaxAge: 5 * time.Minute,
}))
handler.Any("/foo", func(ctx *context.Context) {
ctx.Output.SetStatus(500)
})
r, _ := http.NewRequest("PUT", "/foo", nil)
handler.ServeHTTP(recorder, r)
credentialsVal := recorder.HeaderMap.Get(headerAllowCredentials)
methodsVal := recorder.HeaderMap.Get(headerAllowMethods)
headersVal := recorder.HeaderMap.Get(headerAllowHeaders)
exposedHeadersVal := recorder.HeaderMap.Get(headerExposeHeaders)
maxAgeVal := recorder.HeaderMap.Get(headerMaxAge)
if credentialsVal != "true" {
t.Errorf("Allow-Credentials is expected to be true, found %v", credentialsVal)
}
if methodsVal != "PATCH,GET" {
t.Errorf("Allow-Methods is expected to be PATCH,GET; found %v", methodsVal)
}
if headersVal != "Origin,X-whatever" {
t.Errorf("Allow-Headers is expected to be Origin,X-whatever; found %v", headersVal)
}
if exposedHeadersVal != "Content-Length,Hello" {
t.Errorf("Expose-Headers are expected to be Content-Length,Hello. Found %v", exposedHeadersVal)
}
if maxAgeVal != "300" {
t.Errorf("Max-Age is expected to be 300, found %v", maxAgeVal)
}
}
func Test_DefaultAllowHeaders(t *testing.T) {
recorder := httptest.NewRecorder()
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{
AllowAllOrigins: true,
}))
handler.Any("/foo", func(ctx *context.Context) {
ctx.Output.SetStatus(500)
})
r, _ := http.NewRequest("PUT", "/foo", nil)
handler.ServeHTTP(recorder, r)
headersVal := recorder.HeaderMap.Get(headerAllowHeaders)
if headersVal != "Origin,Accept,Content-Type,Authorization" {
t.Errorf("Allow-Headers is expected to be Origin,Accept,Content-Type,Authorization; found %v", headersVal)
}
}
func Test_Preflight(t *testing.T) {
recorder := NewRecorder()
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{
AllowAllOrigins: true,
AllowMethods: []string{"PUT", "PATCH"},
AllowHeaders: []string{"Origin", "X-whatever", "X-CaseSensitive"},
}))
handler.Any("/foo", func(ctx *context.Context) {
ctx.Output.SetStatus(200)
})
r, _ := http.NewRequest("OPTIONS", "/foo", nil)
r.Header.Add(headerRequestMethod, "PUT")
r.Header.Add(headerRequestHeaders, "X-whatever, x-casesensitive")
handler.ServeHTTP(recorder, r)
headers := recorder.Header()
methodsVal := headers.Get(headerAllowMethods)
headersVal := headers.Get(headerAllowHeaders)
originVal := headers.Get(headerAllowOrigin)
if methodsVal != "PUT,PATCH" {
t.Errorf("Allow-Methods is expected to be PUT,PATCH, found %v", methodsVal)
}
if !strings.Contains(headersVal, "X-whatever") {
t.Errorf("Allow-Headers is expected to contain X-whatever, found %v", headersVal)
}
if !strings.Contains(headersVal, "x-casesensitive") {
t.Errorf("Allow-Headers is expected to contain x-casesensitive, found %v", headersVal)
}
if originVal != "*" {
t.Errorf("Allow-Origin is expected to be *, found %v", originVal)
}
if recorder.Code != http.StatusOK {
t.Errorf("Status code is expected to be 200, found %d", recorder.Code)
}
}
func Benchmark_WithoutCORS(b *testing.B) {
recorder := httptest.NewRecorder()
handler := beego.NewControllerRegister()
beego.BConfig.RunMode = beego.PROD
handler.Any("/foo", func(ctx *context.Context) {
ctx.Output.SetStatus(500)
})
b.ResetTimer()
r, _ := http.NewRequest("PUT", "/foo", nil)
for i := 0; i < b.N; i++ {
handler.ServeHTTP(recorder, r)
}
}
func Benchmark_WithCORS(b *testing.B) {
recorder := httptest.NewRecorder()
handler := beego.NewControllerRegister()
beego.BConfig.RunMode = beego.PROD
handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{
AllowAllOrigins: true,
AllowCredentials: true,
AllowMethods: []string{"PATCH", "GET"},
AllowHeaders: []string{"Origin", "X-whatever"},
MaxAge: 5 * time.Minute,
}))
handler.Any("/foo", func(ctx *context.Context) {
ctx.Output.SetStatus(500)
})
b.ResetTimer()
r, _ := http.NewRequest("PUT", "/foo", nil)
for i := 0; i < b.N; i++ {
handler.ServeHTTP(recorder, r)
}
}

613
src/vendor/github.com/astaxie/beego/router_test.go generated vendored Normal file
View File

@ -0,0 +1,613 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/astaxie/beego/context"
)
type TestController struct {
Controller
}
func (tc *TestController) Get() {
tc.Data["Username"] = "astaxie"
tc.Ctx.Output.Body([]byte("ok"))
}
func (tc *TestController) Post() {
tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Query(":name")))
}
func (tc *TestController) Param() {
tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Query(":name")))
}
func (tc *TestController) List() {
tc.Ctx.Output.Body([]byte("i am list"))
}
func (tc *TestController) Params() {
tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Param("0") + tc.Ctx.Input.Param("1") + tc.Ctx.Input.Param("2")))
}
func (tc *TestController) Myext() {
tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Param(":ext")))
}
func (tc *TestController) GetURL() {
tc.Ctx.Output.Body([]byte(tc.URLFor(".Myext")))
}
func (tc *TestController) GetParams() {
tc.Ctx.WriteString(tc.Ctx.Input.Query(":last") + "+" +
tc.Ctx.Input.Query(":first") + "+" + tc.Ctx.Input.Query("learn"))
}
func (tc *TestController) GetManyRouter() {
tc.Ctx.WriteString(tc.Ctx.Input.Query(":id") + tc.Ctx.Input.Query(":page"))
}
func (tc *TestController) GetEmptyBody() {
var res []byte
tc.Ctx.Output.Body(res)
}
type ResStatus struct {
Code int
Msg string
}
type JSONController struct {
Controller
}
func (jc *JSONController) Prepare() {
jc.Data["json"] = "prepare"
jc.ServeJSON(true)
}
func (jc *JSONController) Get() {
jc.Data["Username"] = "astaxie"
jc.Ctx.Output.Body([]byte("ok"))
}
func TestUrlFor(t *testing.T) {
handler := NewControllerRegister()
handler.Add("/api/list", &TestController{}, "*:List")
handler.Add("/person/:last/:first", &TestController{}, "*:Param")
if a := handler.URLFor("TestController.List"); a != "/api/list" {
Info(a)
t.Errorf("TestController.List must equal to /api/list")
}
if a := handler.URLFor("TestController.Param", ":last", "xie", ":first", "asta"); a != "/person/xie/asta" {
t.Errorf("TestController.Param must equal to /person/xie/asta, but get " + a)
}
}
func TestUrlFor3(t *testing.T) {
handler := NewControllerRegister()
handler.AddAuto(&TestController{})
if a := handler.URLFor("TestController.Myext"); a != "/test/myext" && a != "/Test/Myext" {
t.Errorf("TestController.Myext must equal to /test/myext, but get " + a)
}
if a := handler.URLFor("TestController.GetURL"); a != "/test/geturl" && a != "/Test/GetURL" {
t.Errorf("TestController.GetURL must equal to /test/geturl, but get " + a)
}
}
func TestUrlFor2(t *testing.T) {
handler := NewControllerRegister()
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, "*:List")
handler.Add("/v1/:username/edit", &TestController{}, "get:GetURL")
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param")
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" {
Info(handler.URLFor("TestController.GetURL"))
t.Errorf("TestController.List must equal to /v1/astaxie/edit")
}
if handler.URLFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") !=
"/v1/za/cms_12_123.html" {
Info(handler.URLFor("TestController.List"))
t.Errorf("TestController.List must equal to /v1/za/cms_12_123.html")
}
if handler.URLFor("TestController.Param", ":v", "za", ":id", "12", ":page", "123") !=
"/v1/za_cms/ttt_12_123.html" {
Info(handler.URLFor("TestController.Param"))
t.Errorf("TestController.List must equal to /v1/za_cms/ttt_12_123.html")
}
if handler.URLFor("TestController.Get", ":year", "1111", ":month", "11",
":title", "aaaa", ":entid", "aaaa") !=
"/1111/11/aaaa/aaaa" {
Info(handler.URLFor("TestController.Get"))
t.Errorf("TestController.Get must equal to /1111/11/aaaa/aaaa")
}
}
func TestUserFunc(t *testing.T) {
r, _ := http.NewRequest("GET", "/api/list", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/api/list", &TestController{}, "*:List")
handler.ServeHTTP(w, r)
if w.Body.String() != "i am list" {
t.Errorf("user define func can't run")
}
}
func TestPostFunc(t *testing.T) {
r, _ := http.NewRequest("POST", "/astaxie", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/:name", &TestController{})
handler.ServeHTTP(w, r)
if w.Body.String() != "astaxie" {
t.Errorf("post func should astaxie")
}
}
func TestAutoFunc(t *testing.T) {
r, _ := http.NewRequest("GET", "/test/list", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.AddAuto(&TestController{})
handler.ServeHTTP(w, r)
if w.Body.String() != "i am list" {
t.Errorf("user define func can't run")
}
}
func TestAutoFunc2(t *testing.T) {
r, _ := http.NewRequest("GET", "/Test/List", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.AddAuto(&TestController{})
handler.ServeHTTP(w, r)
if w.Body.String() != "i am list" {
t.Errorf("user define func can't run")
}
}
func TestAutoFuncParams(t *testing.T) {
r, _ := http.NewRequest("GET", "/test/params/2009/11/12", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.AddAuto(&TestController{})
handler.ServeHTTP(w, r)
if w.Body.String() != "20091112" {
t.Errorf("user define func can't run")
}
}
func TestAutoExtFunc(t *testing.T) {
r, _ := http.NewRequest("GET", "/test/myext.json", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.AddAuto(&TestController{})
handler.ServeHTTP(w, r)
if w.Body.String() != "json" {
t.Errorf("user define func can't run")
}
}
func TestRouteOk(t *testing.T) {
r, _ := http.NewRequest("GET", "/person/anderson/thomas?learn=kungfu", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/person/:last/:first", &TestController{}, "get:GetParams")
handler.ServeHTTP(w, r)
body := w.Body.String()
if body != "anderson+thomas+kungfu" {
t.Errorf("url param set to [%s];", body)
}
}
func TestManyRoute(t *testing.T) {
r, _ := http.NewRequest("GET", "/beego32-12.html", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, "get:GetManyRouter")
handler.ServeHTTP(w, r)
body := w.Body.String()
if body != "3212" {
t.Errorf("url param set to [%s];", body)
}
}
// Test for issue #1669
func TestEmptyResponse(t *testing.T) {
r, _ := http.NewRequest("GET", "/beego-empty.html", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/beego-empty.html", &TestController{}, "get:GetEmptyBody")
handler.ServeHTTP(w, r)
if body := w.Body.String(); body != "" {
t.Error("want empty body")
}
}
func TestNotFound(t *testing.T) {
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.ServeHTTP(w, r)
if w.Code != http.StatusNotFound {
t.Errorf("Code set to [%v]; want [%v]", w.Code, http.StatusNotFound)
}
}
// TestStatic tests the ability to serve static
// content from the filesystem
func TestStatic(t *testing.T) {
r, _ := http.NewRequest("GET", "/static/js/jquery.js", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.ServeHTTP(w, r)
if w.Code != 404 {
t.Errorf("handler.Static failed to serve file")
}
}
func TestPrepare(t *testing.T) {
r, _ := http.NewRequest("GET", "/json/list", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/json/list", &JSONController{})
handler.ServeHTTP(w, r)
if w.Body.String() != `"prepare"` {
t.Errorf(w.Body.String() + "user define func can't run")
}
}
func TestAutoPrefix(t *testing.T) {
r, _ := http.NewRequest("GET", "/admin/test/list", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.AddAutoPrefix("/admin", &TestController{})
handler.ServeHTTP(w, r)
if w.Body.String() != "i am list" {
t.Errorf("TestAutoPrefix can't run")
}
}
func TestRouterGet(t *testing.T) {
r, _ := http.NewRequest("GET", "/user", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Get("/user", func(ctx *context.Context) {
ctx.Output.Body([]byte("Get userlist"))
})
handler.ServeHTTP(w, r)
if w.Body.String() != "Get userlist" {
t.Errorf("TestRouterGet can't run")
}
}
func TestRouterPost(t *testing.T) {
r, _ := http.NewRequest("POST", "/user/123", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Post("/user/:id", func(ctx *context.Context) {
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
})
handler.ServeHTTP(w, r)
if w.Body.String() != "123" {
t.Errorf("TestRouterPost can't run")
}
}
func sayhello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("sayhello"))
}
func TestRouterHandler(t *testing.T) {
r, _ := http.NewRequest("POST", "/sayhi", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Handler("/sayhi", http.HandlerFunc(sayhello))
handler.ServeHTTP(w, r)
if w.Body.String() != "sayhello" {
t.Errorf("TestRouterHandler can't run")
}
}
func TestRouterHandlerAll(t *testing.T) {
r, _ := http.NewRequest("POST", "/sayhi/a/b/c", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Handler("/sayhi", http.HandlerFunc(sayhello), true)
handler.ServeHTTP(w, r)
if w.Body.String() != "sayhello" {
t.Errorf("TestRouterHandler can't run")
}
}
//
// Benchmarks NewApp:
//
func beegoFilterFunc(ctx *context.Context) {
ctx.WriteString("hello")
}
type AdminController struct {
Controller
}
func (a *AdminController) Get() {
a.Ctx.WriteString("hello")
}
func TestRouterFunc(t *testing.T) {
mux := NewControllerRegister()
mux.Get("/action", beegoFilterFunc)
mux.Post("/action", beegoFilterFunc)
rw, r := testRequest("GET", "/action")
mux.ServeHTTP(rw, r)
if rw.Body.String() != "hello" {
t.Errorf("TestRouterFunc can't run")
}
}
func BenchmarkFunc(b *testing.B) {
mux := NewControllerRegister()
mux.Get("/action", beegoFilterFunc)
rw, r := testRequest("GET", "/action")
b.ResetTimer()
for i := 0; i < b.N; i++ {
mux.ServeHTTP(rw, r)
}
}
func BenchmarkController(b *testing.B) {
mux := NewControllerRegister()
mux.Add("/action", &AdminController{})
rw, r := testRequest("GET", "/action")
b.ResetTimer()
for i := 0; i < b.N; i++ {
mux.ServeHTTP(rw, r)
}
}
func testRequest(method, path string) (*httptest.ResponseRecorder, *http.Request) {
request, _ := http.NewRequest(method, path, nil)
recorder := httptest.NewRecorder()
return recorder, request
}
// Execution point: BeforeRouter
// expectation: only BeforeRouter function is executed, notmatch output as router doesn't handle
func TestFilterBeforeRouter(t *testing.T) {
testName := "TestFilterBeforeRouter"
url := "/beforeRouter"
mux := NewControllerRegister()
mux.InsertFilter(url, BeforeRouter, beegoBeforeRouter1)
mux.Get(url, beegoFilterFunc)
rw, r := testRequest("GET", url)
mux.ServeHTTP(rw, r)
if strings.Contains(rw.Body.String(), "BeforeRouter1") == false {
t.Errorf(testName + " BeforeRouter did not run")
}
if strings.Contains(rw.Body.String(), "hello") == true {
t.Errorf(testName + " BeforeRouter did not return properly")
}
}
// Execution point: BeforeExec
// expectation: only BeforeExec function is executed, match as router determines route only
func TestFilterBeforeExec(t *testing.T) {
testName := "TestFilterBeforeExec"
url := "/beforeExec"
mux := NewControllerRegister()
mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput)
mux.InsertFilter(url, BeforeExec, beegoBeforeExec1)
mux.Get(url, beegoFilterFunc)
rw, r := testRequest("GET", url)
mux.ServeHTTP(rw, r)
if strings.Contains(rw.Body.String(), "BeforeExec1") == false {
t.Errorf(testName + " BeforeExec did not run")
}
if strings.Contains(rw.Body.String(), "hello") == true {
t.Errorf(testName + " BeforeExec did not return properly")
}
if strings.Contains(rw.Body.String(), "BeforeRouter") == true {
t.Errorf(testName + " BeforeRouter ran in error")
}
}
// Execution point: AfterExec
// expectation: only AfterExec function is executed, match as router handles
func TestFilterAfterExec(t *testing.T) {
testName := "TestFilterAfterExec"
url := "/afterExec"
mux := NewControllerRegister()
mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput)
mux.InsertFilter(url, BeforeExec, beegoFilterNoOutput)
mux.InsertFilter(url, AfterExec, beegoAfterExec1, false)
mux.Get(url, beegoFilterFunc)
rw, r := testRequest("GET", url)
mux.ServeHTTP(rw, r)
if strings.Contains(rw.Body.String(), "AfterExec1") == false {
t.Errorf(testName + " AfterExec did not run")
}
if strings.Contains(rw.Body.String(), "hello") == false {
t.Errorf(testName + " handler did not run properly")
}
if strings.Contains(rw.Body.String(), "BeforeRouter") == true {
t.Errorf(testName + " BeforeRouter ran in error")
}
if strings.Contains(rw.Body.String(), "BeforeExec") == true {
t.Errorf(testName + " BeforeExec ran in error")
}
}
// Execution point: FinishRouter
// expectation: only FinishRouter function is executed, match as router handles
func TestFilterFinishRouter(t *testing.T) {
testName := "TestFilterFinishRouter"
url := "/finishRouter"
mux := NewControllerRegister()
mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput)
mux.InsertFilter(url, BeforeExec, beegoFilterNoOutput)
mux.InsertFilter(url, AfterExec, beegoFilterNoOutput)
mux.InsertFilter(url, FinishRouter, beegoFinishRouter1)
mux.Get(url, beegoFilterFunc)
rw, r := testRequest("GET", url)
mux.ServeHTTP(rw, r)
if strings.Contains(rw.Body.String(), "FinishRouter1") == true {
t.Errorf(testName + " FinishRouter did not run")
}
if strings.Contains(rw.Body.String(), "hello") == false {
t.Errorf(testName + " handler did not run properly")
}
if strings.Contains(rw.Body.String(), "AfterExec1") == true {
t.Errorf(testName + " AfterExec ran in error")
}
if strings.Contains(rw.Body.String(), "BeforeRouter") == true {
t.Errorf(testName + " BeforeRouter ran in error")
}
if strings.Contains(rw.Body.String(), "BeforeExec") == true {
t.Errorf(testName + " BeforeExec ran in error")
}
}
// Execution point: FinishRouter
// expectation: only first FinishRouter function is executed, match as router handles
func TestFilterFinishRouterMultiFirstOnly(t *testing.T) {
testName := "TestFilterFinishRouterMultiFirstOnly"
url := "/finishRouterMultiFirstOnly"
mux := NewControllerRegister()
mux.InsertFilter(url, FinishRouter, beegoFinishRouter1, false)
mux.InsertFilter(url, FinishRouter, beegoFinishRouter2)
mux.Get(url, beegoFilterFunc)
rw, r := testRequest("GET", url)
mux.ServeHTTP(rw, r)
if strings.Contains(rw.Body.String(), "FinishRouter1") == false {
t.Errorf(testName + " FinishRouter1 did not run")
}
if strings.Contains(rw.Body.String(), "hello") == false {
t.Errorf(testName + " handler did not run properly")
}
// not expected in body
if strings.Contains(rw.Body.String(), "FinishRouter2") == true {
t.Errorf(testName + " FinishRouter2 did run")
}
}
// Execution point: FinishRouter
// expectation: both FinishRouter functions execute, match as router handles
func TestFilterFinishRouterMulti(t *testing.T) {
testName := "TestFilterFinishRouterMulti"
url := "/finishRouterMulti"
mux := NewControllerRegister()
mux.InsertFilter(url, FinishRouter, beegoFinishRouter1, false)
mux.InsertFilter(url, FinishRouter, beegoFinishRouter2, false)
mux.Get(url, beegoFilterFunc)
rw, r := testRequest("GET", url)
mux.ServeHTTP(rw, r)
if strings.Contains(rw.Body.String(), "FinishRouter1") == false {
t.Errorf(testName + " FinishRouter1 did not run")
}
if strings.Contains(rw.Body.String(), "hello") == false {
t.Errorf(testName + " handler did not run properly")
}
if strings.Contains(rw.Body.String(), "FinishRouter2") == false {
t.Errorf(testName + " FinishRouter2 did not run properly")
}
}
func beegoFilterNoOutput(ctx *context.Context) {
return
}
func beegoBeforeRouter1(ctx *context.Context) {
ctx.WriteString("|BeforeRouter1")
}
func beegoBeforeRouter2(ctx *context.Context) {
ctx.WriteString("|BeforeRouter2")
}
func beegoBeforeExec1(ctx *context.Context) {
ctx.WriteString("|BeforeExec1")
}
func beegoBeforeExec2(ctx *context.Context) {
ctx.WriteString("|BeforeExec2")
}
func beegoAfterExec1(ctx *context.Context) {
ctx.WriteString("|AfterExec1")
}
func beegoAfterExec2(ctx *context.Context) {
ctx.WriteString("|AfterExec2")
}
func beegoFinishRouter1(ctx *context.Context) {
ctx.WriteString("|FinishRouter1")
}
func beegoFinishRouter2(ctx *context.Context) {
ctx.WriteString("|FinishRouter2")
}

View File

@ -0,0 +1,243 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 couchbase for session provider
//
// depend on github.com/couchbaselabs/go-couchbasee
//
// go install github.com/couchbaselabs/go-couchbase
//
// Usage:
// import(
// _ "github.com/astaxie/beego/session/couchbase"
// "github.com/astaxie/beego/session"
// )
//
// func init() {
// globalSessions, _ = session.NewManager("couchbase", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"http://host:port/, Pool, Bucket"}``)
// go globalSessions.GC()
// }
//
// more docs: http://beego.me/docs/module/session.md
package couchbase
import (
"net/http"
"strings"
"sync"
couchbase "github.com/couchbase/go-couchbase"
"github.com/astaxie/beego/session"
)
var couchbpder = &Provider{}
// SessionStore store each session
type SessionStore struct {
b *couchbase.Bucket
sid string
lock sync.RWMutex
values map[interface{}]interface{}
maxlifetime int64
}
// Provider couchabse provided
type Provider struct {
maxlifetime int64
savePath string
pool string
bucket string
b *couchbase.Bucket
}
// Set value to couchabse session
func (cs *SessionStore) Set(key, value interface{}) error {
cs.lock.Lock()
defer cs.lock.Unlock()
cs.values[key] = value
return nil
}
// Get value from couchabse session
func (cs *SessionStore) Get(key interface{}) interface{} {
cs.lock.RLock()
defer cs.lock.RUnlock()
if v, ok := cs.values[key]; ok {
return v
}
return nil
}
// Delete value in couchbase session by given key
func (cs *SessionStore) Delete(key interface{}) error {
cs.lock.Lock()
defer cs.lock.Unlock()
delete(cs.values, key)
return nil
}
// Flush Clean all values in couchbase session
func (cs *SessionStore) Flush() error {
cs.lock.Lock()
defer cs.lock.Unlock()
cs.values = make(map[interface{}]interface{})
return nil
}
// SessionID Get couchbase session store id
func (cs *SessionStore) SessionID() string {
return cs.sid
}
// SessionRelease Write couchbase session with Gob string
func (cs *SessionStore) SessionRelease(w http.ResponseWriter) {
defer cs.b.Close()
bo, err := session.EncodeGob(cs.values)
if err != nil {
return
}
cs.b.Set(cs.sid, int(cs.maxlifetime), bo)
}
func (cp *Provider) getBucket() *couchbase.Bucket {
c, err := couchbase.Connect(cp.savePath)
if err != nil {
return nil
}
pool, err := c.GetPool(cp.pool)
if err != nil {
return nil
}
bucket, err := pool.GetBucket(cp.bucket)
if err != nil {
return nil
}
return bucket
}
// SessionInit init couchbase session
// savepath like couchbase server REST/JSON URL
// e.g. http://host:port/, Pool, Bucket
func (cp *Provider) SessionInit(maxlifetime int64, savePath string) error {
cp.maxlifetime = maxlifetime
configs := strings.Split(savePath, ",")
if len(configs) > 0 {
cp.savePath = configs[0]
}
if len(configs) > 1 {
cp.pool = configs[1]
}
if len(configs) > 2 {
cp.bucket = configs[2]
}
return nil
}
// SessionRead read couchbase session by sid
func (cp *Provider) SessionRead(sid string) (session.Store, error) {
cp.b = cp.getBucket()
var doc []byte
err := cp.b.Get(sid, &doc)
var kv map[interface{}]interface{}
if doc == nil {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(doc)
if err != nil {
return nil, err
}
}
cs := &SessionStore{b: cp.b, sid: sid, values: kv, maxlifetime: cp.maxlifetime}
return cs, nil
}
// SessionExist Check couchbase session exist.
// it checkes sid exist or not.
func (cp *Provider) SessionExist(sid string) bool {
cp.b = cp.getBucket()
defer cp.b.Close()
var doc []byte
if err := cp.b.Get(sid, &doc); err != nil || doc == nil {
return false
}
return true
}
// SessionRegenerate remove oldsid and use sid to generate new session
func (cp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
cp.b = cp.getBucket()
var doc []byte
if err := cp.b.Get(oldsid, &doc); err != nil || doc == nil {
cp.b.Set(sid, int(cp.maxlifetime), "")
} else {
err := cp.b.Delete(oldsid)
if err != nil {
return nil, err
}
_, _ = cp.b.Add(sid, int(cp.maxlifetime), doc)
}
err := cp.b.Get(sid, &doc)
if err != nil {
return nil, err
}
var kv map[interface{}]interface{}
if doc == nil {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(doc)
if err != nil {
return nil, err
}
}
cs := &SessionStore{b: cp.b, sid: sid, values: kv, maxlifetime: cp.maxlifetime}
return cs, nil
}
// SessionDestroy Remove bucket in this couchbase
func (cp *Provider) SessionDestroy(sid string) error {
cp.b = cp.getBucket()
defer cp.b.Close()
cp.b.Delete(sid)
return nil
}
// SessionGC Recycle
func (cp *Provider) SessionGC() {
return
}
// SessionAll return all active session
func (cp *Provider) SessionAll() int {
return 0
}
func init() {
session.Register("couchbase", couchbpder)
}

View File

@ -0,0 +1,179 @@
// Package ledis provide session Provider
package ledis
import (
"net/http"
"strconv"
"strings"
"sync"
"github.com/astaxie/beego/session"
"github.com/siddontang/ledisdb/config"
"github.com/siddontang/ledisdb/ledis"
)
var ledispder = &Provider{}
var c *ledis.DB
// SessionStore ledis session store
type SessionStore struct {
sid string
lock sync.RWMutex
values map[interface{}]interface{}
maxlifetime int64
}
// Set value in ledis session
func (ls *SessionStore) Set(key, value interface{}) error {
ls.lock.Lock()
defer ls.lock.Unlock()
ls.values[key] = value
return nil
}
// Get value in ledis session
func (ls *SessionStore) Get(key interface{}) interface{} {
ls.lock.RLock()
defer ls.lock.RUnlock()
if v, ok := ls.values[key]; ok {
return v
}
return nil
}
// Delete value in ledis session
func (ls *SessionStore) Delete(key interface{}) error {
ls.lock.Lock()
defer ls.lock.Unlock()
delete(ls.values, key)
return nil
}
// Flush clear all values in ledis session
func (ls *SessionStore) Flush() error {
ls.lock.Lock()
defer ls.lock.Unlock()
ls.values = make(map[interface{}]interface{})
return nil
}
// SessionID get ledis session id
func (ls *SessionStore) SessionID() string {
return ls.sid
}
// SessionRelease save session values to ledis
func (ls *SessionStore) SessionRelease(w http.ResponseWriter) {
b, err := session.EncodeGob(ls.values)
if err != nil {
return
}
c.Set([]byte(ls.sid), b)
c.Expire([]byte(ls.sid), ls.maxlifetime)
}
// Provider ledis session provider
type Provider struct {
maxlifetime int64
savePath string
db int
}
// SessionInit init ledis session
// savepath like ledis server saveDataPath,pool size
// e.g. 127.0.0.1:6379,100,astaxie
func (lp *Provider) SessionInit(maxlifetime int64, savePath string) error {
var err error
lp.maxlifetime = maxlifetime
configs := strings.Split(savePath, ",")
if len(configs) == 1 {
lp.savePath = configs[0]
} else if len(configs) == 2 {
lp.savePath = configs[0]
lp.db, err = strconv.Atoi(configs[1])
if err != nil {
return err
}
}
cfg := new(config.Config)
cfg.DataDir = lp.savePath
nowLedis, err := ledis.Open(cfg)
c, err = nowLedis.Select(lp.db)
if err != nil {
println(err)
return nil
}
return nil
}
// SessionRead read ledis session by sid
func (lp *Provider) SessionRead(sid string) (session.Store, error) {
kvs, err := c.Get([]byte(sid))
var kv map[interface{}]interface{}
if len(kvs) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(kvs)
if err != nil {
return nil, err
}
}
ls := &SessionStore{sid: sid, values: kv, maxlifetime: lp.maxlifetime}
return ls, nil
}
// SessionExist check ledis session exist by sid
func (lp *Provider) SessionExist(sid string) bool {
count, _ := c.Exists([]byte(sid))
if count == 0 {
return false
}
return true
}
// SessionRegenerate generate new sid for ledis session
func (lp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
count, _ := c.Exists([]byte(sid))
if count == 0 {
// oldsid doesn't exists, set the new sid directly
// ignore error here, since if it return error
// the existed value will be 0
c.Set([]byte(sid), []byte(""))
c.Expire([]byte(sid), lp.maxlifetime)
} else {
data, _ := c.Get([]byte(oldsid))
c.Set([]byte(sid), data)
c.Expire([]byte(sid), lp.maxlifetime)
}
kvs, err := c.Get([]byte(sid))
var kv map[interface{}]interface{}
if len(kvs) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob([]byte(kvs))
if err != nil {
return nil, err
}
}
ls := &SessionStore{sid: sid, values: kv, maxlifetime: lp.maxlifetime}
return ls, nil
}
// SessionDestroy delete ledis session by id
func (lp *Provider) SessionDestroy(sid string) error {
c.Del([]byte(sid))
return nil
}
// SessionGC Impelment method, no used.
func (lp *Provider) SessionGC() {
return
}
// SessionAll return all active session
func (lp *Provider) SessionAll() int {
return 0
}
func init() {
session.Register("ledis", ledispder)
}

View File

@ -0,0 +1,232 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 memcache for session provider
//
// depend on github.com/bradfitz/gomemcache/memcache
//
// go install github.com/bradfitz/gomemcache/memcache
//
// Usage:
// import(
// _ "github.com/astaxie/beego/session/memcache"
// "github.com/astaxie/beego/session"
// )
//
// func init() {
// globalSessions, _ = session.NewManager("memcache", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:11211"}``)
// go globalSessions.GC()
// }
//
// more docs: http://beego.me/docs/module/session.md
package memcache
import (
"net/http"
"strings"
"sync"
"github.com/astaxie/beego/session"
"github.com/bradfitz/gomemcache/memcache"
)
var mempder = &MemProvider{}
var client *memcache.Client
// SessionStore memcache session store
type SessionStore struct {
sid string
lock sync.RWMutex
values map[interface{}]interface{}
maxlifetime int64
}
// Set value in memcache session
func (rs *SessionStore) Set(key, value interface{}) error {
rs.lock.Lock()
defer rs.lock.Unlock()
rs.values[key] = value
return nil
}
// Get value in memcache session
func (rs *SessionStore) Get(key interface{}) interface{} {
rs.lock.RLock()
defer rs.lock.RUnlock()
if v, ok := rs.values[key]; ok {
return v
}
return nil
}
// Delete value in memcache session
func (rs *SessionStore) Delete(key interface{}) error {
rs.lock.Lock()
defer rs.lock.Unlock()
delete(rs.values, key)
return nil
}
// Flush clear all values in memcache session
func (rs *SessionStore) Flush() error {
rs.lock.Lock()
defer rs.lock.Unlock()
rs.values = make(map[interface{}]interface{})
return nil
}
// SessionID get memcache session id
func (rs *SessionStore) SessionID() string {
return rs.sid
}
// SessionRelease save session values to memcache
func (rs *SessionStore) SessionRelease(w http.ResponseWriter) {
b, err := session.EncodeGob(rs.values)
if err != nil {
return
}
item := memcache.Item{Key: rs.sid, Value: b, Expiration: int32(rs.maxlifetime)}
client.Set(&item)
}
// MemProvider memcache session provider
type MemProvider struct {
maxlifetime int64
conninfo []string
poolsize int
password string
}
// SessionInit init memcache session
// savepath like
// e.g. 127.0.0.1:9090
func (rp *MemProvider) SessionInit(maxlifetime int64, savePath string) error {
rp.maxlifetime = maxlifetime
rp.conninfo = strings.Split(savePath, ";")
client = memcache.New(rp.conninfo...)
return nil
}
// SessionRead read memcache session by sid
func (rp *MemProvider) SessionRead(sid string) (session.Store, error) {
if client == nil {
if err := rp.connectInit(); err != nil {
return nil, err
}
}
item, err := client.Get(sid)
if err != nil && err == memcache.ErrCacheMiss {
rs := &SessionStore{sid: sid, values: make(map[interface{}]interface{}), maxlifetime: rp.maxlifetime}
return rs, nil
}
var kv map[interface{}]interface{}
if len(item.Value) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(item.Value)
if err != nil {
return nil, err
}
}
rs := &SessionStore{sid: sid, values: kv, maxlifetime: rp.maxlifetime}
return rs, nil
}
// SessionExist check memcache session exist by sid
func (rp *MemProvider) SessionExist(sid string) bool {
if client == nil {
if err := rp.connectInit(); err != nil {
return false
}
}
if item, err := client.Get(sid); err != nil || len(item.Value) == 0 {
return false
}
return true
}
// SessionRegenerate generate new sid for memcache session
func (rp *MemProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
if client == nil {
if err := rp.connectInit(); err != nil {
return nil, err
}
}
var contain []byte
if item, err := client.Get(sid); err != nil || len(item.Value) == 0 {
// oldsid doesn't exists, set the new sid directly
// ignore error here, since if it return error
// the existed value will be 0
item.Key = sid
item.Value = []byte("")
item.Expiration = int32(rp.maxlifetime)
client.Set(item)
} else {
client.Delete(oldsid)
item.Key = sid
item.Expiration = int32(rp.maxlifetime)
client.Set(item)
contain = item.Value
}
var kv map[interface{}]interface{}
if len(contain) == 0 {
kv = make(map[interface{}]interface{})
} else {
var err error
kv, err = session.DecodeGob(contain)
if err != nil {
return nil, err
}
}
rs := &SessionStore{sid: sid, values: kv, maxlifetime: rp.maxlifetime}
return rs, nil
}
// SessionDestroy delete memcache session by id
func (rp *MemProvider) SessionDestroy(sid string) error {
if client == nil {
if err := rp.connectInit(); err != nil {
return err
}
}
err := client.Delete(sid)
if err != nil {
return err
}
return nil
}
func (rp *MemProvider) connectInit() error {
client = memcache.New(rp.conninfo...)
return nil
}
// SessionGC Impelment method, no used.
func (rp *MemProvider) SessionGC() {
return
}
// SessionAll return all activeSession
func (rp *MemProvider) SessionAll() int {
return 0
}
func init() {
session.Register("memcache", mempder)
}

View File

@ -0,0 +1,233 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 mysql for session provider
//
// depends on github.com/go-sql-driver/mysql:
//
// go install github.com/go-sql-driver/mysql
//
// mysql session support need create table as sql:
// CREATE TABLE `session` (
// `session_key` char(64) NOT NULL,
// `session_data` blob,
// `session_expiry` int(11) unsigned NOT NULL,
// PRIMARY KEY (`session_key`)
// ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
//
// Usage:
// import(
// _ "github.com/astaxie/beego/session/mysql"
// "github.com/astaxie/beego/session"
// )
//
// func init() {
// globalSessions, _ = session.NewManager("mysql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]"}``)
// go globalSessions.GC()
// }
//
// more docs: http://beego.me/docs/module/session.md
package mysql
import (
"database/sql"
"net/http"
"sync"
"time"
"github.com/astaxie/beego/session"
// import mysql driver
_ "github.com/go-sql-driver/mysql"
)
var (
// TableName store the session in MySQL
TableName = "session"
mysqlpder = &Provider{}
)
// SessionStore mysql session store
type SessionStore struct {
c *sql.DB
sid string
lock sync.RWMutex
values map[interface{}]interface{}
}
// Set value in mysql session.
// it is temp value in map.
func (st *SessionStore) Set(key, value interface{}) error {
st.lock.Lock()
defer st.lock.Unlock()
st.values[key] = value
return nil
}
// Get value from mysql session
func (st *SessionStore) Get(key interface{}) interface{} {
st.lock.RLock()
defer st.lock.RUnlock()
if v, ok := st.values[key]; ok {
return v
}
return nil
}
// Delete value in mysql session
func (st *SessionStore) Delete(key interface{}) error {
st.lock.Lock()
defer st.lock.Unlock()
delete(st.values, key)
return nil
}
// Flush clear all values in mysql session
func (st *SessionStore) Flush() error {
st.lock.Lock()
defer st.lock.Unlock()
st.values = make(map[interface{}]interface{})
return nil
}
// SessionID get session id of this mysql session store
func (st *SessionStore) SessionID() string {
return st.sid
}
// SessionRelease save mysql session values to database.
// must call this method to save values to database.
func (st *SessionStore) SessionRelease(w http.ResponseWriter) {
defer st.c.Close()
b, err := session.EncodeGob(st.values)
if err != nil {
return
}
st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?",
b, time.Now().Unix(), st.sid)
}
// Provider mysql session provider
type Provider struct {
maxlifetime int64
savePath string
}
// connect to mysql
func (mp *Provider) connectInit() *sql.DB {
db, e := sql.Open("mysql", mp.savePath)
if e != nil {
return nil
}
return db
}
// SessionInit init mysql session.
// savepath is the connection string of mysql.
func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error {
mp.maxlifetime = maxlifetime
mp.savePath = savePath
return nil
}
// SessionRead get mysql session by sid
func (mp *Provider) SessionRead(sid string) (session.Store, error) {
c := mp.connectInit()
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)",
sid, "", time.Now().Unix())
}
var kv map[interface{}]interface{}
if len(sessiondata) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(sessiondata)
if err != nil {
return nil, err
}
}
rs := &SessionStore{c: c, sid: sid, values: kv}
return rs, nil
}
// SessionExist check mysql session exist
func (mp *Provider) SessionExist(sid string) bool {
c := mp.connectInit()
defer c.Close()
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
return false
}
return true
}
// SessionRegenerate generate new sid for mysql session
func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
c := mp.connectInit()
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", oldsid, "", time.Now().Unix())
}
c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid)
var kv map[interface{}]interface{}
if len(sessiondata) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(sessiondata)
if err != nil {
return nil, err
}
}
rs := &SessionStore{c: c, sid: sid, values: kv}
return rs, nil
}
// SessionDestroy delete mysql session by sid
func (mp *Provider) SessionDestroy(sid string) error {
c := mp.connectInit()
c.Exec("DELETE FROM "+TableName+" where session_key=?", sid)
c.Close()
return nil
}
// SessionGC delete expired values in mysql session
func (mp *Provider) SessionGC() {
c := mp.connectInit()
c.Exec("DELETE from "+TableName+" where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
c.Close()
return
}
// SessionAll count values in mysql session
func (mp *Provider) SessionAll() int {
c := mp.connectInit()
defer c.Close()
var total int
err := c.QueryRow("SELECT count(*) as num from " + TableName).Scan(&total)
if err != nil {
return 0
}
return total
}
func init() {
session.Register("mysql", mysqlpder)
}

View File

@ -0,0 +1,248 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 postgres for session provider
//
// depends on github.com/lib/pq:
//
// go install github.com/lib/pq
//
//
// needs this table in your database:
//
// CREATE TABLE session (
// session_key char(64) NOT NULL,
// session_data bytea,
// session_expiry timestamp NOT NULL,
// CONSTRAINT session_key PRIMARY KEY(session_key)
// );
//
// will be activated with these settings in app.conf:
//
// SessionOn = true
// SessionProvider = postgresql
// SessionSavePath = "user=a password=b dbname=c sslmode=disable"
// SessionName = session
//
//
// Usage:
// import(
// _ "github.com/astaxie/beego/session/postgresql"
// "github.com/astaxie/beego/session"
// )
//
// func init() {
// globalSessions, _ = session.NewManager("postgresql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"user=pqgotest dbname=pqgotest sslmode=verify-full"}``)
// go globalSessions.GC()
// }
//
// more docs: http://beego.me/docs/module/session.md
package postgres
import (
"database/sql"
"net/http"
"sync"
"time"
"github.com/astaxie/beego/session"
// import postgresql Driver
_ "github.com/lib/pq"
)
var postgresqlpder = &Provider{}
// SessionStore postgresql session store
type SessionStore struct {
c *sql.DB
sid string
lock sync.RWMutex
values map[interface{}]interface{}
}
// Set value in postgresql session.
// it is temp value in map.
func (st *SessionStore) Set(key, value interface{}) error {
st.lock.Lock()
defer st.lock.Unlock()
st.values[key] = value
return nil
}
// Get value from postgresql session
func (st *SessionStore) Get(key interface{}) interface{} {
st.lock.RLock()
defer st.lock.RUnlock()
if v, ok := st.values[key]; ok {
return v
}
return nil
}
// Delete value in postgresql session
func (st *SessionStore) Delete(key interface{}) error {
st.lock.Lock()
defer st.lock.Unlock()
delete(st.values, key)
return nil
}
// Flush clear all values in postgresql session
func (st *SessionStore) Flush() error {
st.lock.Lock()
defer st.lock.Unlock()
st.values = make(map[interface{}]interface{})
return nil
}
// SessionID get session id of this postgresql session store
func (st *SessionStore) SessionID() string {
return st.sid
}
// SessionRelease save postgresql session values to database.
// must call this method to save values to database.
func (st *SessionStore) SessionRelease(w http.ResponseWriter) {
defer st.c.Close()
b, err := session.EncodeGob(st.values)
if err != nil {
return
}
st.c.Exec("UPDATE session set session_data=$1, session_expiry=$2 where session_key=$3",
b, time.Now().Format(time.RFC3339), st.sid)
}
// Provider postgresql session provider
type Provider struct {
maxlifetime int64
savePath string
}
// connect to postgresql
func (mp *Provider) connectInit() *sql.DB {
db, e := sql.Open("postgres", mp.savePath)
if e != nil {
return nil
}
return db
}
// SessionInit init postgresql session.
// savepath is the connection string of postgresql.
func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error {
mp.maxlifetime = maxlifetime
mp.savePath = savePath
return nil
}
// SessionRead get postgresql session by sid
func (mp *Provider) SessionRead(sid string) (session.Store, error) {
c := mp.connectInit()
row := c.QueryRow("select session_data from session where session_key=$1", sid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
_, err = c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)",
sid, "", time.Now().Format(time.RFC3339))
if err != nil {
return nil, err
}
} else if err != nil {
return nil, err
}
var kv map[interface{}]interface{}
if len(sessiondata) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(sessiondata)
if err != nil {
return nil, err
}
}
rs := &SessionStore{c: c, sid: sid, values: kv}
return rs, nil
}
// SessionExist check postgresql session exist
func (mp *Provider) SessionExist(sid string) bool {
c := mp.connectInit()
defer c.Close()
row := c.QueryRow("select session_data from session where session_key=$1", sid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
return false
}
return true
}
// SessionRegenerate generate new sid for postgresql session
func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
c := mp.connectInit()
row := c.QueryRow("select session_data from session where session_key=$1", oldsid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)",
oldsid, "", time.Now().Format(time.RFC3339))
}
c.Exec("update session set session_key=$1 where session_key=$2", sid, oldsid)
var kv map[interface{}]interface{}
if len(sessiondata) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(sessiondata)
if err != nil {
return nil, err
}
}
rs := &SessionStore{c: c, sid: sid, values: kv}
return rs, nil
}
// SessionDestroy delete postgresql session by sid
func (mp *Provider) SessionDestroy(sid string) error {
c := mp.connectInit()
c.Exec("DELETE FROM session where session_key=$1", sid)
c.Close()
return nil
}
// SessionGC delete expired values in postgresql session
func (mp *Provider) SessionGC() {
c := mp.connectInit()
c.Exec("DELETE from session where EXTRACT(EPOCH FROM (current_timestamp - session_expiry)) > $1", mp.maxlifetime)
c.Close()
return
}
// SessionAll count values in postgresql session
func (mp *Provider) SessionAll() int {
c := mp.connectInit()
defer c.Close()
var total int
err := c.QueryRow("SELECT count(*) as num from session").Scan(&total)
if err != nil {
return 0
}
return total
}
func init() {
session.Register("postgresql", postgresqlpder)
}

View File

@ -0,0 +1,96 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 session
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestCookie(t *testing.T) {
config := `{"cookieName":"gosessionid","enableSetCookie":false,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}`
globalSessions, err := NewManager("cookie", config)
if err != nil {
t.Fatal("init cookie session err", err)
}
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
sess, err := globalSessions.SessionStart(w, r)
if err != nil {
t.Fatal("set error,", err)
}
err = sess.Set("username", "astaxie")
if err != nil {
t.Fatal("set error,", err)
}
if username := sess.Get("username"); username != "astaxie" {
t.Fatal("get username error")
}
sess.SessionRelease(w)
if cookiestr := w.Header().Get("Set-Cookie"); cookiestr == "" {
t.Fatal("setcookie error")
} else {
parts := strings.Split(strings.TrimSpace(cookiestr), ";")
for k, v := range parts {
nameval := strings.Split(v, "=")
if k == 0 && nameval[0] != "gosessionid" {
t.Fatal("error")
}
}
}
}
func TestDestorySessionCookie(t *testing.T) {
config := `{"cookieName":"gosessionid","enableSetCookie":true,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}`
globalSessions, err := NewManager("cookie", config)
if err != nil {
t.Fatal("init cookie session err", err)
}
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
session, err := globalSessions.SessionStart(w, r)
if err != nil {
t.Fatal("session start err,", err)
}
// request again ,will get same sesssion id .
r1, _ := http.NewRequest("GET", "/", nil)
r1.Header.Set("Cookie", w.Header().Get("Set-Cookie"))
w = httptest.NewRecorder()
newSession, err := globalSessions.SessionStart(w, r1)
if err != nil {
t.Fatal("session start err,", err)
}
if newSession.SessionID() != session.SessionID() {
t.Fatal("get cookie session id is not the same again.")
}
// After destroy session , will get a new session id .
globalSessions.SessionDestroy(w, r1)
r2, _ := http.NewRequest("GET", "/", nil)
r2.Header.Set("Cookie", w.Header().Get("Set-Cookie"))
w = httptest.NewRecorder()
newSession, err = globalSessions.SessionStart(w, r2)
if err != nil {
t.Fatal("session start error")
}
if newSession.SessionID() == session.SessionID() {
t.Fatal("after destroy session and reqeust again ,get cookie session id is same.")
}
}

View File

@ -0,0 +1,52 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 session
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestMem(t *testing.T) {
globalSessions, _ := NewManager("memory", `{"cookieName":"gosessionid","gclifetime":10}`)
go globalSessions.GC()
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
sess, err := globalSessions.SessionStart(w, r)
if err != nil {
t.Fatal("set error,", err)
}
defer sess.SessionRelease(w)
err = sess.Set("username", "astaxie")
if err != nil {
t.Fatal("set error,", err)
}
if username := sess.Get("username"); username != "astaxie" {
t.Fatal("get username error")
}
if cookiestr := w.Header().Get("Set-Cookie"); cookiestr == "" {
t.Fatal("setcookie error")
} else {
parts := strings.Split(strings.TrimSpace(cookiestr), ";")
for k, v := range parts {
nameval := strings.Split(v, "=")
if k == 0 && nameval[0] != "gosessionid" {
t.Fatal("error")
}
}
}
}

View File

@ -0,0 +1,132 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 session
import (
"crypto/aes"
"encoding/json"
"testing"
)
func Test_gob(t *testing.T) {
a := make(map[interface{}]interface{})
a["username"] = "astaxie"
a[12] = 234
a["user"] = User{"asta", "xie"}
b, err := EncodeGob(a)
if err != nil {
t.Error(err)
}
c, err := DecodeGob(b)
if err != nil {
t.Error(err)
}
if len(c) == 0 {
t.Error("decodeGob empty")
}
if c["username"] != "astaxie" {
t.Error("decode string error")
}
if c[12] != 234 {
t.Error("decode int error")
}
if c["user"].(User).Username != "asta" {
t.Error("decode struct error")
}
}
type User struct {
Username string
NickName string
}
func TestGenerate(t *testing.T) {
str := generateRandomKey(20)
if len(str) != 20 {
t.Fatal("generate length is not equal to 20")
}
}
func TestCookieEncodeDecode(t *testing.T) {
hashKey := "testhashKey"
blockkey := generateRandomKey(16)
block, err := aes.NewCipher(blockkey)
if err != nil {
t.Fatal("NewCipher:", err)
}
securityName := string(generateRandomKey(20))
val := make(map[interface{}]interface{})
val["name"] = "astaxie"
val["gender"] = "male"
str, err := encodeCookie(block, hashKey, securityName, val)
if err != nil {
t.Fatal("encodeCookie:", err)
}
dst := make(map[interface{}]interface{})
dst, err = decodeCookie(block, hashKey, securityName, str, 3600)
if err != nil {
t.Fatal("decodeCookie", err)
}
if dst["name"] != "astaxie" {
t.Fatal("dst get map error")
}
if dst["gender"] != "male" {
t.Fatal("dst get map error")
}
}
func TestParseConfig(t *testing.T) {
s := `{"cookieName":"gosessionid","gclifetime":3600}`
cf := new(managerConfig)
cf.EnableSetCookie = true
err := json.Unmarshal([]byte(s), cf)
if err != nil {
t.Fatal("parse json error,", err)
}
if cf.CookieName != "gosessionid" {
t.Fatal("parseconfig get cookiename error")
}
if cf.Gclifetime != 3600 {
t.Fatal("parseconfig get gclifetime error")
}
cc := `{"cookieName":"gosessionid","enableSetCookie":false,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}`
cf2 := new(managerConfig)
cf2.EnableSetCookie = true
err = json.Unmarshal([]byte(cc), cf2)
if err != nil {
t.Fatal("parse json error,", err)
}
if cf2.CookieName != "gosessionid" {
t.Fatal("parseconfig get cookiename error")
}
if cf2.Gclifetime != 3600 {
t.Fatal("parseconfig get gclifetime error")
}
if cf2.EnableSetCookie != false {
t.Fatal("parseconfig get enableSetCookie error")
}
cconfig := new(cookieConfig)
err = json.Unmarshal([]byte(cf2.ProviderConfig), cconfig)
if err != nil {
t.Fatal("parse ProviderConfig err,", err)
}
if cconfig.CookieName != "gosessionid" {
t.Fatal("ProviderConfig get cookieName error")
}
if cconfig.SecurityKey != "beegocookiehashkey" {
t.Fatal("ProviderConfig get securityKey error")
}
}

73
src/vendor/github.com/astaxie/beego/staticfile_test.go generated vendored Normal file
View File

@ -0,0 +1,73 @@
package beego
import (
"bytes"
"compress/gzip"
"compress/zlib"
"io"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
var currentWorkDir, _ = os.Getwd()
var licenseFile = filepath.Join(currentWorkDir, "LICENSE")
func testOpenFile(encoding string, content []byte, t *testing.T) {
fi, _ := os.Stat(licenseFile)
b, n, sch, err := openFile(licenseFile, fi, encoding)
if err != nil {
t.Log(err)
t.Fail()
}
t.Log("open static file encoding "+n, b)
assetOpenFileAndContent(sch, content, t)
}
func TestOpenStaticFile_1(t *testing.T) {
file, _ := os.Open(licenseFile)
content, _ := ioutil.ReadAll(file)
testOpenFile("", content, t)
}
func TestOpenStaticFileGzip_1(t *testing.T) {
file, _ := os.Open(licenseFile)
var zipBuf bytes.Buffer
fileWriter, _ := gzip.NewWriterLevel(&zipBuf, gzip.BestCompression)
io.Copy(fileWriter, file)
fileWriter.Close()
content, _ := ioutil.ReadAll(&zipBuf)
testOpenFile("gzip", content, t)
}
func TestOpenStaticFileDeflate_1(t *testing.T) {
file, _ := os.Open(licenseFile)
var zipBuf bytes.Buffer
fileWriter, _ := zlib.NewWriterLevel(&zipBuf, zlib.BestCompression)
io.Copy(fileWriter, file)
fileWriter.Close()
content, _ := ioutil.ReadAll(&zipBuf)
testOpenFile("deflate", content, t)
}
func assetOpenFileAndContent(sch *serveContentHolder, content []byte, t *testing.T) {
t.Log(sch.size, len(content))
if sch.size != int64(len(content)) {
t.Log("static content file size not same")
t.Fail()
}
bs, _ := ioutil.ReadAll(sch)
for i, v := range content {
if v != bs[i] {
t.Log("content not same")
t.Fail()
}
}
if len(staticFileMap) == 0 {
t.Log("men map is empty")
t.Fail()
}
}

View File

@ -0,0 +1,160 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 swagger struct definition
package swagger
// SwaggerVersion show the current swagger version
const SwaggerVersion = "1.2"
// ResourceListing list the resource
type ResourceListing struct {
APIVersion string `json:"apiVersion"`
SwaggerVersion string `json:"swaggerVersion"` // e.g 1.2
// BasePath string `json:"basePath"` obsolete in 1.1
APIs []APIRef `json:"apis"`
Info Information `json:"info"`
}
// APIRef description the api path and description
type APIRef struct {
Path string `json:"path"` // relative or absolute, must start with /
Description string `json:"description"`
}
// Information show the API Information
type Information struct {
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Contact string `json:"contact,omitempty"`
TermsOfServiceURL string `json:"termsOfServiceUrl,omitempty"`
License string `json:"license,omitempty"`
LicenseURL string `json:"licenseUrl,omitempty"`
}
// APIDeclaration see https://github.com/wordnik/swagger-core/blob/scala_2.10-1.3-RC3/schemas/api-declaration-schema.json
type APIDeclaration struct {
APIVersion string `json:"apiVersion"`
SwaggerVersion string `json:"swaggerVersion"`
BasePath string `json:"basePath"`
ResourcePath string `json:"resourcePath"` // must start with /
Consumes []string `json:"consumes,omitempty"`
Produces []string `json:"produces,omitempty"`
APIs []API `json:"apis,omitempty"`
Models map[string]Model `json:"models,omitempty"`
}
// API show tha API struct
type API struct {
Path string `json:"path"` // relative or absolute, must start with /
Description string `json:"description"`
Operations []Operation `json:"operations,omitempty"`
}
// Operation desc the Operation
type Operation struct {
HTTPMethod string `json:"httpMethod"`
Nickname string `json:"nickname"`
Type string `json:"type"` // in 1.1 = DataType
// ResponseClass string `json:"responseClass"` obsolete in 1.2
Summary string `json:"summary,omitempty"`
Notes string `json:"notes,omitempty"`
Parameters []Parameter `json:"parameters,omitempty"`
ResponseMessages []ResponseMessage `json:"responseMessages,omitempty"` // optional
Consumes []string `json:"consumes,omitempty"`
Produces []string `json:"produces,omitempty"`
Authorizations []Authorization `json:"authorizations,omitempty"`
Protocols []Protocol `json:"protocols,omitempty"`
}
// Protocol support which Protocol
type Protocol struct {
}
// ResponseMessage Show the
type ResponseMessage struct {
Code int `json:"code"`
Message string `json:"message"`
ResponseModel string `json:"responseModel"`
}
// Parameter desc the request parameters
type Parameter struct {
ParamType string `json:"paramType"` // path,query,body,header,form
Name string `json:"name"`
Description string `json:"description"`
DataType string `json:"dataType"` // 1.2 needed?
Type string `json:"type"` // integer
Format string `json:"format"` // int64
AllowMultiple bool `json:"allowMultiple"`
Required bool `json:"required"`
Minimum int `json:"minimum"`
Maximum int `json:"maximum"`
}
// ErrorResponse desc response
type ErrorResponse struct {
Code int `json:"code"`
Reason string `json:"reason"`
}
// Model define the data model
type Model struct {
ID string `json:"id"`
Required []string `json:"required,omitempty"`
Properties map[string]ModelProperty `json:"properties"`
}
// ModelProperty define the properties
type ModelProperty struct {
Type string `json:"type"`
Description string `json:"description"`
Items map[string]string `json:"items,omitempty"`
Format string `json:"format"`
}
// Authorization see https://github.com/wordnik/swagger-core/wiki/authorizations
type Authorization struct {
LocalOAuth OAuth `json:"local-oauth"`
APIKey APIKey `json:"apiKey"`
}
// OAuth see https://github.com/wordnik/swagger-core/wiki/authorizations
type OAuth struct {
Type string `json:"type"` // e.g. oauth2
Scopes []string `json:"scopes"` // e.g. PUBLIC
GrantTypes map[string]GrantType `json:"grantTypes"`
}
// GrantType see https://github.com/wordnik/swagger-core/wiki/authorizations
type GrantType struct {
LoginEndpoint Endpoint `json:"loginEndpoint"`
TokenName string `json:"tokenName"` // e.g. access_code
TokenRequestEndpoint Endpoint `json:"tokenRequestEndpoint"`
TokenEndpoint Endpoint `json:"tokenEndpoint"`
}
// Endpoint see https://github.com/wordnik/swagger-core/wiki/authorizations
type Endpoint struct {
URL string `json:"url"`
ClientIDName string `json:"clientIdName"`
ClientSecretName string `json:"clientSecretName"`
TokenName string `json:"tokenName"`
}
// APIKey see https://github.com/wordnik/swagger-core/wiki/authorizations
type APIKey struct {
Type string `json:"type"` // e.g. apiKey
PassAs string `json:"passAs"` // e.g. header
}

136
src/vendor/github.com/astaxie/beego/template_test.go generated vendored Normal file
View File

@ -0,0 +1,136 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"os"
"path/filepath"
"testing"
)
var header = `{{define "header"}}
<h1>Hello, astaxie!</h1>
{{end}}`
var index = `<!DOCTYPE html>
<html>
<head>
<title>beego welcome template</title>
</head>
<body>
{{template "block"}}
{{template "header"}}
{{template "blocks/block.tpl"}}
</body>
</html>
`
var block = `{{define "block"}}
<h1>Hello, blocks!</h1>
{{end}}`
func TestTemplate(t *testing.T) {
dir := "_beeTmp"
files := []string{
"header.tpl",
"index.tpl",
"blocks/block.tpl",
}
if err := os.MkdirAll(dir, 0777); err != nil {
t.Fatal(err)
}
for k, name := range files {
os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777)
if f, err := os.Create(filepath.Join(dir, name)); err != nil {
t.Fatal(err)
} else {
if k == 0 {
f.WriteString(header)
} else if k == 1 {
f.WriteString(index)
} else if k == 2 {
f.WriteString(block)
}
f.Close()
}
}
if err := BuildTemplate(dir); err != nil {
t.Fatal(err)
}
if len(beeTemplates) != 3 {
t.Fatalf("should be 3 but got %v", len(beeTemplates))
}
if err := beeTemplates["index.tpl"].ExecuteTemplate(os.Stdout, "index.tpl", nil); err != nil {
t.Fatal(err)
}
for _, name := range files {
os.RemoveAll(filepath.Join(dir, name))
}
os.RemoveAll(dir)
}
var menu = `<div class="menu">
<ul>
<li>menu1</li>
<li>menu2</li>
<li>menu3</li>
</ul>
</div>
`
var user = `<!DOCTYPE html>
<html>
<head>
<title>beego welcome template</title>
</head>
<body>
{{template "../public/menu.tpl"}}
</body>
</html>
`
func TestRelativeTemplate(t *testing.T) {
dir := "_beeTmp"
files := []string{
"easyui/public/menu.tpl",
"easyui/rbac/user.tpl",
}
if err := os.MkdirAll(dir, 0777); err != nil {
t.Fatal(err)
}
for k, name := range files {
os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777)
if f, err := os.Create(filepath.Join(dir, name)); err != nil {
t.Fatal(err)
} else {
if k == 0 {
f.WriteString(menu)
} else if k == 1 {
f.WriteString(user)
}
f.Close()
}
}
if err := BuildTemplate(dir, files[1]); err != nil {
t.Fatal(err)
}
if err := beeTemplates["easyui/rbac/user.tpl"].ExecuteTemplate(os.Stdout, "easyui/rbac/user.tpl", nil); err != nil {
t.Fatal(err)
}
for _, name := range files {
os.RemoveAll(filepath.Join(dir, name))
}
os.RemoveAll(dir)
}

View File

@ -0,0 +1,323 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"html/template"
"net/url"
"reflect"
"testing"
"time"
)
func TestSubstr(t *testing.T) {
s := `012345`
if Substr(s, 0, 2) != "01" {
t.Error("should be equal")
}
if Substr(s, 0, 100) != "012345" {
t.Error("should be equal")
}
if Substr(s, 12, 100) != "012345" {
t.Error("should be equal")
}
}
func TestHtml2str(t *testing.T) {
h := `<HTML><style></style><script>x<x</script></HTML><123> 123\n
\n`
if HTML2str(h) != "123\\n\n\\n" {
t.Error("should be equal")
}
}
func TestDateFormat(t *testing.T) {
ts := "Mon, 01 Jul 2013 13:27:42 CST"
tt, _ := time.Parse(time.RFC1123, ts)
if ss := DateFormat(tt, "2006-01-02 15:04:05"); ss != "2013-07-01 13:27:42" {
t.Errorf("2013-07-01 13:27:42 does not equal %v", ss)
}
}
func TestDate(t *testing.T) {
ts := "Mon, 01 Jul 2013 13:27:42 CST"
tt, _ := time.Parse(time.RFC1123, ts)
if ss := Date(tt, "Y-m-d H:i:s"); ss != "2013-07-01 13:27:42" {
t.Errorf("2013-07-01 13:27:42 does not equal %v", ss)
}
if ss := Date(tt, "y-n-j h:i:s A"); ss != "13-7-1 01:27:42 PM" {
t.Errorf("13-7-1 01:27:42 PM does not equal %v", ss)
}
if ss := Date(tt, "D, d M Y g:i:s a"); ss != "Mon, 01 Jul 2013 1:27:42 pm" {
t.Errorf("Mon, 01 Jul 2013 1:27:42 pm does not equal %v", ss)
}
if ss := Date(tt, "l, d F Y G:i:s"); ss != "Monday, 01 July 2013 13:27:42" {
t.Errorf("Monday, 01 July 2013 13:27:42 does not equal %v", ss)
}
}
func TestCompareRelated(t *testing.T) {
if !Compare("abc", "abc") {
t.Error("should be equal")
}
if Compare("abc", "aBc") {
t.Error("should be not equal")
}
if !Compare("1", 1) {
t.Error("should be equal")
}
if CompareNot("abc", "abc") {
t.Error("should be equal")
}
if !CompareNot("abc", "aBc") {
t.Error("should be not equal")
}
if !NotNil("a string") {
t.Error("should not be nil")
}
}
func TestHtmlquote(t *testing.T) {
h := `&lt;&#39;&nbsp;&rdquo;&ldquo;&amp;&quot;&gt;`
s := `<' ”“&">`
if Htmlquote(s) != h {
t.Error("should be equal")
}
}
func TestHtmlunquote(t *testing.T) {
h := `&lt;&#39;&nbsp;&rdquo;&ldquo;&amp;&quot;&gt;`
s := `<' ”“&">`
if Htmlunquote(h) != s {
t.Error("should be equal")
}
}
func TestParseForm(t *testing.T) {
type user struct {
ID int `form:"-"`
tag string `form:"tag"`
Name interface{} `form:"username"`
Age int `form:"age,text"`
Email string
Intro string `form:",textarea"`
StrBool bool `form:"strbool"`
Date time.Time `form:"date,2006-01-02"`
}
u := user{}
form := url.Values{
"ID": []string{"1"},
"-": []string{"1"},
"tag": []string{"no"},
"username": []string{"test"},
"age": []string{"40"},
"Email": []string{"test@gmail.com"},
"Intro": []string{"I am an engineer!"},
"strbool": []string{"yes"},
"date": []string{"2014-11-12"},
}
if err := ParseForm(form, u); err == nil {
t.Fatal("nothing will be changed")
}
if err := ParseForm(form, &u); err != nil {
t.Fatal(err)
}
if u.ID != 0 {
t.Errorf("ID should equal 0 but got %v", u.ID)
}
if len(u.tag) != 0 {
t.Errorf("tag's length should equal 0 but got %v", len(u.tag))
}
if u.Name.(string) != "test" {
t.Errorf("Name should equal `test` but got `%v`", u.Name.(string))
}
if u.Age != 40 {
t.Errorf("Age should equal 40 but got %v", u.Age)
}
if u.Email != "test@gmail.com" {
t.Errorf("Email should equal `test@gmail.com` but got `%v`", u.Email)
}
if u.Intro != "I am an engineer!" {
t.Errorf("Intro should equal `I am an engineer!` but got `%v`", u.Intro)
}
if u.StrBool != true {
t.Errorf("strboll should equal `true`, but got `%v`", u.StrBool)
}
y, m, d := u.Date.Date()
if y != 2014 || m.String() != "November" || d != 12 {
t.Errorf("Date should equal `2014-11-12`, but got `%v`", u.Date.String())
}
}
func TestRenderForm(t *testing.T) {
type user struct {
ID int `form:"-"`
tag string `form:"tag"`
Name interface{} `form:"username"`
Age int `form:"age,text,年龄:"`
Sex string
Email []string
Intro string `form:",textarea"`
Ignored string `form:"-"`
}
u := user{Name: "test", Intro: "Some Text"}
output := RenderForm(u)
if output != template.HTML("") {
t.Errorf("output should be empty but got %v", output)
}
output = RenderForm(&u)
result := template.HTML(
`Name: <input name="username" type="text" value="test"></br>` +
`年龄:<input name="age" type="text" value="0"></br>` +
`Sex: <input name="Sex" type="text" value=""></br>` +
`Intro: <textarea name="Intro">Some Text</textarea>`)
if output != result {
t.Errorf("output should equal `%v` but got `%v`", result, output)
}
}
func TestRenderFormField(t *testing.T) {
html := renderFormField("Label: ", "Name", "text", "Value", "", "")
if html != `Label: <input name="Name" type="text" value="Value">` {
t.Errorf("Wrong html output for input[type=text]: %v ", html)
}
html = renderFormField("Label: ", "Name", "textarea", "Value", "", "")
if html != `Label: <textarea name="Name">Value</textarea>` {
t.Errorf("Wrong html output for textarea: %v ", html)
}
}
func TestParseFormTag(t *testing.T) {
// create struct to contain field with different types of struct-tag `form`
type user struct {
All int `form:"name,text,年龄:"`
NoName int `form:",hidden,年龄:"`
OnlyLabel int `form:",,年龄:"`
OnlyName int `form:"name" id:"name" class:"form-name"`
Ignored int `form:"-"`
}
objT := reflect.TypeOf(&user{}).Elem()
label, name, fType, id, class, ignored := parseFormTag(objT.Field(0))
if !(name == "name" && label == "年龄:" && fType == "text" && ignored == false) {
t.Errorf("Form Tag with name, label and type was not correctly parsed.")
}
label, name, fType, id, class, ignored = parseFormTag(objT.Field(1))
if !(name == "NoName" && label == "年龄:" && fType == "hidden" && ignored == false) {
t.Errorf("Form Tag with label and type but without name was not correctly parsed.")
}
label, name, fType, id, class, ignored = parseFormTag(objT.Field(2))
if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && ignored == false) {
t.Errorf("Form Tag containing only label was not correctly parsed.")
}
label, name, fType, id, class, ignored = parseFormTag(objT.Field(3))
if !(name == "name" && label == "OnlyName: " && fType == "text" && ignored == false &&
id == "name" && class == "form-name") {
t.Errorf("Form Tag containing only name was not correctly parsed.")
}
label, name, fType, id, class, ignored = parseFormTag(objT.Field(4))
if ignored == false {
t.Errorf("Form Tag that should be ignored was not correctly parsed.")
}
}
func TestMapGet(t *testing.T) {
// test one level map
m1 := map[string]int64{
"a": 1,
"1": 2,
}
if res, err := MapGet(m1, "a"); err == nil {
if res.(int64) != 1 {
t.Errorf("Should return 1, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
if res, err := MapGet(m1, "1"); err == nil {
if res.(int64) != 2 {
t.Errorf("Should return 2, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
if res, err := MapGet(m1, 1); err == nil {
if res.(int64) != 2 {
t.Errorf("Should return 2, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
// test 2 level map
m2 := map[string]interface{}{
"1": map[string]float64{
"2": 3.5,
},
}
if res, err := MapGet(m2, 1, 2); err == nil {
if res.(float64) != 3.5 {
t.Errorf("Should return 3.5, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
// test 5 level map
m5 := map[string]interface{}{
"1": map[string]interface{}{
"2": map[string]interface{}{
"3": map[string]interface{}{
"4": map[string]interface{}{
"5": 1.2,
},
},
},
},
}
if res, err := MapGet(m5, 1, 2, 3, 4, 5); err == nil {
if res.(float64) != 1.2 {
t.Errorf("Should return 1.2, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
// check whether element not exists in map
if res, err := MapGet(m5, 5, 4, 3, 2, 1); err == nil {
if res != nil {
t.Errorf("Should return nil, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
}

View File

@ -0,0 +1,15 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 testing

65
src/vendor/github.com/astaxie/beego/testing/client.go generated vendored Normal file
View File

@ -0,0 +1,65 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 testing
import (
"github.com/astaxie/beego/config"
"github.com/astaxie/beego/httplib"
)
var port = ""
var baseURL = "http://localhost:"
// TestHTTPRequest beego test request client
type TestHTTPRequest struct {
httplib.BeegoHTTPRequest
}
func getPort() string {
if port == "" {
config, err := config.NewConfig("ini", "../conf/app.conf")
if err != nil {
return "8080"
}
port = config.String("httpport")
return port
}
return port
}
// Get returns test client in GET method
func Get(path string) *TestHTTPRequest {
return &TestHTTPRequest{*httplib.Get(baseURL + getPort() + path)}
}
// Post returns test client in POST method
func Post(path string) *TestHTTPRequest {
return &TestHTTPRequest{*httplib.Post(baseURL + getPort() + path)}
}
// Put returns test client in PUT method
func Put(path string) *TestHTTPRequest {
return &TestHTTPRequest{*httplib.Put(baseURL + getPort() + path)}
}
// Delete returns test client in DELETE method
func Delete(path string) *TestHTTPRequest {
return &TestHTTPRequest{*httplib.Delete(baseURL + getPort() + path)}
}
// Head returns test client in HEAD method
func Head(path string) *TestHTTPRequest {
return &TestHTTPRequest{*httplib.Head(baseURL + getPort() + path)}
}

View File

@ -0,0 +1,28 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 toolbox
import (
"os"
"testing"
)
func TestProcessInput(t *testing.T) {
ProcessInput("lookup goroutine", os.Stdout)
ProcessInput("lookup heap", os.Stdout)
ProcessInput("lookup threadcreate", os.Stdout)
ProcessInput("lookup block", os.Stdout)
ProcessInput("gc summary", os.Stdout)
}

View File

@ -0,0 +1,40 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 toolbox
import (
"encoding/json"
"testing"
"time"
)
func TestStatics(t *testing.T) {
StatisticsMap.AddStatistics("POST", "/api/user", "&admin.user", time.Duration(2000))
StatisticsMap.AddStatistics("POST", "/api/user", "&admin.user", time.Duration(120000))
StatisticsMap.AddStatistics("GET", "/api/user", "&admin.user", time.Duration(13000))
StatisticsMap.AddStatistics("POST", "/api/admin", "&admin.user", time.Duration(14000))
StatisticsMap.AddStatistics("POST", "/api/user/astaxie", "&admin.user", time.Duration(12000))
StatisticsMap.AddStatistics("POST", "/api/user/xiemengjun", "&admin.user", time.Duration(13000))
StatisticsMap.AddStatistics("DELETE", "/api/user", "&admin.user", time.Duration(1400))
t.Log(StatisticsMap.GetMap())
data := StatisticsMap.GetMapData()
b, err := json.Marshal(data)
if err != nil {
t.Errorf(err.Error())
}
t.Log(string(b))
}

View File

@ -0,0 +1,63 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 toolbox
import (
"fmt"
"sync"
"testing"
"time"
)
func TestParse(t *testing.T) {
tk := NewTask("taska", "0/30 * * * * *", func() error { fmt.Println("hello world"); return nil })
err := tk.Run()
if err != nil {
t.Fatal(err)
}
AddTask("taska", tk)
StartTask()
time.Sleep(6 * time.Second)
StopTask()
}
func TestSpec(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(2)
tk1 := NewTask("tk1", "0 12 * * * *", func() error { fmt.Println("tk1"); return nil })
tk2 := NewTask("tk2", "0,10,20 * * * * *", func() error { fmt.Println("tk2"); wg.Done(); return nil })
tk3 := NewTask("tk3", "0 10 * * * *", func() error { fmt.Println("tk3"); wg.Done(); return nil })
AddTask("tk1", tk1)
AddTask("tk2", tk2)
AddTask("tk3", tk3)
StartTask()
defer StopTask()
select {
case <-time.After(200 * time.Second):
t.FailNow()
case <-wait(wg):
}
}
func wait(wg *sync.WaitGroup) chan bool {
ch := make(chan bool)
go func() {
wg.Wait()
ch <- true
}()
return ch
}

306
src/vendor/github.com/astaxie/beego/tree_test.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 beego
import (
"strings"
"testing"
"github.com/astaxie/beego/context"
)
type testinfo struct {
url string
requesturl string
params map[string]string
}
var routers []testinfo
func init() {
routers = make([]testinfo, 0)
routers = append(routers, testinfo{"/topic/?:auth:int", "/topic", nil})
routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"}})
routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"}})
routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"}})
routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"}})
routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"}})
routers = append(routers, testinfo{"/:id", "/123", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/hello/?:id", "/hello", map[string]string{":id": ""}})
routers = append(routers, testinfo{"/", "/", nil})
routers = append(routers, testinfo{"/customer/login", "/customer/login", nil})
routers = append(routers, testinfo{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}})
routers = append(routers, testinfo{"/*", "/customer/123", map[string]string{":splat": "customer/123"}})
routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}})
routers = append(routers, testinfo{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}})
routers = append(routers, testinfo{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}})
routers = append(routers, testinfo{"/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"}})
routers = append(routers, testinfo{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}})
routers = append(routers, testinfo{"/thumbnail/:size/uploads/*",
"/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg",
map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"}})
routers = append(routers, testinfo{"/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"}})
routers = append(routers, testinfo{"/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}})
routers = append(routers, testinfo{"/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}})
routers = append(routers, testinfo{"/dl/:width:int/:height:int/*.*",
"/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg",
map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}})
routers = append(routers, testinfo{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}})
routers = append(routers, testinfo{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}})
routers = append(routers, testinfo{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}})
routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}})
routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}})
routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}})
routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
routers = append(routers, testinfo{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}})
routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}})
}
func TestTreeRouters(t *testing.T) {
for _, r := range routers {
tr := NewTree()
tr.AddRouter(r.url, "astaxie")
ctx := context.NewContext()
obj := tr.Match(r.requesturl, ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal(r.url+" can't get obj, Expect ", r.requesturl)
}
if r.params != nil {
for k, v := range r.params {
if vv := ctx.Input.Param(k); vv != v {
t.Fatal("The Rule: " + r.url + "\nThe RequestURL:" + r.requesturl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv)
} else if vv == "" && v != "" {
t.Fatal(r.url + " " + r.requesturl + " get param empty:" + k)
}
}
}
}
}
func TestStaticPath(t *testing.T) {
tr := NewTree()
tr.AddRouter("/topic/:id", "wildcard")
tr.AddRouter("/topic", "static")
ctx := context.NewContext()
obj := tr.Match("/topic", ctx)
if obj == nil || obj.(string) != "static" {
t.Fatal("/topic is a static route")
}
obj = tr.Match("/topic/1", ctx)
if obj == nil || obj.(string) != "wildcard" {
t.Fatal("/topic/1 is a wildcard route")
}
}
func TestAddTree(t *testing.T) {
tr := NewTree()
tr.AddRouter("/shop/:id/account", "astaxie")
tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie")
t1 := NewTree()
t1.AddTree("/v1/zl", tr)
ctx := context.NewContext()
obj := t1.Match("/v1/zl/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/v1/zl/shop/:id/account can't get obj ")
}
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if ctx.Input.Param(":id") != "123" {
t.Fatal("get :id param error")
}
ctx.Input.Reset(ctx)
obj = t1.Match("/v1/zl/shop/123/ttt_1_12.html", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/v1/zl//shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ")
}
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" {
t.Fatal("get :sd :id :page param error")
}
t2 := NewTree()
t2.AddTree("/v1/:shopid", tr)
ctx.Input.Reset(ctx)
obj = t2.Match("/v1/zl/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/v1/:shopid/shop/:id/account can't get obj ")
}
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":shopid") != "zl" {
t.Fatal("get :id :shopid param error")
}
ctx.Input.Reset(ctx)
obj = t2.Match("/v1/zl/shop/123/ttt_1_12.html", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/v1/:shopid/shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ")
}
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get :shopid param error")
}
if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" || ctx.Input.Param(":shopid") != "zl" {
t.Fatal("get :sd :id :page :shopid param error")
}
}
func TestAddTree2(t *testing.T) {
tr := NewTree()
tr.AddRouter("/shop/:id/account", "astaxie")
tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie")
t3 := NewTree()
t3.AddTree("/:version(v1|v2)/:prefix", tr)
ctx := context.NewContext()
obj := t3.Match("/v1/zl/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/:version(v1|v2)/:prefix/shop/:id/account can't get obj ")
}
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":prefix") != "zl" || ctx.Input.Param(":version") != "v1" {
t.Fatal("get :id :prefix :version param error")
}
}
func TestAddTree3(t *testing.T) {
tr := NewTree()
tr.AddRouter("/create", "astaxie")
tr.AddRouter("/shop/:sd/account", "astaxie")
t3 := NewTree()
t3.AddTree("/table/:num", tr)
ctx := context.NewContext()
obj := t3.Match("/table/123/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/table/:num/shop/:sd/account can't get obj ")
}
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if ctx.Input.Param(":num") != "123" || ctx.Input.Param(":sd") != "123" {
t.Fatal("get :num :sd param error")
}
ctx.Input.Reset(ctx)
obj = t3.Match("/table/123/create", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/table/:num/create can't get obj ")
}
}
func TestAddTree4(t *testing.T) {
tr := NewTree()
tr.AddRouter("/create", "astaxie")
tr.AddRouter("/shop/:sd/:account", "astaxie")
t4 := NewTree()
t4.AddTree("/:info:int/:num/:id", tr)
ctx := context.NewContext()
obj := t4.Match("/12/123/456/shop/123/account", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/:info:int/:num/:id/shop/:sd/:account can't get obj ")
}
if ctx.Input.ParamsLen() == 0 {
t.Fatal("get param error")
}
if ctx.Input.Param(":info") != "12" || ctx.Input.Param(":num") != "123" ||
ctx.Input.Param(":id") != "456" || ctx.Input.Param(":sd") != "123" ||
ctx.Input.Param(":account") != "account" {
t.Fatal("get :info :num :id :sd :account param error")
}
ctx.Input.Reset(ctx)
obj = t4.Match("/12/123/456/create", ctx)
if obj == nil || obj.(string) != "astaxie" {
t.Fatal("/:info:int/:num/:id/create can't get obj ")
}
}
// Test for issue #1595
func TestAddTree5(t *testing.T) {
tr := NewTree()
tr.AddRouter("/v1/shop/:id", "shopdetail")
tr.AddRouter("/v1/shop/", "shophome")
ctx := context.NewContext()
obj := tr.Match("/v1/shop/", ctx)
if obj == nil || obj.(string) != "shophome" {
t.Fatal("url /v1/shop/ need match router /v1/shop/ ")
}
}
func TestSplitPath(t *testing.T) {
a := splitPath("")
if len(a) != 0 {
t.Fatal("/ should retrun []")
}
a = splitPath("/")
if len(a) != 0 {
t.Fatal("/ should retrun []")
}
a = splitPath("/admin")
if len(a) != 1 || a[0] != "admin" {
t.Fatal("/admin should retrun [admin]")
}
a = splitPath("/admin/")
if len(a) != 1 || a[0] != "admin" {
t.Fatal("/admin/ should retrun [admin]")
}
a = splitPath("/admin/users")
if len(a) != 2 || a[0] != "admin" || a[1] != "users" {
t.Fatal("/admin should retrun [admin users]")
}
a = splitPath("/admin/:id:int")
if len(a) != 2 || a[0] != "admin" || a[1] != ":id:int" {
t.Fatal("/admin should retrun [admin :id:int]")
}
}
func TestSplitSegment(t *testing.T) {
items := map[string]struct {
isReg bool
params []string
regStr string
}{
"admin": {false, nil, ""},
"*": {true, []string{":splat"}, ""},
"*.*": {true, []string{".", ":path", ":ext"}, ""},
":id": {true, []string{":id"}, ""},
"?:id": {true, []string{":", ":id"}, ""},
":id:int": {true, []string{":id"}, "([0-9]+)"},
":name:string": {true, []string{":name"}, `([\w]+)`},
":id([0-9]+)": {true, []string{":id"}, `([0-9]+)`},
":id([0-9]+)_:name": {true, []string{":id", ":name"}, `([0-9]+)_(.+)`},
":id(.+)_cms.html": {true, []string{":id"}, `(.+)_cms.html`},
"cms_:id(.+)_:page(.+).html": {true, []string{":id", ":page"}, `cms_(.+)_(.+).html`},
`:app(a|b|c)`: {true, []string{":app"}, `(a|b|c)`},
`:app\((a|b|c)\)`: {true, []string{":app"}, `(.+)\((a|b|c)\)`},
}
for pattern, v := range items {
b, w, r := splitSegment(pattern)
if b != v.isReg || r != v.regStr || strings.Join(w, ",") != strings.Join(v.params, ",") {
t.Fatalf("%s should return %t,%s,%q, got %t,%s,%q", pattern, v.isReg, v.params, v.regStr, b, w, r)
}
}
}

View File

@ -0,0 +1,28 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 utils
import (
"strings"
"testing"
)
func TestGetFuncName(t *testing.T) {
name := GetFuncName(TestGetFuncName)
t.Log(name)
if !strings.HasSuffix(name, ".TestGetFuncName") {
t.Error("get func name error")
}
}

View File

@ -0,0 +1,19 @@
Copyright (c) 2011-2014 Dmitry Chestnykh <dmitry@codingrobots.com>
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.

View File

@ -0,0 +1,45 @@
# Captcha
an example for use captcha
```
package controllers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/cache"
"github.com/astaxie/beego/utils/captcha"
)
var cpt *captcha.Captcha
func init() {
// use beego cache system store the captcha data
store := cache.NewMemoryCache()
cpt = captcha.NewWithFilter("/captcha/", store)
}
type MainController struct {
beego.Controller
}
func (this *MainController) Get() {
this.TplName = "index.tpl"
}
func (this *MainController) Post() {
this.TplName = "index.tpl"
this.Data["Success"] = cpt.VerifyReq(this.Ctx.Request)
}
```
template usage
```
{{.Success}}
<form action="/" method="post">
{{create_captcha}}
<input name="captcha" type="text">
</form>
```

View File

@ -0,0 +1,269 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 captcha implements generation and verification of image CAPTCHAs.
// an example for use captcha
//
// ```
// package controllers
//
// import (
// "github.com/astaxie/beego"
// "github.com/astaxie/beego/cache"
// "github.com/astaxie/beego/utils/captcha"
// )
//
// var cpt *captcha.Captcha
//
// func init() {
// // use beego cache system store the captcha data
// store := cache.NewMemoryCache()
// cpt = captcha.NewWithFilter("/captcha/", store)
// }
//
// type MainController struct {
// beego.Controller
// }
//
// func (this *MainController) Get() {
// this.TplName = "index.tpl"
// }
//
// func (this *MainController) Post() {
// this.TplName = "index.tpl"
//
// this.Data["Success"] = cpt.VerifyReq(this.Ctx.Request)
// }
// ```
//
// template usage
//
// ```
// {{.Success}}
// <form action="/" method="post">
// {{create_captcha}}
// <input name="captcha" type="text">
// </form>
// ```
package captcha
import (
"fmt"
"html/template"
"net/http"
"path"
"strings"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/cache"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/utils"
)
var (
defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
)
const (
// default captcha attributes
challengeNums = 6
expiration = 600 * time.Second
fieldIDName = "captcha_id"
fieldCaptchaName = "captcha"
cachePrefix = "captcha_"
defaultURLPrefix = "/captcha/"
)
// Captcha struct
type Captcha struct {
// beego cache store
store cache.Cache
// url prefix for captcha image
URLPrefix string
// specify captcha id input field name
FieldIDName string
// specify captcha result input field name
FieldCaptchaName string
// captcha image width and height
StdWidth int
StdHeight int
// captcha chars nums
ChallengeNums int
// captcha expiration seconds
Expiration time.Duration
// cache key prefix
CachePrefix string
}
// generate key string
func (c *Captcha) key(id string) string {
return c.CachePrefix + id
}
// generate rand chars with default chars
func (c *Captcha) genRandChars() []byte {
return utils.RandomCreateBytes(c.ChallengeNums, defaultChars...)
}
// Handler beego filter handler for serve captcha image
func (c *Captcha) Handler(ctx *context.Context) {
var chars []byte
id := path.Base(ctx.Request.RequestURI)
if i := strings.Index(id, "."); i != -1 {
id = id[:i]
}
key := c.key(id)
if len(ctx.Input.Query("reload")) > 0 {
chars = c.genRandChars()
if err := c.store.Put(key, chars, c.Expiration); err != nil {
ctx.Output.SetStatus(500)
ctx.WriteString("captcha reload error")
beego.Error("Reload Create Captcha Error:", err)
return
}
} else {
if v, ok := c.store.Get(key).([]byte); ok {
chars = v
} else {
ctx.Output.SetStatus(404)
ctx.WriteString("captcha not found")
return
}
}
img := NewImage(chars, c.StdWidth, c.StdHeight)
if _, err := img.WriteTo(ctx.ResponseWriter); err != nil {
beego.Error("Write Captcha Image Error:", err)
}
}
// CreateCaptchaHTML template func for output html
func (c *Captcha) CreateCaptchaHTML() template.HTML {
value, err := c.CreateCaptcha()
if err != nil {
beego.Error("Create Captcha Error:", err)
return ""
}
// create html
return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`+
`<a class="captcha" href="javascript:">`+
`<img onclick="this.src=('%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s.png">`+
`</a>`, c.FieldIDName, value, c.URLPrefix, value, c.URLPrefix, value))
}
// CreateCaptcha create a new captcha id
func (c *Captcha) CreateCaptcha() (string, error) {
// generate captcha id
id := string(utils.RandomCreateBytes(15))
// get the captcha chars
chars := c.genRandChars()
// save to store
if err := c.store.Put(c.key(id), chars, c.Expiration); err != nil {
return "", err
}
return id, nil
}
// VerifyReq verify from a request
func (c *Captcha) VerifyReq(req *http.Request) bool {
req.ParseForm()
return c.Verify(req.Form.Get(c.FieldIDName), req.Form.Get(c.FieldCaptchaName))
}
// Verify direct verify id and challenge string
func (c *Captcha) Verify(id string, challenge string) (success bool) {
if len(challenge) == 0 || len(id) == 0 {
return
}
var chars []byte
key := c.key(id)
if v, ok := c.store.Get(key).([]byte); ok {
chars = v
} else {
return
}
defer func() {
// finally remove it
c.store.Delete(key)
}()
if len(chars) != len(challenge) {
return
}
// verify challenge
for i, c := range chars {
if c != challenge[i]-48 {
return
}
}
return true
}
// NewCaptcha create a new captcha.Captcha
func NewCaptcha(urlPrefix string, store cache.Cache) *Captcha {
cpt := &Captcha{}
cpt.store = store
cpt.FieldIDName = fieldIDName
cpt.FieldCaptchaName = fieldCaptchaName
cpt.ChallengeNums = challengeNums
cpt.Expiration = expiration
cpt.CachePrefix = cachePrefix
cpt.StdWidth = stdWidth
cpt.StdHeight = stdHeight
if len(urlPrefix) == 0 {
urlPrefix = defaultURLPrefix
}
if urlPrefix[len(urlPrefix)-1] != '/' {
urlPrefix += "/"
}
cpt.URLPrefix = urlPrefix
return cpt
}
// NewWithFilter create a new captcha.Captcha and auto AddFilter for serve captacha image
// and add a template func for output html
func NewWithFilter(urlPrefix string, store cache.Cache) *Captcha {
cpt := NewCaptcha(urlPrefix, store)
// create filter for serve captcha image
beego.InsertFilter(cpt.URLPrefix+"*", beego.BeforeRouter, cpt.Handler)
// add to template func map
beego.AddFuncMap("create_captcha", cpt.CreateCaptchaHTML)
return cpt
}

View File

@ -0,0 +1,498 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 captcha
import (
"bytes"
"image"
"image/color"
"image/png"
"io"
"math"
)
const (
fontWidth = 11
fontHeight = 18
blackChar = 1
// Standard width and height of a captcha image.
stdWidth = 240
stdHeight = 80
// Maximum absolute skew factor of a single digit.
maxSkew = 0.7
// Number of background circles.
circleCount = 20
)
var font = [][]byte{
{ // 0
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1,
0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
},
{ // 1
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0,
0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
},
{ // 2
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
},
{ // 3
0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
},
{ // 4
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0,
0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0,
1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
},
{ // 5
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
},
{ // 6
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0,
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0,
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
},
{ // 7
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
},
{ // 8
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1,
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0,
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
},
{ // 9
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0,
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1,
0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
},
}
// Image struct
type Image struct {
*image.Paletted
numWidth int
numHeight int
dotSize int
}
var prng = &siprng{}
// randIntn returns a pseudorandom non-negative int in range [0, n).
func randIntn(n int) int {
return prng.Intn(n)
}
// randInt returns a pseudorandom int in range [from, to].
func randInt(from, to int) int {
return prng.Intn(to+1-from) + from
}
// randFloat returns a pseudorandom float64 in range [from, to].
func randFloat(from, to float64) float64 {
return (to-from)*prng.Float64() + from
}
func randomPalette() color.Palette {
p := make([]color.Color, circleCount+1)
// Transparent color.
p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00}
// Primary color.
prim := color.RGBA{
uint8(randIntn(129)),
uint8(randIntn(129)),
uint8(randIntn(129)),
0xFF,
}
p[1] = prim
// Circle colors.
for i := 2; i <= circleCount; i++ {
p[i] = randomBrightness(prim, 255)
}
return p
}
// NewImage returns a new captcha image of the given width and height with the
// given digits, where each digit must be in range 0-9.
func NewImage(digits []byte, width, height int) *Image {
m := new(Image)
m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette())
m.calculateSizes(width, height, len(digits))
// Randomly position captcha inside the image.
maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize
maxy := height - m.numHeight - m.dotSize*2
var border int
if width > height {
border = height / 5
} else {
border = width / 5
}
x := randInt(border, maxx-border)
y := randInt(border, maxy-border)
// Draw digits.
for _, n := range digits {
m.drawDigit(font[n], x, y)
x += m.numWidth + m.dotSize
}
// Draw strike-through line.
m.strikeThrough()
// Apply wave distortion.
m.distort(randFloat(5, 10), randFloat(100, 200))
// Fill image with random circles.
m.fillWithCircles(circleCount, m.dotSize)
return m
}
// encodedPNG encodes an image to PNG and returns
// the result as a byte slice.
func (m *Image) encodedPNG() []byte {
var buf bytes.Buffer
if err := png.Encode(&buf, m.Paletted); err != nil {
panic(err.Error())
}
return buf.Bytes()
}
// WriteTo writes captcha image in PNG format into the given writer.
func (m *Image) WriteTo(w io.Writer) (int64, error) {
n, err := w.Write(m.encodedPNG())
return int64(n), err
}
func (m *Image) calculateSizes(width, height, ncount int) {
// Goal: fit all digits inside the image.
var border int
if width > height {
border = height / 4
} else {
border = width / 4
}
// Convert everything to floats for calculations.
w := float64(width - border*2)
h := float64(height - border*2)
// fw takes into account 1-dot spacing between digits.
fw := float64(fontWidth + 1)
fh := float64(fontHeight)
nc := float64(ncount)
// Calculate the width of a single digit taking into account only the
// width of the image.
nw := w / nc
// Calculate the height of a digit from this width.
nh := nw * fh / fw
// Digit too high?
if nh > h {
// Fit digits based on height.
nh = h
nw = fw / fh * nh
}
// Calculate dot size.
m.dotSize = int(nh / fh)
// Save everything, making the actual width smaller by 1 dot to account
// for spacing between digits.
m.numWidth = int(nw) - m.dotSize
m.numHeight = int(nh)
}
func (m *Image) drawHorizLine(fromX, toX, y int, colorIdx uint8) {
for x := fromX; x <= toX; x++ {
m.SetColorIndex(x, y, colorIdx)
}
}
func (m *Image) drawCircle(x, y, radius int, colorIdx uint8) {
f := 1 - radius
dfx := 1
dfy := -2 * radius
xo := 0
yo := radius
m.SetColorIndex(x, y+radius, colorIdx)
m.SetColorIndex(x, y-radius, colorIdx)
m.drawHorizLine(x-radius, x+radius, y, colorIdx)
for xo < yo {
if f >= 0 {
yo--
dfy += 2
f += dfy
}
xo++
dfx += 2
f += dfx
m.drawHorizLine(x-xo, x+xo, y+yo, colorIdx)
m.drawHorizLine(x-xo, x+xo, y-yo, colorIdx)
m.drawHorizLine(x-yo, x+yo, y+xo, colorIdx)
m.drawHorizLine(x-yo, x+yo, y-xo, colorIdx)
}
}
func (m *Image) fillWithCircles(n, maxradius int) {
maxx := m.Bounds().Max.X
maxy := m.Bounds().Max.Y
for i := 0; i < n; i++ {
colorIdx := uint8(randInt(1, circleCount-1))
r := randInt(1, maxradius)
m.drawCircle(randInt(r, maxx-r), randInt(r, maxy-r), r, colorIdx)
}
}
func (m *Image) strikeThrough() {
maxx := m.Bounds().Max.X
maxy := m.Bounds().Max.Y
y := randInt(maxy/3, maxy-maxy/3)
amplitude := randFloat(5, 20)
period := randFloat(80, 180)
dx := 2.0 * math.Pi / period
for x := 0; x < maxx; x++ {
xo := amplitude * math.Cos(float64(y)*dx)
yo := amplitude * math.Sin(float64(x)*dx)
for yn := 0; yn < m.dotSize; yn++ {
r := randInt(0, m.dotSize)
m.drawCircle(x+int(xo), y+int(yo)+(yn*m.dotSize), r/2, 1)
}
}
}
func (m *Image) drawDigit(digit []byte, x, y int) {
skf := randFloat(-maxSkew, maxSkew)
xs := float64(x)
r := m.dotSize / 2
y += randInt(-r, r)
for yo := 0; yo < fontHeight; yo++ {
for xo := 0; xo < fontWidth; xo++ {
if digit[yo*fontWidth+xo] != blackChar {
continue
}
m.drawCircle(x+xo*m.dotSize, y+yo*m.dotSize, r, 1)
}
xs += skf
x = int(xs)
}
}
func (m *Image) distort(amplude float64, period float64) {
w := m.Bounds().Max.X
h := m.Bounds().Max.Y
oldm := m.Paletted
newm := image.NewPaletted(image.Rect(0, 0, w, h), oldm.Palette)
dx := 2.0 * math.Pi / period
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
xo := amplude * math.Sin(float64(y)*dx)
yo := amplude * math.Cos(float64(x)*dx)
newm.SetColorIndex(x, y, oldm.ColorIndexAt(x+int(xo), y+int(yo)))
}
}
m.Paletted = newm
}
func randomBrightness(c color.RGBA, max uint8) color.RGBA {
minc := min3(c.R, c.G, c.B)
maxc := max3(c.R, c.G, c.B)
if maxc > max {
return c
}
n := randIntn(int(max-maxc)) - int(minc)
return color.RGBA{
uint8(int(c.R) + n),
uint8(int(c.G) + n),
uint8(int(c.B) + n),
uint8(c.A),
}
}
func min3(x, y, z uint8) (m uint8) {
m = x
if y < m {
m = y
}
if z < m {
m = z
}
return
}
func max3(x, y, z uint8) (m uint8) {
m = x
if y > m {
m = y
}
if z > m {
m = z
}
return
}

View File

@ -0,0 +1,52 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 captcha
import (
"testing"
"github.com/astaxie/beego/utils"
)
type byteCounter struct {
n int64
}
func (bc *byteCounter) Write(b []byte) (int, error) {
bc.n += int64(len(b))
return len(b), nil
}
func BenchmarkNewImage(b *testing.B) {
b.StopTimer()
d := utils.RandomCreateBytes(challengeNums, defaultChars...)
b.StartTimer()
for i := 0; i < b.N; i++ {
NewImage(d, stdWidth, stdHeight)
}
}
func BenchmarkImageWriteTo(b *testing.B) {
b.StopTimer()
d := utils.RandomCreateBytes(challengeNums, defaultChars...)
b.StartTimer()
counter := &byteCounter{}
for i := 0; i < b.N; i++ {
img := NewImage(d, stdWidth, stdHeight)
img.WriteTo(counter)
b.SetBytes(counter.n)
counter.n = 0
}
}

View File

@ -0,0 +1,277 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 captcha
import (
"crypto/rand"
"encoding/binary"
"io"
"sync"
)
// siprng is PRNG based on SipHash-2-4.
type siprng struct {
mu sync.Mutex
k0, k1, ctr uint64
}
// siphash implements SipHash-2-4, accepting a uint64 as a message.
func siphash(k0, k1, m uint64) uint64 {
// Initialization.
v0 := k0 ^ 0x736f6d6570736575
v1 := k1 ^ 0x646f72616e646f6d
v2 := k0 ^ 0x6c7967656e657261
v3 := k1 ^ 0x7465646279746573
t := uint64(8) << 56
// Compression.
v3 ^= m
// Round 1.
v0 += v1
v1 = v1<<13 | v1>>(64-13)
v1 ^= v0
v0 = v0<<32 | v0>>(64-32)
v2 += v3
v3 = v3<<16 | v3>>(64-16)
v3 ^= v2
v0 += v3
v3 = v3<<21 | v3>>(64-21)
v3 ^= v0
v2 += v1
v1 = v1<<17 | v1>>(64-17)
v1 ^= v2
v2 = v2<<32 | v2>>(64-32)
// Round 2.
v0 += v1
v1 = v1<<13 | v1>>(64-13)
v1 ^= v0
v0 = v0<<32 | v0>>(64-32)
v2 += v3
v3 = v3<<16 | v3>>(64-16)
v3 ^= v2
v0 += v3
v3 = v3<<21 | v3>>(64-21)
v3 ^= v0
v2 += v1
v1 = v1<<17 | v1>>(64-17)
v1 ^= v2
v2 = v2<<32 | v2>>(64-32)
v0 ^= m
// Compress last block.
v3 ^= t
// Round 1.
v0 += v1
v1 = v1<<13 | v1>>(64-13)
v1 ^= v0
v0 = v0<<32 | v0>>(64-32)
v2 += v3
v3 = v3<<16 | v3>>(64-16)
v3 ^= v2
v0 += v3
v3 = v3<<21 | v3>>(64-21)
v3 ^= v0
v2 += v1
v1 = v1<<17 | v1>>(64-17)
v1 ^= v2
v2 = v2<<32 | v2>>(64-32)
// Round 2.
v0 += v1
v1 = v1<<13 | v1>>(64-13)
v1 ^= v0
v0 = v0<<32 | v0>>(64-32)
v2 += v3
v3 = v3<<16 | v3>>(64-16)
v3 ^= v2
v0 += v3
v3 = v3<<21 | v3>>(64-21)
v3 ^= v0
v2 += v1
v1 = v1<<17 | v1>>(64-17)
v1 ^= v2
v2 = v2<<32 | v2>>(64-32)
v0 ^= t
// Finalization.
v2 ^= 0xff
// Round 1.
v0 += v1
v1 = v1<<13 | v1>>(64-13)
v1 ^= v0
v0 = v0<<32 | v0>>(64-32)
v2 += v3
v3 = v3<<16 | v3>>(64-16)
v3 ^= v2
v0 += v3
v3 = v3<<21 | v3>>(64-21)
v3 ^= v0
v2 += v1
v1 = v1<<17 | v1>>(64-17)
v1 ^= v2
v2 = v2<<32 | v2>>(64-32)
// Round 2.
v0 += v1
v1 = v1<<13 | v1>>(64-13)
v1 ^= v0
v0 = v0<<32 | v0>>(64-32)
v2 += v3
v3 = v3<<16 | v3>>(64-16)
v3 ^= v2
v0 += v3
v3 = v3<<21 | v3>>(64-21)
v3 ^= v0
v2 += v1
v1 = v1<<17 | v1>>(64-17)
v1 ^= v2
v2 = v2<<32 | v2>>(64-32)
// Round 3.
v0 += v1
v1 = v1<<13 | v1>>(64-13)
v1 ^= v0
v0 = v0<<32 | v0>>(64-32)
v2 += v3
v3 = v3<<16 | v3>>(64-16)
v3 ^= v2
v0 += v3
v3 = v3<<21 | v3>>(64-21)
v3 ^= v0
v2 += v1
v1 = v1<<17 | v1>>(64-17)
v1 ^= v2
v2 = v2<<32 | v2>>(64-32)
// Round 4.
v0 += v1
v1 = v1<<13 | v1>>(64-13)
v1 ^= v0
v0 = v0<<32 | v0>>(64-32)
v2 += v3
v3 = v3<<16 | v3>>(64-16)
v3 ^= v2
v0 += v3
v3 = v3<<21 | v3>>(64-21)
v3 ^= v0
v2 += v1
v1 = v1<<17 | v1>>(64-17)
v1 ^= v2
v2 = v2<<32 | v2>>(64-32)
return v0 ^ v1 ^ v2 ^ v3
}
// rekey sets a new PRNG key, which is read from crypto/rand.
func (p *siprng) rekey() {
var k [16]byte
if _, err := io.ReadFull(rand.Reader, k[:]); err != nil {
panic(err.Error())
}
p.k0 = binary.LittleEndian.Uint64(k[0:8])
p.k1 = binary.LittleEndian.Uint64(k[8:16])
p.ctr = 1
}
// Uint64 returns a new pseudorandom uint64.
// It rekeys PRNG on the first call and every 64 MB of generated data.
func (p *siprng) Uint64() uint64 {
p.mu.Lock()
if p.ctr == 0 || p.ctr > 8*1024*1024 {
p.rekey()
}
v := siphash(p.k0, p.k1, p.ctr)
p.ctr++
p.mu.Unlock()
return v
}
func (p *siprng) Int63() int64 {
return int64(p.Uint64() & 0x7fffffffffffffff)
}
func (p *siprng) Uint32() uint32 {
return uint32(p.Uint64())
}
func (p *siprng) Int31() int32 {
return int32(p.Uint32() & 0x7fffffff)
}
func (p *siprng) Intn(n int) int {
if n <= 0 {
panic("invalid argument to Intn")
}
if n <= 1<<31-1 {
return int(p.Int31n(int32(n)))
}
return int(p.Int63n(int64(n)))
}
func (p *siprng) Int63n(n int64) int64 {
if n <= 0 {
panic("invalid argument to Int63n")
}
max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
v := p.Int63()
for v > max {
v = p.Int63()
}
return v % n
}
func (p *siprng) Int31n(n int32) int32 {
if n <= 0 {
panic("invalid argument to Int31n")
}
max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
v := p.Int31()
for v > max {
v = p.Int31()
}
return v % n
}
func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) }

View File

@ -0,0 +1,33 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 captcha
import "testing"
func TestSiphash(t *testing.T) {
good := uint64(0xe849e8bb6ffe2567)
cur := siphash(0, 0, 0)
if cur != good {
t.Fatalf("siphash: expected %x, got %x", good, cur)
}
}
func BenchmarkSiprng(b *testing.B) {
b.SetBytes(8)
p := &siprng{}
for i := 0; i < b.N; i++ {
p.Uint64()
}
}

View File

@ -0,0 +1,46 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 utils
import (
"testing"
)
type mytype struct {
next *mytype
prev *mytype
}
func TestPrint(t *testing.T) {
Display("v1", 1, "v2", 2, "v3", 3)
}
func TestPrintPoint(t *testing.T) {
var v1 = new(mytype)
var v2 = new(mytype)
v1.prev = nil
v1.next = v2
v2.prev = v1
v2.next = nil
Display("v1", v1, "v2", v2)
}
func TestPrintString(t *testing.T) {
str := GetDisplayString("v1", 1, "v2", 2)
println(str)
}

75
src/vendor/github.com/astaxie/beego/utils/file_test.go generated vendored Normal file
View File

@ -0,0 +1,75 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 utils
import (
"path/filepath"
"reflect"
"testing"
)
var noExistedFile = "/tmp/not_existed_file"
func TestSelfPath(t *testing.T) {
path := SelfPath()
if path == "" {
t.Error("path cannot be empty")
}
t.Logf("SelfPath: %s", path)
}
func TestSelfDir(t *testing.T) {
dir := SelfDir()
t.Logf("SelfDir: %s", dir)
}
func TestFileExists(t *testing.T) {
if !FileExists("./file.go") {
t.Errorf("./file.go should exists, but it didn't")
}
if FileExists(noExistedFile) {
t.Errorf("Wierd, how could this file exists: %s", noExistedFile)
}
}
func TestSearchFile(t *testing.T) {
path, err := SearchFile(filepath.Base(SelfPath()), SelfDir())
if err != nil {
t.Error(err)
}
t.Log(path)
path, err = SearchFile(noExistedFile, ".")
if err == nil {
t.Errorf("err shouldnot be nil, got path: %s", SelfDir())
}
}
func TestGrepFile(t *testing.T) {
_, err := GrepFile("", noExistedFile)
if err == nil {
t.Error("expect file-not-existed error, but got nothing")
}
path := filepath.Join(".", "testdata", "grepe.test")
lines, err := GrepFile(`^\s*[^#]+`, path)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(lines, []string{"hello", "world"}) {
t.Errorf("expect [hello world], but receive %v", lines)
}
}

41
src/vendor/github.com/astaxie/beego/utils/mail_test.go generated vendored Normal file
View File

@ -0,0 +1,41 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 utils
import "testing"
func TestMail(t *testing.T) {
config := `{"username":"astaxie@gmail.com","password":"astaxie","host":"smtp.gmail.com","port":587}`
mail := NewEMail(config)
if mail.Username != "astaxie@gmail.com" {
t.Fatal("email parse get username error")
}
if mail.Password != "astaxie" {
t.Fatal("email parse get password error")
}
if mail.Host != "smtp.gmail.com" {
t.Fatal("email parse get host error")
}
if mail.Port != 587 {
t.Fatal("email parse get port error")
}
mail.To = []string{"xiemengjun@gmail.com"}
mail.From = "astaxie@gmail.com"
mail.Subject = "hi, just from beego!"
mail.Text = "Text Body is, of course, supported!"
mail.HTML = "<h1>Fancy Html is supported, too!</h1>"
mail.AttachFile("/Users/astaxie/github/beego/beego.go")
mail.Send()
}

View File

@ -0,0 +1,26 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 pagination
import (
"github.com/astaxie/beego/context"
)
// SetPaginator Instantiates a Paginator and assigns it to context.Input.Data["paginator"].
func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) {
paginator = NewPaginator(context.Request, per, nums)
context.Input.SetData("paginator", &paginator)
return
}

View File

@ -0,0 +1,58 @@
/*
Package pagination provides utilities to setup a paginator within the
context of a http request.
Usage
In your beego.Controller:
package controllers
import "github.com/astaxie/beego/utils/pagination"
type PostsController struct {
beego.Controller
}
func (this *PostsController) ListAllPosts() {
// sets this.Data["paginator"] with the current offset (from the url query param)
postsPerPage := 20
paginator := pagination.SetPaginator(this.Ctx, postsPerPage, CountPosts())
// fetch the next 20 posts
this.Data["posts"] = ListPostsByOffsetAndLimit(paginator.Offset(), postsPerPage)
}
In your view templates:
{{if .paginator.HasPages}}
<ul class="pagination pagination">
{{if .paginator.HasPrev}}
<li><a href="{{.paginator.PageLinkFirst}}">{{ i18n .Lang "paginator.first_page"}}</a></li>
<li><a href="{{.paginator.PageLinkPrev}}">&laquo;</a></li>
{{else}}
<li class="disabled"><a>{{ i18n .Lang "paginator.first_page"}}</a></li>
<li class="disabled"><a>&laquo;</a></li>
{{end}}
{{range $index, $page := .paginator.Pages}}
<li{{if $.paginator.IsActive .}} class="active"{{end}}>
<a href="{{$.paginator.PageLink $page}}">{{$page}}</a>
</li>
{{end}}
{{if .paginator.HasNext}}
<li><a href="{{.paginator.PageLinkNext}}">&raquo;</a></li>
<li><a href="{{.paginator.PageLinkLast}}">{{ i18n .Lang "paginator.last_page"}}</a></li>
{{else}}
<li class="disabled"><a>&raquo;</a></li>
<li class="disabled"><a>{{ i18n .Lang "paginator.last_page"}}</a></li>
{{end}}
</ul>
{{end}}
See also
http://beego.me/docs/mvc/view/page.md
*/
package pagination

View File

@ -0,0 +1,189 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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 pagination
import (
"math"
"net/http"
"net/url"
"strconv"
)
// Paginator within the state of a http request.
type Paginator struct {
Request *http.Request
PerPageNums int
MaxPages int
nums int64
pageRange []int
pageNums int
page int
}
// PageNums Returns the total number of pages.
func (p *Paginator) PageNums() int {
if p.pageNums != 0 {
return p.pageNums
}
pageNums := math.Ceil(float64(p.nums) / float64(p.PerPageNums))
if p.MaxPages > 0 {
pageNums = math.Min(pageNums, float64(p.MaxPages))
}
p.pageNums = int(pageNums)
return p.pageNums
}
// Nums Returns the total number of items (e.g. from doing SQL count).
func (p *Paginator) Nums() int64 {
return p.nums
}
// SetNums Sets the total number of items.
func (p *Paginator) SetNums(nums interface{}) {
p.nums, _ = toInt64(nums)
}
// Page Returns the current page.
func (p *Paginator) Page() int {
if p.page != 0 {
return p.page
}
if p.Request.Form == nil {
p.Request.ParseForm()
}
p.page, _ = strconv.Atoi(p.Request.Form.Get("p"))
if p.page > p.PageNums() {
p.page = p.PageNums()
}
if p.page <= 0 {
p.page = 1
}
return p.page
}
// Pages Returns a list of all pages.
//
// Usage (in a view template):
//
// {{range $index, $page := .paginator.Pages}}
// <li{{if $.paginator.IsActive .}} class="active"{{end}}>
// <a href="{{$.paginator.PageLink $page}}">{{$page}}</a>
// </li>
// {{end}}
func (p *Paginator) Pages() []int {
if p.pageRange == nil && p.nums > 0 {
var pages []int
pageNums := p.PageNums()
page := p.Page()
switch {
case page >= pageNums-4 && pageNums > 9:
start := pageNums - 9 + 1
pages = make([]int, 9)
for i := range pages {
pages[i] = start + i
}
case page >= 5 && pageNums > 9:
start := page - 5 + 1
pages = make([]int, int(math.Min(9, float64(page+4+1))))
for i := range pages {
pages[i] = start + i
}
default:
pages = make([]int, int(math.Min(9, float64(pageNums))))
for i := range pages {
pages[i] = i + 1
}
}
p.pageRange = pages
}
return p.pageRange
}
// PageLink Returns URL for a given page index.
func (p *Paginator) PageLink(page int) string {
link, _ := url.ParseRequestURI(p.Request.URL.String())
values := link.Query()
if page == 1 {
values.Del("p")
} else {
values.Set("p", strconv.Itoa(page))
}
link.RawQuery = values.Encode()
return link.String()
}
// PageLinkPrev Returns URL to the previous page.
func (p *Paginator) PageLinkPrev() (link string) {
if p.HasPrev() {
link = p.PageLink(p.Page() - 1)
}
return
}
// PageLinkNext Returns URL to the next page.
func (p *Paginator) PageLinkNext() (link string) {
if p.HasNext() {
link = p.PageLink(p.Page() + 1)
}
return
}
// PageLinkFirst Returns URL to the first page.
func (p *Paginator) PageLinkFirst() (link string) {
return p.PageLink(1)
}
// PageLinkLast Returns URL to the last page.
func (p *Paginator) PageLinkLast() (link string) {
return p.PageLink(p.PageNums())
}
// HasPrev Returns true if the current page has a predecessor.
func (p *Paginator) HasPrev() bool {
return p.Page() > 1
}
// HasNext Returns true if the current page has a successor.
func (p *Paginator) HasNext() bool {
return p.Page() < p.PageNums()
}
// IsActive Returns true if the given page index points to the current page.
func (p *Paginator) IsActive(page int) bool {
return p.Page() == page
}
// Offset Returns the current offset.
func (p *Paginator) Offset() int {
return (p.Page() - 1) * p.PerPageNums
}
// HasPages Returns true if there is more than one page.
func (p *Paginator) HasPages() bool {
return p.PageNums() > 1
}
// NewPaginator Instantiates a paginator struct for the current http request.
func NewPaginator(req *http.Request, per int, nums interface{}) *Paginator {
p := Paginator{}
p.Request = req
if per <= 0 {
per = 10
}
p.PerPageNums = per
p.SetNums(nums)
return &p
}

Some files were not shown because too many files have changed in this diff Show More