diff --git a/connect/service.go b/connect/service.go index a40a0a36..71df301f 100644 --- a/connect/service.go +++ b/connect/service.go @@ -142,14 +142,12 @@ func (svc service) ackQueryResponses(req mdm.Response) error { // Acknowledge a response to `InstalledApplicationList`. func (svc service) ackInstalledApplicationList(req mdm.Response) error { - fmt.Println("Acknowledging installed applications") - device, err := svc.devices.GetDeviceByUDID(req.UDID, "device_uuid") if err != nil { return errors.Wrap(err, "getting a device record by udid") } - requestApps := make([]apps.Application, len(req.InstalledApplicationList)) + var requestApps []apps.Application = []apps.Application{} // Update or insert application records that do not exist, returning the UUID so that it can be inserted for // the device sending the response. for _, reqApp := range req.InstalledApplicationList { @@ -171,12 +169,12 @@ func (svc service) ackInstalledApplicationList(req mdm.Response) error { BundleSize: bundleSize, DynamicSize: dynamicSize, } - appUuid, err := svc.apps.New(&newApp) + _, err := svc.apps.New(&newApp) if err != nil { return err } - newApp.UUID = appUuid + //newApp.UUID = appUuid requestApps = append(requestApps, newApp) } @@ -185,15 +183,15 @@ func (svc service) ackInstalledApplicationList(req mdm.Response) error { return errors.Wrap(err, "getting applications by device uuid") } - var deviceRemoved []apps.Application = make([]apps.Application, len(req.InstalledApplicationList)) - var deviceNotRemoved []apps.Application = make([]apps.Application, len(req.InstalledApplicationList)) + var deviceRemoved []apps.Application = []apps.Application{} + var deviceNotRemoved []apps.Application = []apps.Application{} // Check to see whether installed applications exist in the latest response // If they do not, they are added to the removed slice. // TODO: This is a pretty horrible algorithm and I should re-design it at some point. m. - fmt.Println("Determining apps removed") removedouter: for _, deviceApp := range deviceApps { + fmt.Printf("Is app removed? %s\n", deviceApp.Name) for _, app := range requestApps { if deviceApp.Version == app.Version && deviceApp.Name == app.Name { deviceNotRemoved = append(deviceNotRemoved, deviceApp) @@ -207,8 +205,6 @@ removedouter: // Any installed applications that are already represented in the `applications` table AND // allocated to the device in `devices_applications` should be skipped. var updated []apps.Application = make([]apps.Application, len(req.InstalledApplicationList)) - - fmt.Println("Determining apps changed or added") skip: for _, ackApp := range requestApps { for _, app := range deviceNotRemoved { @@ -220,12 +216,10 @@ skip: updated = append(updated, ackApp) } - fmt.Printf("removed %d application(s)\n", len(deviceRemoved)) - fmt.Printf("updated %d application(s)\n", len(updated)) - for _, insertApp := range updated { if err := svc.apps.SaveApplicationByDeviceUUID(device.UUID, &insertApp); err != nil { - fmt.Printf("could not save application, no valid uuid: %s\n", insertApp.Name) + fmt.Println(err) + fmt.Printf("could not save application, no valid uuid: %s, %s\n", insertApp.Name, insertApp.UUID) // return errors.Wrap(err, "saving installed application for a device") } } diff --git a/connect/service_test.go b/connect/service_test.go index 98f93676..1fc0718d 100644 --- a/connect/service_test.go +++ b/connect/service_test.go @@ -1,11 +1,16 @@ package connect import ( + "database/sql" + "github.com/go-kit/kit/log" + "github.com/jmoiron/sqlx" "github.com/micromdm/mdm" "github.com/micromdm/micromdm/applications" "github.com/micromdm/micromdm/device" + "golang.org/x/net/context" + "gopkg.in/DATA-DOG/go-sqlmock.v1" + "os" "testing" - "time" ) type MockDevices struct{} @@ -14,7 +19,9 @@ func (md MockDevices) New(src string, d *device.Device) (string, error) { return "", nil } func (md MockDevices) GetDeviceByUDID(udid string, fields ...string) (*device.Device, error) { - return &device.Device{}, nil + return &device.Device{ + UUID: "00000000-1111-2222-3333-444455556666", + }, nil } func (md MockDevices) GetDeviceByUUID(uuid string, fields ...string) (*device.Device, error) { return &device.Device{}, nil @@ -22,7 +29,7 @@ func (md MockDevices) GetDeviceByUUID(uuid string, fields ...string) (*device.De func (md MockDevices) Devices(params ...interface{}) ([]device.Device, error) { return []device.Device{ { - UUID: "ABCD-EFGH-IJKL", + UUID: "00000000-1111-2222-3333-444455556666", }, }, nil } @@ -30,21 +37,6 @@ func (md MockDevices) Save(msg string, dev *device.Device) error { return nil } -type MockApps struct{} - -func (ma MockApps) New(a *applications.Application) (string, error) { - return "", nil -} -func (ma MockApps) Applications(params ...interface{}) ([]applications.Application, error) { - return []applications.Application{}, nil -} -func (ma MockApps) GetApplicationsByDeviceUUID(deviceUUID string) ([]applications.Application, error) { - return []applications.Application{}, nil -} -func (ma MockApps) SaveApplicationByDeviceUUID(deviceUUID string, app *applications.Application) error { - return nil -} - type MockCmd struct{} func (mc MockCmd) NewCommand(*mdm.CommandRequest) (*mdm.Payload, error) { @@ -57,24 +49,32 @@ func (mc MockCmd) DeleteCommand(deviceUDID, commandUUID string) (int, error) { return 0, nil } -type MockContext struct{} +var ctx context.Context +var appDs applications.Datastore +var db *sql.DB +var mock sqlmock.Sqlmock +var dbx *sqlx.DB +var logger log.Logger -func (mc MockContext) Done() <-chan struct{} { - ch := make(chan struct{}) +func setupServiceTests() { + ctx = context.Background() + db, mock, _ = sqlmock.New() + //if err != nil { + // t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + //} + dbx = sqlx.NewDb(db, "mock") + logger = log.NewLogfmtLogger(os.Stdout) + appDs, _ = applications.NewDatastore(dbx, logger) +} - return ch -} -func (mc MockContext) Err() error { - return nil -} -func (mc MockContext) Deadline() (deadline time.Time, ok bool) { - return time.Now(), true -} -func (mc MockContext) Value(key interface{}) interface{} { - return nil +func teardownServiceTests() { + dbx.Close() } func TestAckQueryResponses(t *testing.T) { + setupServiceTests() + defer teardownServiceTests() + response := mdm.Response{ UDID: "00000000-1111-2222-3333-444455556666", Status: "Acknowledged", @@ -84,14 +84,19 @@ func TestAckQueryResponses(t *testing.T) { } mockDevices := MockDevices{} - mockApps := MockApps{} mockCmd := MockCmd{} - svc := NewService(mockDevices, mockApps, mockCmd) - svc.Acknowledge(MockContext{}, response) + svc := NewService(mockDevices, appDs, mockCmd) + svc.Acknowledge(ctx, response) + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } } func TestAckInstalledApplicationList(t *testing.T) { + setupServiceTests() + defer teardownServiceTests() response := mdm.Response{ UDID: "00000000-1111-2222-3333-444455556666", @@ -114,9 +119,25 @@ func TestAckInstalledApplicationList(t *testing.T) { } mockDevices := MockDevices{} - mockApps := MockApps{} mockCmd := MockCmd{} - svc := NewService(mockDevices, mockApps, mockCmd) - svc.Acknowledge(MockContext{}, response) + // Expect insert applications as new + wifiAppUuidRow := sqlmock.NewRows([]string{"application_uuid"}).AddRow("90000000-1111-2222-3333-444455556666") + mock.ExpectQuery("INSERT INTO applications").WithArgs("Wireless Network Utility", nil, nil, nil, 2416111, 0, nil).WillReturnRows(wifiAppUuidRow) + kcAppUuidRow := sqlmock.NewRows([]string{"application_uuid"}).AddRow("A0000000-1111-2222-3333-444455556666") + mock.ExpectQuery("INSERT INTO applications").WithArgs("Keychain Access", "com.apple.keychainaccess", "9.0", "9.0", 14166172, 0, nil).WillReturnRows(kcAppUuidRow) + + // Expect query for device installed apps + deviceAppsRow := sqlmock.NewRows([]string{"application_uuid", "name"}).AddRow("APP00000-1111-2222-3333-444455556666", "Mock Application") + mock.ExpectQuery("RIGHT JOIN devices_applications").WithArgs("00000000-1111-2222-3333-444455556666").WillReturnRows(deviceAppsRow) + + mock.ExpectExec("INSERT INTO devices_applications").WithArgs("00000000-1111-2222-3333-444455556666", "90000000-1111-2222-3333-444455556666").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("INSERT INTO devices_applications").WithArgs("00000000-1111-2222-3333-444455556666", "A0000000-1111-2222-3333-444455556666").WillReturnResult(sqlmock.NewResult(1, 1)) + + svc := NewService(mockDevices, appDs, mockCmd) + svc.Acknowledge(ctx, response) + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } } diff --git a/connect/transport_test.go b/connect/transport_test.go index c5714b93..0770e28a 100644 --- a/connect/transport_test.go +++ b/connect/transport_test.go @@ -14,10 +14,12 @@ import ( var m *http.ServeMux var respRec *httptest.ResponseRecorder -var ctx context.Context + +//var ctx context.Context var handler http.Handler var kitService Service -var logger log.Logger + +//var logger log.Logger // TODO: Mock services var deviceDB device.Datastore