1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-01-04 03:49:32 +02:00

Add a lot of module related stuff.

- Leave a failing test to make hate not love.
This commit is contained in:
Aaron 2015-01-05 00:18:41 -08:00
parent a8a17318db
commit 92b3172a3e
8 changed files with 218 additions and 72 deletions

View File

@ -6,3 +6,46 @@ races without having to think about the hard questions like how to store
Remember Me tokens, or passwords.
*/
package authboss // import "gopkg.in/authboss.v0"
import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"path"
)
var logger io.Writer = ioutil.Discard
// Init authboss and it's loaded modules with a configuration.
func Init(config *Config) error {
if config.Storer == nil {
return errors.New("Configuration must provide a storer.")
}
logger = config.LogWriter
for name, mod := range modules {
fmt.Fprintf(logger, "[%-10s] Initializing\n", name)
if err := mod.Initialize(config); err != nil {
return fmt.Errorf("[%s] Error Initializing: %v", name, err)
}
}
return nil
}
// Router returns a router to be mounted at some mountpoint.
func Router(config *Config) http.Handler {
mux := http.NewServeMux()
for name, mod := range modules {
for route, handler := range mod.Routes() {
fmt.Fprintf(logger, "[%-10s] Register Route: %s\n", name)
mux.HandleFunc(path.Join(config.MountPath, route), handler)
}
}
return http.StripPrefix(config.MountPath, mux)
}

52
authboss_test.go Normal file
View File

@ -0,0 +1,52 @@
package authboss
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
)
func TestMain(main *testing.M) {
RegisterModule("testmodule", testMod)
code := main.Run()
os.Exit(code)
}
func TestAuthBossInit(t *testing.T) {
c := NewConfig()
err := Init(c)
if err == nil || !strings.Contains(err.Error(), "storer") {
t.Error("Expected error about a storer, got:", err)
}
c.Storer = testStorer(0)
err = Init(c)
if err != nil {
t.Error("Unexpected error:", err)
}
if testMod.c == nil {
t.Error("Expected the modules to be passed the config.")
}
}
func TestAuthBossRouter(t *testing.T) {
t.Parallel()
c := NewConfig()
c.MountPath = "/candycanes"
c.LogWriter = os.Stdout
router := Router(c)
r, _ := http.NewRequest("GET", "/candycanes/testroute", nil)
response := httptest.NewRecorder()
router.ServeHTTP(response, r)
if response.Header().Get("testmodule") != "test" {
t.Error("Expected a header to have been set.")
}
}

View File

@ -1,14 +1,24 @@
package authboss
// Config is a map to provide configuration key-values.
//
import (
"io"
"io/ioutil"
)
// Config holds all the configuration for both authboss and it's modules.
type Config struct {
MountPath string `json:"mountPath" xml:"mountPath"`
AuthLoginPageURI string `json:"authLoginPage" xml:"authLoginPage"`
AuthLogoutRedirect string `json:"authLogoutRedirect" xml:"authLogoutRedirect"`
Storer Storer `json:"-" xml:"-"`
LogWriter io.Writer `json:"-" xml:"-"`
}
func NewConfig() {
// NewConfig creates a new config full of default values ready to override.
func NewConfig() *Config {
return &Config{
LogWriter: ioutil.Discard,
}
}

18
core.go
View File

@ -1,18 +0,0 @@
package authboss
import (
"net/http"
)
type Routes map[string]http.HandlerFunc
type Modularizer interface {
Initialize(Config) error
Routes() Routes
Style() ([]byte, error)
Storage()
}
func Register(m Modularizer) {
}

View File

@ -1,50 +0,0 @@
/*
Package core is essentially just a namespacing for the module system. This
allows the main package for user consumption to remain free of cruft.
*/
package core // import "gopkg.in/authboss.v0/core
// dataType represents the various types that clients must be able to store.
// This type is duplicated from storer.go that we might avoid having users
// importing the core package.
type dataType int
const (
Integer dataType = iota
String
DateTime
)
var modules = make(map[string]module)
type module struct {
Name string
Storage StorageOptions
RequiredConfig []string
}
// StorageOptions is a map depicting the things a module must be able to store.
type StorageOptions map[string]DataType
// Register a module with the core providing all the necessary information to
// integrate into authboss.
func Register(name string, storage StorageOptions, requiredConfig ...string) {
}
// LoadedModules returns a list of modules that are currently loaded.
func LoadedModules() []string {
mods := make([]string, len(modules))
i := 0
for k, _ := range modules {
mods[i] = k
i++
}
return mods
}
// IsLoaded checks if a specific module is loaded.
func IsLoaded(mod string) bool {
_, ok := modules[mod]
return ok
}

43
module.go Normal file
View File

@ -0,0 +1,43 @@
package authboss
import (
"net/http"
)
var modules = make(map[string]Modularizer)
// RouteTable is a routing table from a path to a handlerfunc.
type RouteTable map[string]http.HandlerFunc
// StorageOptions is a map depicting the things a module must be able to store.
type StorageOptions map[string]DataType
type Modularizer interface {
Initialize(*Config) error
Routes() RouteTable
Storage() StorageOptions
}
// RegisterModule with the core providing all the necessary information to
// integrate into authboss.
func RegisterModule(name string, m Modularizer) {
modules[name] = m
}
// LoadedModules returns a list of modules that are currently loaded.
func LoadedModules() []string {
mods := make([]string, len(modules))
i := 0
for k, _ := range modules {
mods[i] = k
i++
}
return mods
}
// IsLoaded checks if a specific module is loaded.
func IsLoaded(mod string) bool {
_, ok := modules[mod]
return ok
}

60
module_test.go Normal file
View File

@ -0,0 +1,60 @@
package authboss
import (
"net/http"
"testing"
)
const testModName = "testmodule"
type testModule struct {
c *Config
s StorageOptions
r RouteTable
}
var testMod = &testModule{
r: RouteTable{
"/testroute": testHandler,
},
}
func testHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("testhandler", "test")
}
func (t *testModule) Initialize(c *Config) error {
t.c = c
return nil
}
func (t *testModule) Routes() RouteTable {
return t.r
}
func (t *testModule) Storage() StorageOptions {
return t.s
}
func TestRegister(t *testing.T) {
t.Parallel()
// RegisterModule called by TestMain.
if _, ok := modules["testmodule"]; !ok {
t.Error("Expected module to be saved.")
}
}
func TestLoadedModules(t *testing.T) {
t.Parallel()
// RegisterModule called by TestMain.
loadedMods := LoadedModules()
if len(loadedMods) != 1 {
t.Error("Expected only a single module to be loaded.")
} else if loadedMods[0] != "testmodule" {
t.Error("Expected testmodule to be loaded.")
}
}

View File

@ -6,6 +6,12 @@ import (
"time"
)
type testStorer int
func (t testStorer) Create(key string, attr Attributes) error { return nil }
func (t testStorer) Put(key string, attr Attributes) error { return nil }
func (t testStorer) Get(key string, attrMeta AttributeMeta) (interface{}, error) { return nil, nil }
func TestAttributes_Bind(t *testing.T) {
anInteger := 5
aString := "string"