open-vault/logical/framework/backend_test.go

545 lines
12 KiB
Go
Raw Normal View History

2015-03-15 23:39:49 +00:00
package framework
2015-03-14 04:15:20 +00:00
import (
"context"
2015-03-14 04:15:20 +00:00
"reflect"
2015-03-18 00:15:23 +00:00
"sync/atomic"
2015-03-14 04:15:20 +00:00
"testing"
"time"
2015-03-14 06:58:20 +00:00
2015-03-15 21:57:19 +00:00
"github.com/hashicorp/vault/logical"
2015-03-14 04:15:20 +00:00
)
2015-03-14 06:22:48 +00:00
func BenchmarkBackendRoute(b *testing.B) {
patterns := []string{
"foo",
"bar/(?P<name>.+?)",
"baz/(?P<name>what)",
`aws/policy/(?P<policy>\w)`,
`aws/(?P<policy>\w)`,
}
backend := &Backend{Paths: make([]*Path, 0, len(patterns))}
for _, p := range patterns {
backend.Paths = append(backend.Paths, &Path{Pattern: p})
}
// Warm any caches
backend.Route("aws/policy/foo")
// Reset the timer since we did a lot above
2015-03-14 06:22:48 +00:00
b.ResetTimer()
// Run through and route. We do a sanity check of the return value
2015-03-14 06:22:48 +00:00
for i := 0; i < b.N; i++ {
if p := backend.Route("aws/policy/foo"); p == nil {
2015-03-14 06:22:48 +00:00
b.Fatal("p should not be nil")
}
}
}
2015-03-14 06:58:20 +00:00
func TestBackend_impl(t *testing.T) {
2015-03-15 21:57:19 +00:00
var _ logical.Backend = new(Backend)
2015-03-14 06:58:20 +00:00
}
func TestBackendHandleRequest(t *testing.T) {
callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
2015-03-15 21:57:19 +00:00
return &logical.Response{
2015-03-14 06:58:20 +00:00
Data: map[string]interface{}{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
"value": data.Get("value"),
2015-03-14 06:58:20 +00:00
},
}, nil
}
b := &Backend{
Paths: []*Path{
&Path{
Pattern: "foo/bar",
Fields: map[string]*FieldSchema{
"value": &FieldSchema{Type: TypeInt},
},
2015-03-15 21:57:19 +00:00
Callbacks: map[logical.Operation]OperationFunc{
logical.ReadOperation: callback,
},
2015-03-14 06:58:20 +00:00
},
},
}
resp, err := b.HandleRequest(context.Background(), &logical.Request{
2015-03-15 21:57:19 +00:00
Operation: logical.ReadOperation,
Path: "foo/bar",
Data: map[string]interface{}{"value": "42"},
2015-03-14 06:58:20 +00:00
})
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Data["value"] != 42 {
t.Fatalf("bad: %#v", resp)
}
}
func TestBackendHandleRequest_badwrite(t *testing.T) {
callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
return &logical.Response{
Data: map[string]interface{}{
"value": data.Get("value").(bool),
},
}, nil
}
b := &Backend{
Paths: []*Path{
&Path{
Pattern: "foo/bar",
Fields: map[string]*FieldSchema{
"value": &FieldSchema{Type: TypeBool},
},
Callbacks: map[logical.Operation]OperationFunc{
2016-01-07 15:30:47 +00:00
logical.UpdateOperation: callback,
},
},
},
}
_, err := b.HandleRequest(context.Background(), &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "foo/bar",
Data: map[string]interface{}{"value": "3false3"},
})
if err == nil {
t.Fatalf("should have thrown a conversion error")
}
}
2015-03-14 06:58:20 +00:00
func TestBackendHandleRequest_404(t *testing.T) {
callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
2015-03-15 21:57:19 +00:00
return &logical.Response{
2015-03-14 06:58:20 +00:00
Data: map[string]interface{}{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
"value": data.Get("value"),
2015-03-14 06:58:20 +00:00
},
}, nil
}
b := &Backend{
Paths: []*Path{
&Path{
Pattern: `foo/bar`,
Fields: map[string]*FieldSchema{
"value": &FieldSchema{Type: TypeInt},
},
2015-03-15 21:57:19 +00:00
Callbacks: map[logical.Operation]OperationFunc{
logical.ReadOperation: callback,
},
2015-03-14 06:58:20 +00:00
},
},
}
_, err := b.HandleRequest(context.Background(), &logical.Request{
2015-03-15 21:57:19 +00:00
Operation: logical.ReadOperation,
Path: "foo/baz",
Data: map[string]interface{}{"value": "84"},
2015-03-14 06:58:20 +00:00
})
2015-03-15 21:57:19 +00:00
if err != logical.ErrUnsupportedPath {
2015-03-14 06:58:20 +00:00
t.Fatalf("err: %s", err)
}
}
func TestBackendHandleRequest_help(t *testing.T) {
b := &Backend{
Paths: []*Path{
&Path{
Pattern: "foo/bar",
Fields: map[string]*FieldSchema{
"value": &FieldSchema{Type: TypeInt},
},
HelpSynopsis: "foo",
HelpDescription: "bar",
},
},
}
resp, err := b.HandleRequest(context.Background(), &logical.Request{
2015-03-15 21:57:19 +00:00
Operation: logical.HelpOperation,
Path: "foo/bar",
Data: map[string]interface{}{"value": "42"},
})
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Data["help"] == nil {
t.Fatalf("bad: %#v", resp)
}
}
2015-04-04 03:36:47 +00:00
func TestBackendHandleRequest_helpRoot(t *testing.T) {
b := &Backend{
Help: "42",
}
resp, err := b.HandleRequest(context.Background(), &logical.Request{
2015-04-04 03:36:47 +00:00
Operation: logical.HelpOperation,
Path: "",
})
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Data["help"] == nil {
t.Fatalf("bad: %#v", resp)
}
}
func TestBackendHandleRequest_renewAuth(t *testing.T) {
b := &Backend{}
resp, err := b.HandleRequest(context.Background(), logical.RenewAuthRequest("/foo", &logical.Auth{}, nil))
if err != nil {
t.Fatalf("err: %s", err)
}
if !resp.IsError() {
t.Fatalf("bad: %#v", resp)
}
}
func TestBackendHandleRequest_renewAuthCallback(t *testing.T) {
var called uint32
callback := func(context.Context, *logical.Request, *FieldData) (*logical.Response, error) {
atomic.AddUint32(&called, 1)
return nil, nil
}
b := &Backend{
AuthRenew: callback,
}
_, err := b.HandleRequest(context.Background(), logical.RenewAuthRequest("/foo", &logical.Auth{}, nil))
if err != nil {
t.Fatalf("err: %s", err)
}
if v := atomic.LoadUint32(&called); v != 1 {
t.Fatalf("bad: %#v", v)
}
}
2015-03-19 19:20:25 +00:00
func TestBackendHandleRequest_renew(t *testing.T) {
var called uint32
callback := func(context.Context, *logical.Request, *FieldData) (*logical.Response, error) {
2015-03-19 19:20:25 +00:00
atomic.AddUint32(&called, 1)
return nil, nil
}
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
secret := &Secret{
Type: "foo",
Renew: callback,
}
2015-03-19 19:20:25 +00:00
b := &Backend{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secrets: []*Secret{secret},
2015-03-19 19:20:25 +00:00
}
_, err := b.HandleRequest(context.Background(), logical.RenewRequest("/foo", secret.Response(nil, nil).Secret, nil))
2015-03-19 19:20:25 +00:00
if err != nil {
t.Fatalf("err: %s", err)
}
if v := atomic.LoadUint32(&called); v != 1 {
t.Fatalf("bad: %#v", v)
}
}
2015-03-19 18:41:41 +00:00
func TestBackendHandleRequest_revoke(t *testing.T) {
var called uint32
callback := func(context.Context, *logical.Request, *FieldData) (*logical.Response, error) {
2015-03-19 18:41:41 +00:00
atomic.AddUint32(&called, 1)
return nil, nil
}
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
secret := &Secret{
Type: "foo",
Revoke: callback,
}
2015-03-19 18:41:41 +00:00
b := &Backend{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secrets: []*Secret{secret},
2015-03-19 18:41:41 +00:00
}
_, err := b.HandleRequest(context.Background(), logical.RevokeRequest("/foo", secret.Response(nil, nil).Secret, nil))
2015-03-19 18:41:41 +00:00
if err != nil {
t.Fatalf("err: %s", err)
}
if v := atomic.LoadUint32(&called); v != 1 {
t.Fatalf("bad: %#v", v)
}
}
2015-03-18 00:15:23 +00:00
func TestBackendHandleRequest_rollback(t *testing.T) {
var called uint32
callback := func(_ context.Context, req *logical.Request, kind string, data interface{}) error {
2015-03-18 00:15:23 +00:00
if data == "foo" {
atomic.AddUint32(&called, 1)
}
return nil
2015-03-18 00:15:23 +00:00
}
b := &Backend{
2016-05-14 23:35:36 +00:00
WALRollback: callback,
WALRollbackMinAge: 1 * time.Millisecond,
2015-03-18 00:15:23 +00:00
}
storage := new(logical.InmemStorage)
if _, err := PutWAL(context.Background(), storage, "kind", "foo"); err != nil {
2015-03-18 00:15:23 +00:00
t.Fatalf("err: %s", err)
}
time.Sleep(10 * time.Millisecond)
_, err := b.HandleRequest(context.Background(), &logical.Request{
2015-03-18 00:15:23 +00:00
Operation: logical.RollbackOperation,
Path: "",
Storage: storage,
})
if err != nil {
t.Fatalf("err: %s", err)
}
if v := atomic.LoadUint32(&called); v != 1 {
t.Fatalf("bad: %#v", v)
}
}
func TestBackendHandleRequest_rollbackMinAge(t *testing.T) {
var called uint32
callback := func(_ context.Context, req *logical.Request, kind string, data interface{}) error {
if data == "foo" {
atomic.AddUint32(&called, 1)
}
return nil
}
b := &Backend{
2016-05-14 23:35:36 +00:00
WALRollback: callback,
WALRollbackMinAge: 5 * time.Second,
}
storage := new(logical.InmemStorage)
if _, err := PutWAL(context.Background(), storage, "kind", "foo"); err != nil {
t.Fatalf("err: %s", err)
}
_, err := b.HandleRequest(context.Background(), &logical.Request{
Operation: logical.RollbackOperation,
Path: "",
Storage: storage,
})
if err != nil {
t.Fatalf("err: %s", err)
}
if v := atomic.LoadUint32(&called); v != 0 {
t.Fatalf("bad: %#v", v)
}
}
func TestBackendHandleRequest_unsupportedOperation(t *testing.T) {
callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
2015-03-15 21:57:19 +00:00
return &logical.Response{
Data: map[string]interface{}{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
"value": data.Get("value"),
},
}, nil
}
b := &Backend{
Paths: []*Path{
&Path{
Pattern: `foo/bar`,
Fields: map[string]*FieldSchema{
"value": &FieldSchema{Type: TypeInt},
},
2015-03-15 21:57:19 +00:00
Callbacks: map[logical.Operation]OperationFunc{
logical.ReadOperation: callback,
},
},
},
}
_, err := b.HandleRequest(context.Background(), &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "foo/bar",
Data: map[string]interface{}{"value": "84"},
})
2015-03-15 21:57:19 +00:00
if err != logical.ErrUnsupportedOperation {
t.Fatalf("err: %s", err)
}
}
2015-03-14 06:58:20 +00:00
func TestBackendHandleRequest_urlPriority(t *testing.T) {
callback := func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) {
2015-03-15 21:57:19 +00:00
return &logical.Response{
2015-03-14 06:58:20 +00:00
Data: map[string]interface{}{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
"value": data.Get("value"),
2015-03-14 06:58:20 +00:00
},
}, nil
}
b := &Backend{
Paths: []*Path{
&Path{
Pattern: `foo/(?P<value>\d+)`,
Fields: map[string]*FieldSchema{
"value": &FieldSchema{Type: TypeInt},
},
2015-03-15 21:57:19 +00:00
Callbacks: map[logical.Operation]OperationFunc{
logical.ReadOperation: callback,
},
2015-03-14 06:58:20 +00:00
},
},
}
resp, err := b.HandleRequest(context.Background(), &logical.Request{
2015-03-15 21:57:19 +00:00
Operation: logical.ReadOperation,
Path: "foo/42",
Data: map[string]interface{}{"value": "84"},
2015-03-14 06:58:20 +00:00
})
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Data["value"] != 42 {
t.Fatalf("bad: %#v", resp)
}
}
func TestBackendRoute(t *testing.T) {
cases := map[string]struct {
Patterns []string
Path string
Match string
}{
"no match": {
[]string{"foo"},
"bar",
"",
},
"exact": {
[]string{"foo"},
"foo",
"^foo$",
},
"regexp": {
[]string{"fo+"},
"foo",
"^fo+$",
},
"anchor-start": {
[]string{"bar"},
"foobar",
"",
},
"anchor-end": {
[]string{"bar"},
"barfoo",
"",
},
"anchor-ambiguous": {
[]string{"mounts", "sys/mounts"},
"sys/mounts",
"^sys/mounts$",
},
}
for n, tc := range cases {
paths := make([]*Path, len(tc.Patterns))
for i, pattern := range tc.Patterns {
paths[i] = &Path{Pattern: pattern}
}
b := &Backend{Paths: paths}
result := b.Route(tc.Path)
match := ""
if result != nil {
match = result.Pattern
}
if match != tc.Match {
t.Fatalf("bad: %s\n\nExpected: %s\nGot: %s",
n, tc.Match, match)
}
}
}
func TestBackendSecret(t *testing.T) {
cases := map[string]struct {
Secrets []*Secret
Search string
Match bool
}{
"no match": {
[]*Secret{&Secret{Type: "foo"}},
"bar",
false,
},
"match": {
[]*Secret{&Secret{Type: "foo"}},
"foo",
true,
},
}
for n, tc := range cases {
b := &Backend{Secrets: tc.Secrets}
result := b.Secret(tc.Search)
if tc.Match != (result != nil) {
t.Fatalf("bad: %s\n\nExpected match: %v", n, tc.Match)
}
if result != nil && result.Type != tc.Search {
t.Fatalf("bad: %s\n\nExpected matching type: %#v", n, result)
}
}
}
2015-03-14 04:15:20 +00:00
func TestFieldSchemaDefaultOrZero(t *testing.T) {
cases := map[string]struct {
Schema *FieldSchema
Value interface{}
}{
"default set": {
&FieldSchema{Type: TypeString, Default: "foo"},
"foo",
},
"default not set": {
&FieldSchema{Type: TypeString},
"",
},
"default duration set": {
&FieldSchema{Type: TypeDurationSecond, Default: 60},
60,
},
"default duration int64": {
&FieldSchema{Type: TypeDurationSecond, Default: int64(60)},
60,
},
"default duration string": {
&FieldSchema{Type: TypeDurationSecond, Default: "60s"},
60,
},
"default duration not set": {
&FieldSchema{Type: TypeDurationSecond},
0,
},
2015-03-14 04:15:20 +00:00
}
for name, tc := range cases {
actual := tc.Schema.DefaultOrZero()
if !reflect.DeepEqual(actual, tc.Value) {
t.Fatalf("bad: %s\n\nExpected: %#v\nGot: %#v",
name, tc.Value, actual)
}
}
}