Require database connection configuraton (#228)

* Require explicit configuration for database connection

* Test validation

* Remove stutter

* Only use packr for self hosting

* Restart server upon change
This commit is contained in:
Sung Won Cho 2019-07-24 17:32:12 +10:00 committed by GitHub
commit 2c82e36f7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 205 additions and 28 deletions

View file

@ -2,6 +2,7 @@ DEP := $(shell command -v dep 2> /dev/null)
PACKR2 := $(shell command -v packr2 2> /dev/null)
NPM := $(shell command -v npm 2> /dev/null)
HUB := $(shell command -v hub 2> /dev/null)
COMPILEDAEMON := $(shell command -v CompileDaemon 2> /dev/null)
## installation
install: install-go install-js
@ -18,6 +19,11 @@ ifndef PACKR2
@go get -u github.com/gobuffalo/packr/v2/packr2
endif
ifndef COMPILEDAEMON
@echo "==> installing CompileDaemon"
@go get -u github.com/githubnemo/CompileDaemon
endif
@echo "==> installing go dependencies"
@dep ensure
.PHONY: install-go

View file

@ -1,7 +1,7 @@
GO_ENV=DEVELOPMENT
DBHost=localhost
DBPost=5432
DBPort=5432
DBName=dnote
DBUser=postgres
DBPassword=

View file

@ -5,3 +5,4 @@ tmp/
test-dnote
/dist
/build
server

View file

@ -21,11 +21,19 @@ package main
import (
"github.com/dnote/dnote/pkg/server/api/helpers"
"github.com/dnote/dnote/pkg/server/database"
"os"
"time"
)
func main() {
database.InitDB()
c := database.Config{
Host: os.Getenv("DBHost"),
Port: os.Getenv("DBPort"),
Name: os.Getenv("DBName"),
User: os.Getenv("DBUser"),
Password: os.Getenv("DBPassword"),
}
database.Open(c)
db := database.DBConn
tx := db.Begin()

View file

@ -23,6 +23,7 @@ import (
"os"
"github.com/jinzhu/gorm"
"github.com/pkg/errors"
// Use postgres
_ "github.com/lib/pq"
@ -33,7 +34,49 @@ var (
MigrationTableName = "migrations"
)
func getPGConnectionString() string {
// Config holds the connection configuration
type Config struct {
Host string
Port string
Name string
User string
Password string
}
// ErrConfigMissingHost is an error for an incomplete configuration missing the host
var ErrConfigMissingHost = errors.New("Host is empty")
// ErrConfigMissingPort is an error for an incomplete configuration missing the port
var ErrConfigMissingPort = errors.New("Port is empty")
// ErrConfigMissingName is an error for an incomplete configuration missing the name
var ErrConfigMissingName = errors.New("Name is empty")
// ErrConfigMissingUser is an error for an incomplete configuration missing the user
var ErrConfigMissingUser = errors.New("User is empty")
func validateConfig(c Config) error {
if c.Host == "" {
return ErrConfigMissingHost
}
if c.Port == "" {
return ErrConfigMissingPort
}
if c.Name == "" {
return ErrConfigMissingName
}
if c.User == "" {
return ErrConfigMissingUser
}
return nil
}
func getPGConnectionString(c Config) (string, error) {
if err := validateConfig(c); err != nil {
return "", errors.Wrap(err, "invalid database config")
}
var sslmode string
if os.Getenv("GO_ENV") == "PRODUCTION" {
sslmode = "require"
@ -44,12 +87,12 @@ func getPGConnectionString() string {
return fmt.Sprintf(
"sslmode=%s host=%s port=%s dbname=%s user=%s password=%s",
sslmode,
os.Getenv("DBHost"),
os.Getenv("DBPort"),
os.Getenv("DBName"),
os.Getenv("DBUser"),
os.Getenv("DBPassword"),
)
c.Host,
c.Port,
c.Name,
c.User,
c.Password,
), nil
}
var (
@ -64,11 +107,12 @@ const (
TokenTypeEmailPreference = "email_preference"
)
// InitDB opens the connection with the database
func InitDB() {
var err error
connStr := getPGConnectionString()
// Open opens the connection with the database
func Open(c Config) {
connStr, err := getPGConnectionString(c)
if err != nil {
panic(err)
}
DBConn, err = gorm.Open("postgres", connStr)
if err != nil {
@ -76,8 +120,8 @@ func InitDB() {
}
}
// CloseDB closes database connection
func CloseDB() {
// Close closes database connection
func Close() {
DBConn.Close()
}

View file

@ -0,0 +1,79 @@
package database
import (
"github.com/dnote/dnote/pkg/assert"
"testing"
)
func TestValidateConfig(t *testing.T) {
testCases := []struct {
input Config
expected error
}{
{
input: Config{
Host: "mockHost",
Port: "mockPort",
Name: "mockName",
User: "mockUser",
Password: "mockPassword",
},
expected: nil,
},
{
input: Config{
Host: "mockHost",
Port: "mockPort",
Name: "mockName",
User: "mockUser",
},
expected: nil,
},
{
input: Config{
Port: "mockPort",
Name: "mockName",
User: "mockUser",
Password: "mockPassword",
},
expected: ErrConfigMissingHost,
},
{
input: Config{
Host: "mockHost",
Name: "mockName",
User: "mockUser",
Password: "mockPassword",
},
expected: ErrConfigMissingPort,
},
{
input: Config{
Host: "mockHost",
Port: "mockPort",
User: "mockUser",
Password: "mockPassword",
},
expected: ErrConfigMissingName,
},
{
input: Config{
Host: "mockHost",
Port: "mockPort",
Name: "mockName",
Password: "mockPassword",
},
expected: ErrConfigMissingUser,
},
{
input: Config{},
expected: ErrConfigMissingHost,
},
}
for _, tc := range testCases {
result := validateConfig(tc.input)
assert.Equal(t, result, tc.expected, "result mismatch")
}
}

View file

@ -43,7 +43,14 @@ func init() {
}
}
database.InitDB()
c := database.Config{
Host: os.Getenv("DBHost"),
Port: os.Getenv("DBPort"),
Name: os.Getenv("DBName"),
User: os.Getenv("DBUser"),
Password: os.Getenv("DBPassword"),
}
database.Open(c)
}
func main() {

View file

@ -86,8 +86,14 @@ func initTemplate(box *packr.Box, templateName string) (*template.Template, erro
}
// InitTemplates initializes templates
func InitTemplates() {
box := packr.New("emailTemplates", "./templates/src")
func InitTemplates(srcDir *string) {
var box *packr.Box
if srcDir != nil {
box = packr.Folder(*srcDir)
} else {
box = packr.New("emailTemplates", "./templates/src")
}
weeklyDigestTmpl, err := initTemplate(box, EmailTypeWeeklyDigest)
if err != nil {

View file

@ -21,6 +21,7 @@ package main
import (
"log"
"net/http"
"os"
"github.com/dnote/dnote/pkg/server/database"
"github.com/dnote/dnote/pkg/server/job"
@ -76,10 +77,17 @@ func init() {
}
func main() {
database.InitDB()
defer database.CloseDB()
c := database.Config{
Host: os.Getenv("DBHost"),
Port: os.Getenv("DBPort"),
Name: os.Getenv("DBName"),
User: os.Getenv("DBUser"),
Password: os.Getenv("DBPassword"),
}
database.Open(c)
defer database.Close()
mailer.InitTemplates()
mailer.InitTemplates(nil)
log.Println("Email template debug server running on http://127.0.0.1:2300")

View file

@ -23,6 +23,7 @@ import (
"fmt"
"log"
"net/http"
"os"
"strings"
"github.com/dnote/dnote/pkg/server/api/clock"
@ -37,7 +38,7 @@ import (
)
var versionTag = "master"
var port = flag.String("port", "8080", "port to connect to")
var port = flag.String("port", "3000", "port to connect to")
func init() {
}
@ -78,10 +79,18 @@ func initServer() *mux.Router {
}
func startCmd() {
mailer.InitTemplates()
database.InitDB()
c := database.Config{
Host: os.Getenv("DBHost"),
Port: os.Getenv("DBPort"),
Name: os.Getenv("DBName"),
User: os.Getenv("DBUser"),
Password: os.Getenv("DBPassword"),
}
database.Open(c)
database.InitSchema()
defer database.CloseDB()
defer database.Close()
mailer.InitTemplates(nil)
// Perform database migration
if err := database.Migrate(); err != nil {

View file

@ -24,6 +24,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
@ -38,7 +39,14 @@ import (
// InitTestDB establishes connection pool with the test database specified by
// the environment variable configuration and initalizes a new schema
func InitTestDB() {
database.InitDB()
c := database.Config{
Host: os.Getenv("DBHost"),
Port: os.Getenv("DBPort"),
Name: os.Getenv("DBName"),
User: os.Getenv("DBUser"),
Password: os.Getenv("DBPassword"),
}
database.Open(c)
database.InitSchema()
}

View file

@ -35,4 +35,5 @@ set +a
devServerPID=$!
# run server
(cd "$serverPath" && go run main.go)
(cd "$serverPath" && CompileDaemon \
-command="$serverPath/server start")