Remove methods with signature NewDatastore() from datastores and injection of the logger instance into each datastore because groob is a doodoo head :)

Move NewDatastore methods into unit tests
Reinstate NewDB test
Create certificates package including a Certificate type and a datastore.
Began working on a method ackCertificateList in the connect service.
Boilerplate for management service test.
Renamed some tables in certificates migration, hopefully nobody notices.
This commit is contained in:
Mosen
2016-07-19 20:41:08 +10:00
parent db7c43141d
commit 8bc2fc749b
10 changed files with 220 additions and 21 deletions

View File

@@ -9,7 +9,7 @@ import (
"time"
)
// Datastore manages devices in a database
// This Datastore manages a list of known applications, and their relationship to devices.
type Datastore interface {
New(a *Application) (string, error)
Applications(params ...interface{}) ([]Application, error)
@@ -19,11 +19,6 @@ type Datastore interface {
type pgStore struct {
*sqlx.DB
logger kitlog.Logger
}
func NewDatastore(connection *sqlx.DB, logger kitlog.Logger) (Datastore, error) {
return pgStore{DB: connection, logger: logger}, nil
}
func NewDB(driver, conn string, logger kitlog.Logger) (Datastore, error) {

View File

@@ -42,19 +42,22 @@ var appFixtures []Application = []Application{
var logger log.Logger = log.NewNopLogger()
//func TestNewDB(t *testing.T) {
// var logger logger.Logger = logger.NewNopLogger()
// appsDB, err := NewDB("postgres", "host=localhost", logger)
//
// if err != nil {
// t.Error(err)
// }
//
// if _, ok := appsDB.(Datastore); !ok {
// t.Log("Did not get a datastore")
// t.Fail()
// }
//}
func NewDatastore(connection *sqlx.DB, logger log.Logger) (Datastore, error) {
return pgStore{DB: connection, logger: logger}, nil
}
func TestNewDB(t *testing.T) {
appsDB, err := NewDB("postgres", "host=localhost", logger)
if err != nil {
t.Error(err)
}
if _, ok := appsDB.(Datastore); !ok {
t.Log("Did not get a datastore")
t.Fail()
}
}
func TestNewDatastore(t *testing.T) {
db, _, err := sqlmock.New()

View File

@@ -0,0 +1,12 @@
package certificates
import (
"crypto/x509"
)
type Certificate struct {
UUID string `db:"certificate_uuid" json:"uuid"`
Data x509.Certificate `db:"data" json:"data"`
CommonName string `db:"common_name" json:"common_nane"`
IsIdentity bool `db:"is_identity" json:"is_identity"`
}

112
certificates/datastore.go Normal file
View File

@@ -0,0 +1,112 @@
package certificates
import (
"fmt"
kitlog "github.com/go-kit/kit/log"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq" // postgres driver
"github.com/pkg/errors"
"strings"
"time"
)
var (
insertCertificateStmt = `INSERT INTO certificates (
common_name,
data,
is_identity
) VALUES ($1, $2, $3)
RETURNING certificate_uuid;`
selectCertificatesStmt = `SELECT
certificate_uuid,
common_name,
data,
is_identity
FROM certificates`
)
// This Datastore manages a list of certificates assigned to devices.
type Datastore interface {
New(crt *Certificate) (string, error)
Certificates(params ...interface{}) ([]Certificate, error)
}
type pgStore struct {
*sqlx.DB
}
func NewDB(driver, conn string, logger kitlog.Logger) (Datastore, error) {
switch driver {
case "postgres":
db, err := sqlx.Open(driver, conn)
if err != nil {
return nil, errors.Wrap(err, "certificates datastore")
}
var dbError error
maxAttempts := 20
for attempts := 1; attempts <= maxAttempts; attempts++ {
dbError = db.Ping()
if dbError == nil {
break
}
logger.Log("msg", fmt.Sprintf("could not connect to postgres: %v", dbError))
time.Sleep(time.Duration(attempts) * time.Second)
}
if dbError != nil {
return nil, errors.Wrap(dbError, "applications datastore")
}
return pgStore{DB: db}, nil
default:
return nil, errors.New("unknown driver")
}
}
func (store pgStore) New(c *Certificate) (string, error) {
if err := store.QueryRow(insertCertificateStmt, c.CommonName, "", c.IsIdentity).Scan(&c.UUID); err != nil {
return "", err
}
return c.UUID, nil
}
func (store pgStore) Certificates(params ...interface{}) ([]Certificate, error) {
stmt := selectCertificatesStmt
stmt = addWhereFilters(stmt, "OR", params...)
var certificates []Certificate
err := store.Select(&certificates, stmt)
if err != nil {
return nil, errors.Wrap(err, "pgStore Certificates")
}
return certificates, nil
}
// UUID is a filter that can be added as a parameter to narrow down the list of returned results
type UUID struct {
UUID string
}
func (p UUID) where() string {
return fmt.Sprintf("certificate_uuid = '%s'", p.UUID)
}
// whereer is for building args passed into a method which finds resources
type whereer interface {
where() string
}
// add WHERE clause from params
func addWhereFilters(stmt string, separator string, params ...interface{}) string {
var where []string
for _, param := range params {
if f, ok := param.(whereer); ok {
where = append(where, f.where())
}
}
if len(where) != 0 {
whereFilter := strings.Join(where, " "+separator+" ")
stmt = fmt.Sprintf("%s WHERE %s", stmt, whereFilter)
}
return stmt
}

View File

@@ -0,0 +1,41 @@
package certificates
import (
"database/sql"
"github.com/jmoiron/sqlx"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
"testing"
)
var (
db *sql.DB
dbx *sqlx.DB
mock sqlmock.Sqlmock
err error
)
func setup() {
db, mock, err = sqlmock.New()
if err != nil {
panic("an error was not expected when opening a stub database connection")
}
dbx = sqlx.NewDb(db, "mock")
}
func teardown() {
dbx.Close()
}
func NewDatastore(connection *sqlx.DB) (Datastore, error) {
return pgStore{DB: connection}, nil
}
func TestNewDatastore(t *testing.T) {
setup()
defer teardown()
_, err := NewDatastore(dbx)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -49,6 +49,8 @@ func (svc service) Acknowledge(ctx context.Context, req mdm.Response) (int, erro
fmt.Printf("Got an error acknowledging InstalledApplicationList: %v\n", err)
return 0, err
}
case "CertificateList":
return 0, nil
default:
// Need to handle the absence of RequestType in IOS8 devices
if req.QueryResponses.UDID != "" {
@@ -232,3 +234,13 @@ skip:
return nil
}
// Acknowledge a response to `CertificateList`.
func (svc service) ackCertificateList(req mdm.Response) error {
_, err := svc.devices.GetDeviceByUDID(req.UDID, "device_uuid")
if err != nil {
return errors.Wrap(err, "getting a device record by udid")
}
return nil
}

View File

@@ -0,0 +1,23 @@
package management
import "testing"
func svcSetup() {
}
func svcTearDown() {
}
func TestService_InstalledApps(t *testing.T) {
svcSetup()
defer svcTearDown()
svc := NewService(nil, nil, nil, nil, nil)
_, err := svc.InstalledApps("00000000-1111-2222-3333-444455556666")
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1 +0,0 @@
DROP TABLE IF EXISTS certificates;

View File

@@ -0,0 +1 @@
DROP TABLE IF EXISTS devices_certificates;

View File

@@ -1,7 +1,8 @@
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE IF NOT EXISTS certificates (
CREATE TABLE IF NOT EXISTS devices_certificates (
certificate_uuid uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
device_uuid uuid REFERENCES devices(device_uuid) ON DELETE CASCADE,
common_name text NOT NULL,
data BYTEA NOT NULL,
is_identity BOOL DEFAULT false