blob: 6fde4dba6ed4fd74d11ceeea75637429614cca76 [file]
// Copyright 2016 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package format
import (
"testing"
"github.com/luci/luci-go/luci_config/server/cfgclient"
"github.com/luci/luci-go/luci_config/server/cfgclient/backend"
"golang.org/x/net/context"
. "github.com/smartystreets/goconvey/convey"
)
// testingBackend is a Backend implementation that ignores Authority.
type testingBackend struct {
backend.B
err error
items []*backend.Item
}
func (tb *testingBackend) Get(c context.Context, configSet, path string, p backend.Params) (*backend.Item, error) {
if err := tb.err; err != nil {
return nil, tb.err
}
if len(tb.items) == 0 {
return nil, cfgclient.ErrNoConfig
}
return tb.cloneItems()[0], nil
}
func (tb *testingBackend) GetAll(c context.Context, t backend.GetAllTarget, path string, p backend.Params) (
[]*backend.Item, error) {
if err := tb.err; err != nil {
return nil, tb.err
}
return tb.cloneItems(), nil
}
func (tb *testingBackend) cloneItems() []*backend.Item {
clones := make([]*backend.Item, len(tb.items))
for i, it := range tb.items {
clone := *it
clones[i] = &clone
}
return clones
}
// retainingBackend is a simple Backend implementation that retains the last set
// of data that it received.
type retainingBackend struct {
backend.B
lastItems []*backend.Item
lastErr error
}
func (b *retainingBackend) Get(c context.Context, configSet, path string, p backend.Params) (*backend.Item, error) {
var item *backend.Item
item, b.lastErr = b.B.Get(c, configSet, path, p)
b.lastItems = []*backend.Item{item}
return item, b.lastErr
}
func (b *retainingBackend) GetAll(c context.Context, t backend.GetAllTarget, path string, p backend.Params) (
[]*backend.Item, error) {
b.lastItems, b.lastErr = b.B.GetAll(c, t, path, p)
return b.lastItems, b.lastErr
}
type customFormatter string
func (cf customFormatter) FormatItem(c string, fd string) (string, error) {
return string(cf), nil
}
type retainingResolver struct {
format string
item *backend.Item
}
func (rr *retainingResolver) Format() backend.FormatSpec { return backend.FormatSpec{rr.format, ""} }
func (rr *retainingResolver) Resolve(it *backend.Item) error {
rr.item = it
return nil
}
var _ interface {
cfgclient.Resolver
cfgclient.FormattingResolver
} = (*retainingResolver)(nil)
type panicFormatter struct{}
func (pf panicFormatter) FormatItem(string, string) (string, error) { panic("panic") }
func TestFormatBackend(t *testing.T) {
Convey(`A testing environment`, t, func() {
tb := testingBackend{
items: []*backend.Item{
{Meta: backend.Meta{"projects/foo", "path", "####", "v1"}, Content: "foo"},
{Meta: backend.Meta{"projects/bar", "path", "####", "v1"}, Content: "bar"},
},
}
// Pass all things from the backend through the formatter.
fb := Backend{
B: &tb,
}
// Retain all raw Items that were returned for examination.
rb := retainingBackend{
B: &fb,
}
c := context.Background()
c = backend.WithBackend(c, &rb)
ClearRegistry()
Convey(`Will panic if an attempt to register empty key is made.`, func() {
So(func() { Register("", nil) }, ShouldPanic)
})
Convey(`Will ignore items that have already been formatted.`, func() {
rr := retainingResolver{"test", nil}
Register("test", panicFormatter{})
// Confirm that this setup correctly attempts to format the item.
So(func() { cfgclient.Get(c, cfgclient.AsService, "", "", &rr, nil) }, ShouldPanic)
// Now, pretend the item is already formatter. We should not get a panic.
tb.items[0].FormatSpec.Formatter = "something"
So(cfgclient.Get(c, cfgclient.AsService, "", "", &rr, nil), ShouldBeNil)
})
Convey(`Testing custom formatter`, func() {
cf := customFormatter("content")
Register("test", cf)
// Confirm that this setup correctly attempts to format the item.
rr := retainingResolver{"test", nil}
So(cfgclient.Get(c, cfgclient.AsService, "", "", &rr, nil), ShouldBeNil)
So(rr.item, ShouldNotBeNil)
So(rr.item.FormatSpec.Formatter, ShouldEqual, "test")
So(rr.item.Content, ShouldEqual, "content")
})
})
}