Skip to content

Commit

Permalink
Add tests for BootstrapToken changes
Browse files Browse the repository at this point in the history
This commit refactors the MySQL tests, and puts some common code into
the storage test library. In particular, we add a new dependency on
"github.com/google/uuid" in order to generate gen4 UUIDs for test
devices. This should make the MySQL tests pass even on a dirty database,
and isolate storage tests a little bit more.

The pgsql changes should also be refactored to use these changes, but I
think that deserves another PR.
  • Loading branch information
Calvin Lee committed Jan 12, 2023
1 parent be1171e commit 0287471
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 74 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
)

require (
github.com/google/uuid v1.3.0
golang.org/x/net v0.0.0-20191009170851-d66e71096ffb // indirect
golang.org/x/text v0.3.0 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/RobotsAndPencils/buford v0.14.0/go.mod h1:F5FvdB/nkMby8Pge6HFpPHgLOeU
github.com/aai/gocrypto v0.0.0-20160205191751-93df0c47f8b8/go.mod h1:nE/FnVUmtbP0EbgMVCUtDrm1+86H47QfJIdcmZb+J1s=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/groob/plist v0.0.0-20220217120414-63fa881b19a5 h1:saaSiB25B1wgaxrshQhurfPKUGJ4It3OxNJUy0rdOjU=
github.com/groob/plist v0.0.0-20220217120414-63fa881b19a5/go.mod h1:itkABA+w2cw7x5nYUS/pLRef6ludkZKOigbROmCTaFw=
Expand Down
90 changes: 90 additions & 0 deletions storage/internal/test/device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package test

import (
"context"
"errors"
"io/ioutil"

"github.com/google/uuid"
"github.com/micromdm/nanomdm/mdm"
"github.com/micromdm/nanomdm/storage"
)

type DeviceInterfaces interface {
storage.CheckinStore
}

type Device struct {
Uuid string
}

func NewDevice() Device {
return Device{Uuid: uuid.NewString()}
}

func (d *Device) EnrollID() *mdm.EnrollID {
return &mdm.EnrollID{Type: mdm.Device, ID: d.Uuid}
}

func loadAuthMsg() (*mdm.Authenticate, error) {
b, err := ioutil.ReadFile("../../mdm/testdata/Authenticate.2.plist")
if err != nil {
return nil, err
}
r, err := mdm.DecodeCheckin(b)
if err != nil {
return nil, err
}
a, ok := r.(*mdm.Authenticate)
if !ok {
return nil, errors.New("not an Authenticate message")
}
return a, nil
}

func loadTokenMsg() (*mdm.TokenUpdate, error) {
b, err := ioutil.ReadFile("../../mdm/testdata/TokenUpdate.2.plist")
if err != nil {
return nil, err
}
r, err := mdm.DecodeCheckin(b)
if err != nil {
return nil, err
}
a, ok := r.(*mdm.TokenUpdate)
if !ok {
return nil, errors.New("not a TokenUpdate message")
}
return a, nil
}

func (d *Device) newMdmReq() *mdm.Request {
return &mdm.Request{
Context: context.Background(),
EnrollID: &mdm.EnrollID{
Type: mdm.Device,
ID: d.Uuid,
},
}
}

func EnrollTestDevice(storage DeviceInterfaces) (Device, error) {
d := NewDevice()
authMsg, err := loadAuthMsg()
if err != nil {
return d, err
}
err = storage.StoreAuthenticate(d.newMdmReq(), authMsg)
if err != nil {
return d, err
}
tokenMsg, err := loadTokenMsg()
if err != nil {
return d, err
}
err = storage.StoreTokenUpdate(d.newMdmReq(), tokenMsg)
if err != nil {
return d, err
}
return d, nil
}
61 changes: 61 additions & 0 deletions storage/mysql/bstoken_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//go:build integration
// +build integration

package mysql

import (
"bytes"
"context"
"encoding/base64"
"testing"

"github.com/micromdm/nanomdm/mdm"
"github.com/micromdm/nanomdm/storage/internal/test"
)

func TestBSToken(t *testing.T) {
if *flDSN == "" {
t.Fatal("MySQL DSN flag not provided to test")
}

storage, err := New(WithDSN(*flDSN), WithDeleteCommands())
if err != nil {
t.Fatal(err)
}

var d test.Device
d, err = test.EnrollTestDevice(storage)
if err != nil {
t.Fatal(err)
}

ctx := context.Background()

t.Run("BSToken nil", func(t *testing.T) {
tok, err := storage.RetrieveBootstrapToken(&mdm.Request{Context: ctx, EnrollID: d.EnrollID()}, nil)
if err != nil {
t.Fatal(err)
}
if tok != nil {
t.Fatal("Token for new device was nonnull")
}
})
t.Run("BSToken set/get", func(t *testing.T) {
data := []byte("test token")
bsToken := mdm.BootstrapToken{BootstrapToken: make([]byte, base64.StdEncoding.EncodedLen(len(data)))}
base64.StdEncoding.Encode(bsToken.BootstrapToken, data)
testReq := &mdm.Request{Context: ctx, EnrollID: d.EnrollID()}
err := storage.StoreBootstrapToken(testReq, &mdm.SetBootstrapToken{BootstrapToken: bsToken})
if err != nil {
t.Fatal(err)
}

tok, err := storage.RetrieveBootstrapToken(testReq, nil)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(bsToken.BootstrapToken, tok.BootstrapToken) {
t.Fatalf("Bootstap tokens disequal after roundtrip: %v!=%v", bsToken, tok)
}
})
}
8 changes: 8 additions & 0 deletions storage/mysql/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:build integration
// +build integration

package mysql

import "flag"

var flDSN = flag.String("dsn", "", "DSN of test MySQL instance")
78 changes: 4 additions & 74 deletions storage/mysql/queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,84 +4,13 @@
package mysql

import (
"context"
"errors"
"flag"
"io/ioutil"
"testing"

"github.com/micromdm/nanomdm/mdm"
"github.com/micromdm/nanomdm/storage/internal/test"

_ "github.com/go-sql-driver/mysql"
)

var flDSN = flag.String("dsn", "", "DSN of test MySQL instance")

func loadAuthMsg() (*mdm.Authenticate, error) {
b, err := ioutil.ReadFile("../../mdm/testdata/Authenticate.2.plist")
if err != nil {
return nil, err
}
r, err := mdm.DecodeCheckin(b)
if err != nil {
return nil, err
}
a, ok := r.(*mdm.Authenticate)
if !ok {
return nil, errors.New("not an Authenticate message")
}
return a, nil
}

func loadTokenMsg() (*mdm.TokenUpdate, error) {
b, err := ioutil.ReadFile("../../mdm/testdata/TokenUpdate.2.plist")
if err != nil {
return nil, err
}
r, err := mdm.DecodeCheckin(b)
if err != nil {
return nil, err
}
a, ok := r.(*mdm.TokenUpdate)
if !ok {
return nil, errors.New("not a TokenUpdate message")
}
return a, nil
}

const deviceUDID = "66ADE930-5FDF-5EC4-8429-15640684C489"

func newMdmReq() *mdm.Request {
return &mdm.Request{
Context: context.Background(),
EnrollID: &mdm.EnrollID{
Type: mdm.Device,
ID: deviceUDID,
},
}
}

func enrollTestDevice(storage *MySQLStorage) error {
authMsg, err := loadAuthMsg()
if err != nil {
return err
}
err = storage.StoreAuthenticate(newMdmReq(), authMsg)
if err != nil {
return err
}
tokenMsg, err := loadTokenMsg()
if err != nil {
return err
}
err = storage.StoreTokenUpdate(newMdmReq(), tokenMsg)
if err != nil {
return err
}
return nil
}

func TestQueue(t *testing.T) {
if *flDSN == "" {
t.Fatal("MySQL DSN flag not provided to test")
Expand All @@ -92,13 +21,14 @@ func TestQueue(t *testing.T) {
t.Fatal(err)
}

err = enrollTestDevice(storage)
var d test.Device
d, err = test.EnrollTestDevice(storage)
if err != nil {
t.Fatal(err)
}

t.Run("WithDeleteCommands()", func(t *testing.T) {
test.TestQueue(t, deviceUDID, storage)
test.TestQueue(t, d.Uuid, storage)
})

storage, err = New(WithDSN(*flDSN))
Expand All @@ -107,6 +37,6 @@ func TestQueue(t *testing.T) {
}

t.Run("normal", func(t *testing.T) {
test.TestQueue(t, deviceUDID, storage)
test.TestQueue(t, d.Uuid, storage)
})
}

0 comments on commit 0287471

Please sign in to comment.