mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-12 05:23:42 +08:00
271 lines
7.7 KiB
Go
271 lines
7.7 KiB
Go
|
// Package storagetest provides utilities to assist in testing caddytls.Storage
|
||
|
// implementations.
|
||
|
package storagetest
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"github.com/mholt/caddy/caddytls"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
// StorageTest is a test harness that contains tests to execute all exposed
|
||
|
// parts of a Storage implementation.
|
||
|
type StorageTest struct {
|
||
|
// Storage is the implementation to use during tests. This must be
|
||
|
// present.
|
||
|
caddytls.Storage
|
||
|
|
||
|
// PreTest, if present, is called before every test. Any error returned
|
||
|
// is returned from the test and the test does not continue.
|
||
|
PreTest func() error
|
||
|
|
||
|
// PostTest, if present, is executed after every test via defer which
|
||
|
// means it executes even on failure of the test (but not on failure of
|
||
|
// PreTest).
|
||
|
PostTest func()
|
||
|
|
||
|
// AfterUserEmailStore, if present, is invoked during
|
||
|
// TestMostRecentUserEmail after each storage just in case anything
|
||
|
// needs to be mocked.
|
||
|
AfterUserEmailStore func(email string) error
|
||
|
}
|
||
|
|
||
|
// TestFunc holds information about a test.
|
||
|
type TestFunc struct {
|
||
|
// Name is the friendly name of the test.
|
||
|
Name string
|
||
|
|
||
|
// Fn is the function that is invoked for the test.
|
||
|
Fn func() error
|
||
|
}
|
||
|
|
||
|
// runPreTest runs the PreTest function if present.
|
||
|
func (s *StorageTest) runPreTest() error {
|
||
|
if s.PreTest != nil {
|
||
|
return s.PreTest()
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// runPostTest runs the PostTest function if present.
|
||
|
func (s *StorageTest) runPostTest() {
|
||
|
if s.PostTest != nil {
|
||
|
s.PostTest()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// AllFuncs returns all test functions that are part of this harness.
|
||
|
func (s *StorageTest) AllFuncs() []TestFunc {
|
||
|
return []TestFunc{
|
||
|
{"TestSiteInfoExists", s.TestSiteExists},
|
||
|
{"TestSite", s.TestSite},
|
||
|
{"TestUser", s.TestUser},
|
||
|
{"TestMostRecentUserEmail", s.TestMostRecentUserEmail},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Test executes the entire harness using the testing package. Failures are
|
||
|
// reported via T.Fatal. If eagerFail is true, the first failure causes all
|
||
|
// testing to stop immediately.
|
||
|
func (s *StorageTest) Test(t *testing.T, eagerFail bool) {
|
||
|
if errs := s.TestAll(eagerFail); len(errs) > 0 {
|
||
|
ifaces := make([]interface{}, len(errs))
|
||
|
for i, err := range errs {
|
||
|
ifaces[i] = err
|
||
|
}
|
||
|
t.Fatal(ifaces...)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TestAll executes the entire harness and returns the results as an array of
|
||
|
// errors. If eagerFail is true, the first failure causes all testing to stop
|
||
|
// immediately.
|
||
|
func (s *StorageTest) TestAll(eagerFail bool) (errs []error) {
|
||
|
for _, fn := range s.AllFuncs() {
|
||
|
if err := fn.Fn(); err != nil {
|
||
|
errs = append(errs, fmt.Errorf("%v failed: %v", fn.Name, err))
|
||
|
if eagerFail {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var simpleSiteData = &caddytls.SiteData{
|
||
|
Cert: []byte("foo"),
|
||
|
Key: []byte("bar"),
|
||
|
Meta: []byte("baz"),
|
||
|
}
|
||
|
var simpleSiteDataAlt = &caddytls.SiteData{
|
||
|
Cert: []byte("qux"),
|
||
|
Key: []byte("quux"),
|
||
|
Meta: []byte("corge"),
|
||
|
}
|
||
|
|
||
|
// TestSiteExists tests Storage.SiteExists.
|
||
|
func (s *StorageTest) TestSiteExists() error {
|
||
|
if err := s.runPreTest(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer s.runPostTest()
|
||
|
|
||
|
// Should not exist at first
|
||
|
if s.SiteExists("example.com") {
|
||
|
return errors.New("Site should not exist")
|
||
|
}
|
||
|
|
||
|
// Should exist after we store it
|
||
|
if err := s.StoreSite("example.com", simpleSiteData); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if !s.SiteExists("example.com") {
|
||
|
return errors.New("Expected site to exist")
|
||
|
}
|
||
|
|
||
|
// Site should no longer exist after we delete it
|
||
|
if err := s.DeleteSite("example.com"); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if s.SiteExists("example.com") {
|
||
|
return errors.New("Site should not exist after delete")
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// TestSite tests Storage.LoadSite, Storage.StoreSite, and Storage.DeleteSite.
|
||
|
func (s *StorageTest) TestSite() error {
|
||
|
if err := s.runPreTest(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer s.runPostTest()
|
||
|
|
||
|
// Should be a not-found error at first
|
||
|
if _, err := s.LoadSite("example.com"); err != caddytls.ErrStorageNotFound {
|
||
|
return fmt.Errorf("Expected ErrStorageNotFound from load, got: %v", err)
|
||
|
}
|
||
|
|
||
|
// Delete should also be a not-found error at first
|
||
|
if err := s.DeleteSite("example.com"); err != caddytls.ErrStorageNotFound {
|
||
|
return fmt.Errorf("Expected ErrStorageNotFound from delete, got: %v", err)
|
||
|
}
|
||
|
|
||
|
// Should store successfully and then load just fine
|
||
|
if err := s.StoreSite("example.com", simpleSiteData); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if siteData, err := s.LoadSite("example.com"); err != nil {
|
||
|
return err
|
||
|
} else if !bytes.Equal(siteData.Cert, simpleSiteData.Cert) {
|
||
|
return errors.New("Unexpected cert returned after store")
|
||
|
} else if !bytes.Equal(siteData.Key, simpleSiteData.Key) {
|
||
|
return errors.New("Unexpected key returned after store")
|
||
|
} else if !bytes.Equal(siteData.Meta, simpleSiteData.Meta) {
|
||
|
return errors.New("Unexpected meta returned after store")
|
||
|
}
|
||
|
|
||
|
// Overwrite should work just fine
|
||
|
if err := s.StoreSite("example.com", simpleSiteDataAlt); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if siteData, err := s.LoadSite("example.com"); err != nil {
|
||
|
return err
|
||
|
} else if !bytes.Equal(siteData.Cert, simpleSiteDataAlt.Cert) {
|
||
|
return errors.New("Unexpected cert returned after overwrite")
|
||
|
}
|
||
|
|
||
|
// It should delete fine and then not be there
|
||
|
if err := s.DeleteSite("example.com"); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if _, err := s.LoadSite("example.com"); err != caddytls.ErrStorageNotFound {
|
||
|
return fmt.Errorf("Expected ErrStorageNotFound after delete, got: %v", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
var simpleUserData = &caddytls.UserData{
|
||
|
Reg: []byte("foo"),
|
||
|
Key: []byte("bar"),
|
||
|
}
|
||
|
var simpleUserDataAlt = &caddytls.UserData{
|
||
|
Reg: []byte("baz"),
|
||
|
Key: []byte("qux"),
|
||
|
}
|
||
|
|
||
|
// TestUser tests Storage.LoadUser and Storage.StoreUser.
|
||
|
func (s *StorageTest) TestUser() error {
|
||
|
if err := s.runPreTest(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer s.runPostTest()
|
||
|
|
||
|
// Should be a not-found error at first
|
||
|
if _, err := s.LoadUser("foo@example.com"); err != caddytls.ErrStorageNotFound {
|
||
|
return fmt.Errorf("Expected ErrStorageNotFound from load, got: %v", err)
|
||
|
}
|
||
|
|
||
|
// Should store successfully and then load just fine
|
||
|
if err := s.StoreUser("foo@example.com", simpleUserData); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if userData, err := s.LoadUser("foo@example.com"); err != nil {
|
||
|
return err
|
||
|
} else if !bytes.Equal(userData.Reg, simpleUserData.Reg) {
|
||
|
return errors.New("Unexpected reg returned after store")
|
||
|
} else if !bytes.Equal(userData.Key, simpleUserData.Key) {
|
||
|
return errors.New("Unexpected key returned after store")
|
||
|
}
|
||
|
|
||
|
// Overwrite should work just fine
|
||
|
if err := s.StoreUser("foo@example.com", simpleUserDataAlt); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if userData, err := s.LoadUser("foo@example.com"); err != nil {
|
||
|
return err
|
||
|
} else if !bytes.Equal(userData.Reg, simpleUserDataAlt.Reg) {
|
||
|
return errors.New("Unexpected reg returned after overwrite")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// TestMostRecentUserEmail tests Storage.MostRecentUserEmail.
|
||
|
func (s *StorageTest) TestMostRecentUserEmail() error {
|
||
|
if err := s.runPreTest(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer s.runPostTest()
|
||
|
|
||
|
// Should be empty on first run
|
||
|
if e := s.MostRecentUserEmail(); e != "" {
|
||
|
return fmt.Errorf("Expected empty most recent user on first run, got: %v", e)
|
||
|
}
|
||
|
|
||
|
// If we store user, then that one should be returned
|
||
|
if err := s.StoreUser("foo1@example.com", simpleUserData); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if s.AfterUserEmailStore != nil {
|
||
|
s.AfterUserEmailStore("foo1@example.com")
|
||
|
}
|
||
|
if e := s.MostRecentUserEmail(); e != "foo1@example.com" {
|
||
|
return fmt.Errorf("Unexpected most recent email after first store: %v", e)
|
||
|
}
|
||
|
|
||
|
// If we store another user, then that one should be returned
|
||
|
if err := s.StoreUser("foo2@example.com", simpleUserDataAlt); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if s.AfterUserEmailStore != nil {
|
||
|
s.AfterUserEmailStore("foo2@example.com")
|
||
|
}
|
||
|
if e := s.MostRecentUserEmail(); e != "foo2@example.com" {
|
||
|
return fmt.Errorf("Unexpected most recent email after user key: %v", e)
|
||
|
}
|
||
|
return nil
|
||
|
}
|