micro/api/server/acme/certmagic/certmagic_test.go

229 lines
5.6 KiB
Go
Raw Normal View History

package certmagic
import (
"net"
"net/http"
"os"
"reflect"
"sort"
"testing"
"time"
"github.com/go-acme/lego/v3/providers/dns/cloudflare"
"github.com/mholt/certmagic"
"github.com/micro/go-micro/v2/api/server/acme"
cfstore "github.com/micro/go-micro/v2/store/cloudflare"
"github.com/micro/go-micro/v2/sync/lock/memory"
)
func TestCertMagic(t *testing.T) {
if len(os.Getenv("IN_TRAVIS_CI")) != 0 {
t.Skip("Travis doesn't let us bind :443")
}
l, err := NewProvider().Listen()
if err != nil {
if _, ok := err.(*net.OpError); ok {
t.Skip("Run under non privileged user")
}
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
}
l.Close()
c := cloudflare.NewDefaultConfig()
c.AuthEmail = ""
c.AuthKey = ""
c.AuthToken = "test"
c.ZoneToken = "test"
p, err := cloudflare.NewDNSProviderConfig(c)
if err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
}
l, err = NewProvider(acme.AcceptToS(true),
acme.CA(acme.LetsEncryptStagingCA),
acme.ChallengeProvider(p),
).Listen()
if err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
}
l.Close()
}
func TestStorageImplementation(t *testing.T) {
apiToken, accountID := os.Getenv("CF_API_TOKEN"), os.Getenv("CF_ACCOUNT_ID")
kvID := os.Getenv("KV_NAMESPACE_ID")
if len(apiToken) == 0 || len(accountID) == 0 || len(kvID) == 0 {
t.Skip("No Cloudflare API keys available, skipping test")
}
var s certmagic.Storage
2019-10-23 22:54:55 +01:00
st := cfstore.NewStore(
2019-10-23 23:12:45 +01:00
cfstore.Token(apiToken),
cfstore.Account(accountID),
2019-10-23 22:31:36 +01:00
cfstore.Namespace(kvID),
)
s = &storage{
lock: memory.NewLock(),
store: st,
}
// Test Lock
if err := s.Lock("test"); err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err)
}
// Test Unlock
if err := s.Unlock("test"); err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err)
}
// Test data
testdata := []struct {
key string
value []byte
}{
{key: "/foo/a", value: []byte("lorem")},
{key: "/foo/b", value: []byte("ipsum")},
{key: "/foo/c", value: []byte("dolor")},
{key: "/foo/d", value: []byte("sit")},
{key: "/bar/a", value: []byte("amet")},
{key: "/bar/b", value: []byte("consectetur")},
{key: "/bar/c", value: []byte("adipiscing")},
{key: "/bar/d", value: []byte("elit")},
{key: "/foo/bar/a", value: []byte("sed")},
{key: "/foo/bar/b", value: []byte("do")},
{key: "/foo/bar/c", value: []byte("eiusmod")},
{key: "/foo/bar/d", value: []byte("tempor")},
{key: "/foo/bar/baz/a", value: []byte("incididunt")},
{key: "/foo/bar/baz/b", value: []byte("ut")},
{key: "/foo/bar/baz/c", value: []byte("labore")},
{key: "/foo/bar/baz/d", value: []byte("et")},
// a duplicate just in case there's any edge cases
{key: "/foo/a", value: []byte("lorem")},
}
// Test Store
for _, d := range testdata {
if err := s.Store(d.key, d.value); err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
}
}
// Test Load
for _, d := range testdata {
if value, err := s.Load(d.key); err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
} else {
if !reflect.DeepEqual(value, d.value) {
2019-10-23 22:31:36 +01:00
t.Fatalf("Load %s: expected %v, got %v", d.key, d.value, value)
}
}
}
// Test Exists
for _, d := range testdata {
if !s.Exists(d.key) {
2019-10-23 22:31:36 +01:00
t.Fatalf("%s should exist, but doesn't\n", d.key)
}
}
// Test List
if list, err := s.List("/", true); err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
} else {
var expected []string
for i, d := range testdata {
if i != len(testdata)-1 {
// Don't store the intentionally duplicated key
expected = append(expected, d.key)
}
}
sort.Strings(expected)
sort.Strings(list)
if !reflect.DeepEqual(expected, list) {
2019-10-23 22:31:36 +01:00
t.Fatalf("List: Expected %v, got %v\n", expected, list)
}
}
if list, err := s.List("/foo", false); err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
} else {
sort.Strings(list)
expected := []string{"/foo/a", "/foo/b", "/foo/bar", "/foo/c", "/foo/d"}
if !reflect.DeepEqual(expected, list) {
2019-10-23 22:31:36 +01:00
t.Fatalf("List: expected %s, got %s\n", expected, list)
}
}
// Test Stat
for _, d := range testdata {
info, err := s.Stat(d.key)
if err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
} else {
if info.Key != d.key {
2019-10-23 22:31:36 +01:00
t.Fatalf("Stat().Key: expected %s, got %s\n", d.key, info.Key)
}
if info.Size != int64(len(d.value)) {
2019-10-23 22:31:36 +01:00
t.Fatalf("Stat().Size: expected %d, got %d\n", len(d.value), info.Size)
}
if time.Since(info.Modified) > time.Minute {
2019-10-23 22:31:36 +01:00
t.Fatalf("Stat().Modified: expected time since last modified to be < 1 minute, got %v\n", time.Since(info.Modified))
}
}
}
// Test Delete
for _, d := range testdata {
if err := s.Delete(d.key); err != nil {
2019-10-23 22:31:36 +01:00
t.Fatal(err.Error())
}
}
// New interface doesn't return an error, so call it in case any log.Fatal
// happens
NewProvider(acme.Cache(s))
}
// Full test with a real zone, with against LE staging
func TestE2e(t *testing.T) {
apiToken, accountID := os.Getenv("CF_API_TOKEN"), os.Getenv("CF_ACCOUNT_ID")
kvID := os.Getenv("KV_NAMESPACE_ID")
if len(apiToken) == 0 || len(accountID) == 0 || len(kvID) == 0 {
t.Skip("No Cloudflare API keys available, skipping test")
}
testLock := memory.NewLock()
2019-10-23 22:54:55 +01:00
testStore := cfstore.NewStore(
2019-10-23 23:12:45 +01:00
cfstore.Token(apiToken),
cfstore.Account(accountID),
2019-10-23 22:31:36 +01:00
cfstore.Namespace(kvID),
)
testStorage := NewStorage(testLock, testStore)
conf := cloudflare.NewDefaultConfig()
conf.AuthToken = apiToken
conf.ZoneToken = apiToken
testChallengeProvider, err := cloudflare.NewDNSProviderConfig(conf)
if err != nil {
t.Fatal(err.Error())
}
testProvider := NewProvider(
acme.AcceptToS(true),
acme.Cache(testStorage),
acme.CA(acme.LetsEncryptStagingCA),
acme.ChallengeProvider(testChallengeProvider),
acme.OnDemand(false),
)
listener, err := testProvider.Listen("*.micro.mu", "micro.mu")
if err != nil {
t.Fatal(err.Error())
}
go http.Serve(listener, http.NotFoundHandler())
time.Sleep(10 * time.Minute)
}