mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-13 14:05:42 +08:00
update device datastore
This commit is contained in:
@@ -23,9 +23,10 @@ var (
|
||||
dep_profile_assign_time,
|
||||
dep_profile_push_time,
|
||||
dep_profile_assigned_date,
|
||||
dep_profile_assigned_by
|
||||
dep_profile_assigned_by,
|
||||
dep_device
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||
ON CONFLICT (serial_number)
|
||||
DO UPDATE SET
|
||||
model = $2,
|
||||
@@ -37,7 +38,8 @@ var (
|
||||
dep_profile_assign_time = $8,
|
||||
dep_profile_push_time = $9,
|
||||
dep_profile_assigned_date = $10,
|
||||
dep_profile_assigned_by = $11
|
||||
dep_profile_assigned_by = $11,
|
||||
dep_device = $12
|
||||
RETURNING device_uuid;`
|
||||
|
||||
authenticateMDM = `INSERT INTO devices (
|
||||
@@ -62,12 +64,21 @@ var (
|
||||
imei=$7,
|
||||
meid=$8
|
||||
RETURNING device_uuid;`
|
||||
|
||||
selectDevicesStmt = `SELECT device_uuid,
|
||||
udid,
|
||||
serial_number,
|
||||
dep_profile_status,
|
||||
model,
|
||||
workflow_uuid
|
||||
FROM devices`
|
||||
)
|
||||
|
||||
// Datastore manages devices in a database
|
||||
type Datastore interface {
|
||||
New(src string, d *Device) (string, error)
|
||||
GetDeviceByUDID(udid string, fields ...string) (*Device, error)
|
||||
Devices(params ...interface{}) ([]Device, error)
|
||||
}
|
||||
|
||||
type pgStore struct {
|
||||
@@ -97,6 +108,7 @@ func (store pgStore) New(src string, d *Device) (string, error) {
|
||||
d.DEPProfilePushTime,
|
||||
d.DEPProfileAssignedDate,
|
||||
d.DEPProfileAssignedBy,
|
||||
true,
|
||||
).Scan(&d.UUID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -123,6 +135,38 @@ func (store pgStore) New(src string, d *Device) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (store pgStore) Devices(params ...interface{}) ([]Device, error) {
|
||||
stmt := selectDevicesStmt
|
||||
stmt = addWhereFilters(stmt, params...)
|
||||
var devices []Device
|
||||
err := store.Select(&devices, stmt)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "pgStore Devices")
|
||||
}
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
// 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, 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, ",")
|
||||
stmt = fmt.Sprintf("%s WHERE %s", stmt, whereFilter)
|
||||
}
|
||||
return stmt
|
||||
}
|
||||
|
||||
//NewDB creates a Datastore
|
||||
func NewDB(driver, conn string, logger kitlog.Logger) (Datastore, error) {
|
||||
switch driver {
|
||||
@@ -157,7 +201,7 @@ func migrate(db *sqlx.DB) {
|
||||
CREATE TABLE IF NOT EXISTS devices (
|
||||
device_uuid uuid PRIMARY KEY
|
||||
DEFAULT uuid_generate_v4(),
|
||||
udid text,
|
||||
udid text NOT NULL DEFAULT '',
|
||||
serial_number text,
|
||||
os_version text,
|
||||
model text,
|
||||
@@ -178,6 +222,8 @@ func migrate(db *sqlx.DB) {
|
||||
apple_mdm_topic text,
|
||||
apple_push_magic text,
|
||||
mdm_enrolled boolean,
|
||||
workflow_uuid text NOT NULL DEFAULT '',
|
||||
dep_device boolean,
|
||||
awaiting_configuration boolean
|
||||
);
|
||||
CREATE UNIQUE INDEX serial_idx ON devices (serial_number);`
|
||||
|
||||
@@ -18,10 +18,19 @@ func TestNewDB(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertFetch(t *testing.T) {
|
||||
func TestRetrieveDevices(t *testing.T) {
|
||||
ds := datastore(t)
|
||||
defer teardown()
|
||||
addTestDevices(t, ds)
|
||||
|
||||
_, err := ds.Devices()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func addTestDevices(t *testing.T, ds Datastore) {
|
||||
now := time.Now()
|
||||
var devicetests = []struct {
|
||||
in Device
|
||||
}{
|
||||
@@ -56,7 +65,62 @@ func TestInsertFetch(t *testing.T) {
|
||||
Description: "It's a tablet",
|
||||
Color: "pink",
|
||||
AssetTag: "foo",
|
||||
DEPProfileAssignTime: time.Now(),
|
||||
DEPProfileAssignTime: &now,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range devicetests {
|
||||
uuid, err := ds.New("fetch", &tt.in)
|
||||
if err != nil {
|
||||
t.Log("failed at", tt.in.SerialNumber)
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(uuid) != 36 {
|
||||
t.Errorf("newdevice fetch: expected uuid got %q", uuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestInsertFetch(t *testing.T) {
|
||||
ds := datastore(t)
|
||||
defer teardown()
|
||||
|
||||
now := time.Now()
|
||||
var devicetests = []struct {
|
||||
in Device
|
||||
}{
|
||||
{
|
||||
Device{
|
||||
SerialNumber: "DEADBEEF123A",
|
||||
Model: "Macbook",
|
||||
Description: "It's a laptop",
|
||||
Color: "red",
|
||||
},
|
||||
},
|
||||
{
|
||||
Device{
|
||||
SerialNumber: "DEADBEEF123A",
|
||||
Model: "Macbook",
|
||||
Description: "It's a laptop",
|
||||
Color: "red",
|
||||
},
|
||||
},
|
||||
{
|
||||
Device{
|
||||
SerialNumber: "DEADBEEF123B",
|
||||
Model: "Macbook",
|
||||
Description: "It's a laptop",
|
||||
Color: "blue",
|
||||
},
|
||||
},
|
||||
{
|
||||
Device{
|
||||
SerialNumber: "DEADBEEF123C",
|
||||
Model: "iPad",
|
||||
Description: "It's a tablet",
|
||||
Color: "pink",
|
||||
AssetTag: "foo",
|
||||
DEPProfileAssignTime: &now,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -77,6 +141,7 @@ func TestInsertAuthenticate(t *testing.T) {
|
||||
ds := datastore(t)
|
||||
defer teardown()
|
||||
|
||||
var now = time.Now()
|
||||
var devicetests = []struct {
|
||||
in Device
|
||||
}{
|
||||
@@ -129,7 +194,7 @@ func TestInsertAuthenticate(t *testing.T) {
|
||||
Description: "It's a tablet",
|
||||
Color: "pink",
|
||||
AssetTag: "foo",
|
||||
DEPProfileAssignTime: time.Now(),
|
||||
DEPProfileAssignTime: &now,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -149,6 +214,7 @@ func TestInsertAuthenticate(t *testing.T) {
|
||||
func TestGetDeviceByUDID(t *testing.T) {
|
||||
ds := datastore(t)
|
||||
defer teardown()
|
||||
var now = time.Now()
|
||||
var devicetests = []struct {
|
||||
in Device
|
||||
}{
|
||||
@@ -205,7 +271,7 @@ func TestGetDeviceByUDID(t *testing.T) {
|
||||
Description: "It's a tablet",
|
||||
Color: "pink",
|
||||
AssetTag: "foo",
|
||||
DEPProfileAssignTime: time.Now(),
|
||||
DEPProfileAssignTime: &now,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
type Device struct {
|
||||
// Primary key is UUID
|
||||
UUID string `json:"uuid" db:"device_uuid"`
|
||||
UDID string `json:"udid"`
|
||||
UDID string `json:"udid,omitempty"`
|
||||
SerialNumber string `json:"serial_number,omitempty" db:"serial_number,omitempty"`
|
||||
OSVersion string `json:"os_version,omitempty" db:"os_version,omitempty"`
|
||||
BuildVersion string `json:"build_version,omitempty" db:"build_version,omitempty"`
|
||||
@@ -26,7 +26,7 @@ type Device struct {
|
||||
Token string `json:"token,omitempty" db:"apple_mdm_token,omitempty"`
|
||||
UnlockToken string `json:"unlock_token,omitempty" db:"unlock_token,omitempty"`
|
||||
Enrolled bool `json:"enrolled,omitempty" db:"mdm_enrolled,omitempty"`
|
||||
Workflow string `json:"workflow,omitempty" db:"workflow_uuid"`
|
||||
Workflow string `json:"workflow,omitempty" db:"workflow_uuid,omitempty"`
|
||||
DEPDevice bool `json:"dep_device,omitempty" db:"dep_device,omitempty"`
|
||||
Description string `json:"description,omitempty" db:"description"`
|
||||
Model string `json:"model,omitempty" db:"model"`
|
||||
@@ -34,10 +34,10 @@ type Device struct {
|
||||
AssetTag string `json:"asset_tag,omitempty" db:"asset_tag"`
|
||||
DEPProfileStatus DEPProfileStatus `json:"dep_profile_status,omitempty" db:"dep_profile_status"`
|
||||
DEPProfileUUID string `json:"dep_profile_uuid,omitempty" db:"dep_profile_uuid"`
|
||||
DEPProfileAssignTime time.Time `json:"dep_profile_assign_time,omitempty" db:"dep_profile_assign_time"`
|
||||
DEPProfilePushTime time.Time `json:"dep_profile_push_time,omitempty" db:"dep_profile_push_time"`
|
||||
DEPProfileAssignedDate time.Time `json:"dep_profile_assigned_date" db:"dep_profile_assigned_date"`
|
||||
DEPProfileAssignedBy string `json:"dep_profile_assigned_by" db:"dep_profile_assigned_by"`
|
||||
DEPProfileAssignTime *time.Time `json:"dep_profile_assign_time,omitempty" db:"dep_profile_assign_time"`
|
||||
DEPProfilePushTime *time.Time `json:"dep_profile_push_time,omitempty" db:"dep_profile_push_time"`
|
||||
DEPProfileAssignedDate *time.Time `json:"dep_profile_assigned_date,omitempty" db:"dep_profile_assigned_date"`
|
||||
DEPProfileAssignedBy string `json:"dep_profile_assigned_by,omitempty" db:"dep_profile_assigned_by"`
|
||||
}
|
||||
|
||||
// DEPProfileStatus is the status of the DEP Profile
|
||||
@@ -53,7 +53,12 @@ const (
|
||||
)
|
||||
|
||||
// Value implements Valuer from database/sql
|
||||
func (status DEPProfileStatus) Value() (driver.Value, error) { return string(status), nil }
|
||||
func (status DEPProfileStatus) Value() (driver.Value, error) {
|
||||
if status == "" {
|
||||
return "empty", nil
|
||||
}
|
||||
return string(status), nil
|
||||
}
|
||||
|
||||
// Scan implements Scanner from database/sql
|
||||
func (status *DEPProfileStatus) Scan(value interface{}) error {
|
||||
@@ -62,7 +67,7 @@ func (status *DEPProfileStatus) Scan(value interface{}) error {
|
||||
return nil
|
||||
}
|
||||
if sv, err := driver.String.ConvertValue(value); err == nil {
|
||||
if v, ok := sv.(string); ok {
|
||||
if v, ok := sv.([]byte); ok {
|
||||
*status = DEPProfileStatus(v)
|
||||
return nil
|
||||
}
|
||||
@@ -82,9 +87,9 @@ func NewFromDEP(dd dep.Device) *Device {
|
||||
AssetTag: dd.AssetTag,
|
||||
DEPProfileStatus: DEPProfileStatus(dd.ProfileStatus),
|
||||
DEPProfileUUID: dd.ProfileUUID,
|
||||
DEPProfileAssignTime: dd.ProfileAssignTime,
|
||||
DEPProfilePushTime: dd.ProfilePushTime,
|
||||
DEPProfileAssignedDate: dd.DeviceAssignedDate,
|
||||
DEPProfileAssignTime: &dd.ProfileAssignTime,
|
||||
DEPProfilePushTime: &dd.ProfilePushTime,
|
||||
DEPProfileAssignedDate: &dd.DeviceAssignedDate,
|
||||
DEPProfileAssignedBy: dd.DeviceAssignedBy,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
var (
|
||||
// ErrEmptyRequest is returned if the request body is empty
|
||||
errEmptyRequest = errors.New("request must contain a profile identifier")
|
||||
errEmptyRequest = errors.New("request must contain all required fields")
|
||||
errBadRouting = errors.New("inconsistent mapping between route and handler (programmer error)")
|
||||
)
|
||||
|
||||
57
management/endpoint_workflow.go
Normal file
57
management/endpoint_workflow.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package management
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/micromdm/micromdm/workflow"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type addWorkflowRequest struct {
|
||||
*workflow.Workflow
|
||||
}
|
||||
|
||||
type addWorkflowResponse struct {
|
||||
*workflow.Workflow
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r addWorkflowResponse) status() int { return http.StatusCreated }
|
||||
|
||||
func (r addWorkflowResponse) error() error { return r.Err }
|
||||
|
||||
func makeAddWorkflowEndpoint(svc Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(addWorkflowRequest)
|
||||
wf, err := svc.AddWorkflow(req.Workflow)
|
||||
return addWorkflowResponse{Err: err, Workflow: wf}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type listWorkflowsRequest struct{}
|
||||
|
||||
type listWorkflowsResponse struct {
|
||||
workflows []workflow.Workflow
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r listWorkflowsResponse) error() error { return r.Err }
|
||||
|
||||
func (r listWorkflowsResponse) encodeList(w http.ResponseWriter) error {
|
||||
jsn, err := json.MarshalIndent(r.workflows, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Write(jsn)
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeListWorkflowsEndpoint(svc Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
workflows, err := svc.Workflows()
|
||||
return listWorkflowsResponse{Err: err, workflows: workflows}, nil
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,15 @@ var ErrNotFound = errors.New("not found")
|
||||
|
||||
// Service is the interface that provides methods for managing devices
|
||||
type Service interface {
|
||||
// profiles
|
||||
AddProfile(prf *workflow.Profile) (*workflow.Profile, error)
|
||||
Profiles() ([]workflow.Profile, error)
|
||||
Profile(uuid string) (*workflow.Profile, error)
|
||||
DeleteProfile(uuid string) error
|
||||
// workflows
|
||||
AddWorkflow(wf *workflow.Workflow) (*workflow.Workflow, error)
|
||||
Workflows() ([]workflow.Workflow, error)
|
||||
// dep
|
||||
FetchDEPDevices() error
|
||||
}
|
||||
|
||||
@@ -73,6 +78,15 @@ func (svc service) FetchDEPDevices() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// workflows svc
|
||||
func (svc service) AddWorkflow(wf *workflow.Workflow) (*workflow.Workflow, error) {
|
||||
return svc.workflows.CreateWorkflow(wf)
|
||||
}
|
||||
|
||||
func (svc service) Workflows() ([]workflow.Workflow, error) {
|
||||
return svc.workflows.Workflows()
|
||||
}
|
||||
|
||||
// NewService creates a management service
|
||||
func NewService(ds device.Datastore, ws workflow.Datastore, dc dep.Client) Service {
|
||||
return &service{
|
||||
|
||||
@@ -59,13 +59,33 @@ func ServiceHandler(ctx context.Context, svc Service, logger kitlog.Logger) http
|
||||
opts...,
|
||||
)
|
||||
|
||||
addWorkflowHandler := kithttp.NewServer(
|
||||
ctx,
|
||||
makeAddWorkflowEndpoint(svc),
|
||||
decodeAddWorkflowRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
)
|
||||
listWorkflowsHandler := kithttp.NewServer(
|
||||
ctx,
|
||||
makeListWorkflowsEndpoint(svc),
|
||||
decodeListWorkflowsRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
)
|
||||
|
||||
r := mux.NewRouter()
|
||||
|
||||
// dep
|
||||
r.Handle("/management/v1/devices/fetch", fetchDEPHandler).Methods("POST")
|
||||
// profiles
|
||||
r.Handle("/management/v1/profiles", addProfileHandler).Methods("POST")
|
||||
r.Handle("/management/v1/profiles", listProfilesHandler).Methods("GET")
|
||||
r.Handle("/management/v1/profiles/{uuid}", showProfileHandler).Methods("GET")
|
||||
r.Handle("/management/v1/profiles/{uuid}", deleteProfileHandler).Methods("DELETE")
|
||||
// workflows
|
||||
r.Handle("/management/v1/workflows", addWorkflowHandler).Methods("POST")
|
||||
r.Handle("/management/v1/workflows", listWorkflowsHandler).Methods("GET")
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -116,6 +136,23 @@ func decodeDeleteProfileRequest(_ context.Context, r *http.Request) (interface{}
|
||||
return deleteProfileRequest{UUID: uuid}, nil
|
||||
}
|
||||
|
||||
// workflow
|
||||
func decodeAddWorkflowRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
var request addWorkflowRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&request)
|
||||
if err == io.EOF {
|
||||
return nil, errEmptyRequest
|
||||
}
|
||||
if request.Name == "" {
|
||||
return nil, errEmptyRequest
|
||||
}
|
||||
return request, err
|
||||
}
|
||||
|
||||
func decodeListWorkflowsRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
return listWorkflowsRequest{}, nil
|
||||
}
|
||||
|
||||
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
|
||||
if e, ok := response.(errorer); ok && e.error() != nil {
|
||||
encodeError(ctx, e.error(), w)
|
||||
|
||||
@@ -17,6 +17,110 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestAddWorkflowWithProfiles(t *testing.T) {
|
||||
server, svc := newServer(t)
|
||||
defer teardown()
|
||||
defer server.Close()
|
||||
|
||||
profileData := []byte(`{
|
||||
"payload_identifier": "com.micromdm.example2",
|
||||
"data" : "fooProfile"
|
||||
}`)
|
||||
|
||||
pfBody := testAddHTTP("profiles", t, svc, server, profileData, http.StatusCreated)
|
||||
var pf workflow.Profile
|
||||
err := json.NewDecoder(pfBody).Decode(&pf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wf := workflow.Workflow{
|
||||
Name: "test_workflow",
|
||||
Profiles: []workflow.Profile{pf},
|
||||
}
|
||||
wfData, err := json.Marshal(wf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wfBody := testAddHTTP("workflows", t, svc, server, wfData, http.StatusCreated)
|
||||
|
||||
var returned workflow.Workflow
|
||||
err = json.NewDecoder(wfBody).Decode(&returned)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !returned.HasProfile(pf.PayloadIdentifier) {
|
||||
t.Fatal("returned workflow must have profile")
|
||||
}
|
||||
}
|
||||
|
||||
// create some workflows to be used by tests
|
||||
func addWorkflows(t *testing.T, server *httptest.Server, svc Service) []workflow.Workflow {
|
||||
profileData := []byte(`{
|
||||
"payload_identifier": "com.micromdm.example2",
|
||||
"data" : "fooProfile"
|
||||
}`)
|
||||
|
||||
pfBody := testAddHTTP("profiles", t, svc, server, profileData, http.StatusCreated)
|
||||
var pf workflow.Profile
|
||||
err := json.NewDecoder(pfBody).Decode(&pf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wf := workflow.Workflow{
|
||||
Name: "test_workflow",
|
||||
Profiles: []workflow.Profile{pf},
|
||||
}
|
||||
wfData, err := json.Marshal(wf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wfBody := testAddHTTP("workflows", t, svc, server, wfData, http.StatusCreated)
|
||||
|
||||
var returned workflow.Workflow
|
||||
err = json.NewDecoder(wfBody).Decode(&returned)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return []workflow.Workflow{returned}
|
||||
}
|
||||
|
||||
func TestAddWorkflow(t *testing.T) {
|
||||
server, svc := newServer(t)
|
||||
defer teardown()
|
||||
defer server.Close()
|
||||
|
||||
workflowData := []byte(`{
|
||||
"name": "testWorkflow"
|
||||
}`)
|
||||
|
||||
var addTests = []struct {
|
||||
in []byte
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
in: nil,
|
||||
expected: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
in: workflowData,
|
||||
expected: http.StatusCreated,
|
||||
},
|
||||
{
|
||||
in: workflowData,
|
||||
expected: http.StatusConflict,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range addTests {
|
||||
testAddHTTP("workflows", t, svc, server, tt.in, tt.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteProfile(t *testing.T) {
|
||||
server, svc := newServer(t)
|
||||
defer teardown()
|
||||
@@ -29,7 +133,7 @@ func TestDeleteProfile(t *testing.T) {
|
||||
"data" : "fooProfile"
|
||||
}`)
|
||||
|
||||
testAddHTTP(t, svc, server, profileData, http.StatusCreated)
|
||||
testAddHTTP("profiles", t, svc, server, profileData, http.StatusCreated)
|
||||
profiles := testListHTTP(t, svc, server, http.StatusOK)
|
||||
for _, p := range profiles {
|
||||
testDeleteHTTP(t, svc, server, p.UUID, http.StatusNoContent)
|
||||
@@ -49,7 +153,7 @@ func TestShowProfile(t *testing.T) {
|
||||
testGetHTTP(t, svc, server, "foo", http.StatusBadRequest)
|
||||
testGetHTTP(t, svc, server, "036d339c-4fe4-4d6e-a051-65fafbec8c93", http.StatusNotFound)
|
||||
|
||||
testAddHTTP(t, svc, server, profileData, http.StatusCreated)
|
||||
testAddHTTP("profiles", t, svc, server, profileData, http.StatusCreated)
|
||||
profiles := testListHTTP(t, svc, server, http.StatusOK)
|
||||
for _, p := range profiles {
|
||||
returned := testGetHTTP(t, svc, server, p.UUID, http.StatusOK)
|
||||
@@ -98,6 +202,14 @@ func testGetHTTP(t *testing.T, svc Service, server *httptest.Server, uuid string
|
||||
return &profile
|
||||
}
|
||||
|
||||
func TestListWorkflows(t *testing.T) {
|
||||
server, svc := newServer(t)
|
||||
defer teardown()
|
||||
defer server.Close()
|
||||
addWorkflows(t, server, svc)
|
||||
testListWorkflowsHTTP(t, svc, server, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestListProfiles(t *testing.T) {
|
||||
server, svc := newServer(t)
|
||||
defer teardown()
|
||||
@@ -108,7 +220,7 @@ func TestListProfiles(t *testing.T) {
|
||||
"data" : "fooProfile"
|
||||
}`)
|
||||
|
||||
testAddHTTP(t, svc, server, profileData, http.StatusCreated)
|
||||
testAddHTTP("profiles", t, svc, server, profileData, http.StatusCreated)
|
||||
testListHTTP(t, svc, server, http.StatusOK)
|
||||
|
||||
}
|
||||
@@ -142,7 +254,7 @@ func TestAddProfile(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range addTests {
|
||||
testAddHTTP(t, svc, server, tt.in, tt.expected)
|
||||
testAddHTTP("profiles", t, svc, server, tt.in, tt.expected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +268,7 @@ func newServer(t *testing.T) (*httptest.Server, Service) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ps, err := workflow.NewDB("postgres", testConn, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -167,6 +280,28 @@ func newServer(t *testing.T) (*httptest.Server, Service) {
|
||||
return server, svc
|
||||
}
|
||||
|
||||
func testListWorkflowsHTTP(t *testing.T, svc Service, server *httptest.Server, expectedStatus int) []workflow.Workflow {
|
||||
client := http.DefaultClient
|
||||
theURL := server.URL + "/management/v1/workflows"
|
||||
resp, err := client.Get(theURL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != expectedStatus {
|
||||
io.Copy(os.Stdout, resp.Body)
|
||||
t.Fatal("expected", expectedStatus, "got", resp.StatusCode)
|
||||
}
|
||||
|
||||
// test decoding the result into a struct
|
||||
var workflows []workflow.Workflow
|
||||
if err := json.NewDecoder(resp.Body).Decode(&workflows); err != nil {
|
||||
t.Log("failed to decode profiles from list response")
|
||||
t.Fatal(err)
|
||||
}
|
||||
return workflows
|
||||
}
|
||||
|
||||
func testListHTTP(t *testing.T, svc Service, server *httptest.Server, expectedStatus int) []workflow.Profile {
|
||||
client := http.DefaultClient
|
||||
theURL := server.URL + "/management/v1/profiles"
|
||||
@@ -189,11 +324,11 @@ func testListHTTP(t *testing.T, svc Service, server *httptest.Server, expectedSt
|
||||
return profiles
|
||||
}
|
||||
|
||||
func testAddHTTP(t *testing.T, svc Service, server *httptest.Server, profile []byte, expectedStatus int) {
|
||||
body := &nopCloser{bytes.NewBuffer(profile)}
|
||||
func testAddHTTP(endpoint string, t *testing.T, svc Service, server *httptest.Server, data []byte, expectedStatus int) io.Reader {
|
||||
body := &nopCloser{bytes.NewBuffer(data)}
|
||||
|
||||
client := http.DefaultClient
|
||||
theURL := server.URL + "/management/v1/profiles"
|
||||
theURL := server.URL + "/management/v1/" + endpoint
|
||||
resp, err := client.Post(theURL, "application/json", body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -203,6 +338,8 @@ func testAddHTTP(t *testing.T, svc Service, server *httptest.Server, profile []b
|
||||
io.Copy(os.Stdout, resp.Body)
|
||||
t.Fatal("expected", expectedStatus, "got", resp.StatusCode)
|
||||
}
|
||||
|
||||
return resp.Body
|
||||
}
|
||||
|
||||
func TestFetchDEPDevices(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user