Functional tests complete for GET, PUT, POST, DELETE

Some major enhancements to client and request
diff --git a/lib/client.js b/lib/client.js
index 06f61dc..b7541b1 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -3,8 +3,7 @@
 var UsergridRequest = require('./request'),
     ok = require('objectkit'),
     helpers = require('../helpers'),
-    config = require('../package.json'),
-    urljoin = require('url-join');
+    url = require('url')
 
 var UsergridClient = function(orgId, appId) {
     var self = this
@@ -13,33 +12,50 @@
         self.appId = appId
         return self;
     } else {
-        throw new Error('orgId and appId must be passed during initialization')
+        throw new Error('\'orgId\' and \'appId\' parameters must be passed during UsergridClient initialization')
     }
 }
 
-UsergridClient.prototype.GET = function(type, options, callback) {
-    callback = callback || options
-    var uri = urljoin(config.usergrid.baseUrl, this.orgId, this.appId, type)
-    return new UsergridRequest('GET', uri, options, callback)
+UsergridClient.prototype.GET = function(type, uuid, callback) {
+    return new UsergridRequest({
+        client: this,
+        method: 'GET',
+        type: type,
+        uuid: typeof uuid === 'string' ? uuid : undefined
+    }, callback || uuid)
 }
 
-UsergridClient.prototype.PUT = function(type, options, callback) {
-    callback = callback || options
-    var uri = urljoin(config.usergrid.baseUrl, this.orgId, this.appId, type)
-    return new UsergridRequest('PUT', uri, options, callback)
+UsergridClient.prototype.PUT = function(type, uuid, body, callback) {
+    if (typeof uuid !== 'string')
+        throw new Error('\'uuid\' (or \'name\') parameter must be defined when making a PUT request')
+    return new UsergridRequest({
+        client: this,
+        method: 'PUT',
+        type: type,
+        uuid: typeof uuid === 'string' ? uuid : undefined,
+        body: typeof body === 'object' ? body : typeof uuid === 'object' ? uuid : undefined
+    }, callback || body || uuid)
 }
 
-UsergridClient.prototype.POST = function(type, options, callback) {
-    callback = callback || options
-    var uri = urljoin(config.usergrid.baseUrl, this.orgId, this.appId, type)
-    return new UsergridRequest('POST', uri, options, callback)
+UsergridClient.prototype.POST = function(type, uuid, body, callback) {
+    return new UsergridRequest({
+        client: this,
+        method: 'POST',
+        type: type,
+        uuid: typeof uuid === 'string' ? uuid : undefined,
+        body: typeof body === 'object' ? body : typeof uuid === 'object' ? uuid : undefined
+    }, callback || body || uuid)
 }
 
-UsergridClient.prototype.DELETE = function(type, options, callback) {
-    callback = callback || options
-    var uri = urljoin(config.usergrid.baseUrl, this.orgId, this.appId, type)
-    return new UsergridRequest('DELETE', uri, options, callback)
+UsergridClient.prototype.DELETE = function(type, uuid, callback) {
+    if (typeof uuid !== 'string')
+        throw new Error('\'uuid\' (or \'name\') parameter must be defined when making a DELETE request')
+    return new UsergridRequest({
+        client: this,
+        method: 'DELETE',
+        type: type,
+        uuid: typeof uuid === 'string' ? uuid : undefined
+    }, callback || uuid)
 }
 
-// Exports
 module.exports = UsergridClient
\ No newline at end of file
diff --git a/lib/request.js b/lib/request.js
index d1ea651..4da51f4 100644
--- a/lib/request.js
+++ b/lib/request.js
@@ -1,25 +1,36 @@
 'use strict'
+
 var extend = require('extend'),
     request = require('request'),
+    config = require('../package.json').config,
     UsergridResponse = require('../lib/response'),
+    util = require('util'),
+    urljoin = require('url-join'),
     ok = require('objectkit')
 
-var UsergridRequest = function(method, uri, options, callback) {
-    
-    if (typeof uri === 'undefined' && ok(options).check(['uri', 'url']) === ok.false) {
-        throw new Error('undefined is not a valid uri or options object.')
-    }
+var UsergridRequest = function(opts, callback) {
 
-    var params = request.initParams(uri, options, callback)
-    params.method = method
+    if (typeof opts.type !== 'string')
+        throw new Error('\'type\' (or \'collection\') parameter must be defined when making a request')
+
+    // uuid and body are optional and not always passed; setting callback to the last defined argument
+    var uri = urljoin(config.usergrid.baseUrl, opts.client.orgId, opts.client.appId, opts.type, (typeof opts.uuid === 'string') ? opts.uuid : "")
+    var params = request.initParams(uri, {
+        headers: {
+            'User-Agent': util.format("usergrid-nodejs/v%s", config.usergrid.version),
+        },
+        body: opts.body
+    }, callback)
+
+    params.method = opts.method
 
     // default to using JSON, since we only ever do that with Usergrid
     params.json = true
-
+    
     request(params, function(error, response) {
-        response = new UsergridResponse(response);
-        params.callback(error, response);
-    });
-};
+        response = new UsergridResponse(response)
+        params.callback(error, response)
+    })
+}
 
-module.exports = UsergridRequest;
\ No newline at end of file
+module.exports = UsergridRequest
\ No newline at end of file
diff --git a/lib/response.js b/lib/response.js
index 33db8af..9104fdf 100644
--- a/lib/response.js
+++ b/lib/response.js
@@ -1,4 +1,5 @@
 'use strict'
+
 var extend = require('extend'),
     ok = require('objectkit'),
     helpers = require('../helpers'),
@@ -12,8 +13,13 @@
             metadata: extend({}, response.body),
             entities: entities
         })
-        response.first = (function() { return entities[0] || undefined })()
-        response.last = (function() { return entities[entities.length - 1] || entities[0] || undefined })()
+        response.first = (function() {
+            return entities[0] || undefined
+        })()
+        response.entity = response.first
+        response.last = (function() {
+            return entities[entities.length - 1] || entities[0] || undefined
+        })()
         delete response.metadata.entities
 
         entities.forEach(function(entity) {
@@ -28,9 +34,23 @@
                 helpers.setImmutable(entity, 'name')
             }
         })
+
+        // if response contains users, add UsergridUser references
+        if (response.first !== undefined && (_(response.first.type.toLowerCase()).startsWith('user'))) {
+            if (response.entities.length === 1) {
+                response.user = response.first
+            } else {
+                response.users = function() {
+                    return this.entities
+                }
+            }
+        }
         response.entities = entities
     } else {
+        response.body.name = response.body.error
+        delete response.body.error
         response.error = response.body
+
     }
     return response;
 }
diff --git a/package.json b/package.json
index 268b839..c6308bb 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,15 @@
 {
     "author": "Brandon Shelley",
+    "config": {
+        "usergrid": {
+            "appId": "sandbox",
+            "baseUrl": "https://api.usergrid.com",
+            "clientId": "YXA6GXSAACS2EeOYd20aP4G6Lw",
+            "clientSecret": "YXA66BeEvgNpJBwc4PAbvZZGTVS_SSw",
+            "orgId": "brandon.apigee",
+            "version": "2.0"
+        }
+    },
     "dependencies": {
         "async": "",
         "extend": "",
@@ -23,7 +33,7 @@
     },
     "description": "The official Node.js SDK for Usergrid",
     "devDependencies": {
-        "should": "3.1.x"
+        "should": ""
     },
     "keywords": [],
     "license": "MIT",
@@ -34,12 +44,5 @@
         "start": "node app.js",
         "test": "mocha tests"
     },
-    "usergrid": {
-        "appId": "sandbox",
-        "baseUrl": "https://api.usergrid.com",
-        "clientId": "YXA6GXSAACS2EeOYd20aP4G6Lw",
-        "clientSecret": "YXA66BeEvgNpJBwc4PAbvZZGTVS_SSw",
-        "orgId": "brandon.apigee"
-    },
     "version": "2.0.0"
 }
\ No newline at end of file
diff --git a/tests/usergrid.js b/tests/usergrid.js
index a7dae92..d7a3405 100644
--- a/tests/usergrid.js
+++ b/tests/usergrid.js
@@ -1,106 +1,159 @@
 'use strict'
 
-var should = require('should')
-var ok = require('objectkit')
+var should = require('should'),
+    config = require('../package.json').config,
+    Usergrid = require('../usergrid'),
+    UsergridClient = require('../lib/client')
 
-var config = require('../package.json')
-var Usergrid = require('../usergrid')
-var UsergridClient = require('../lib/client')
+const _collection = 'tests'
+var _uuid = null
 
 describe('Usergrid', function() {
     it('should fail to initialize without an orgId and appId', function() {
         should(function() {
             Usergrid.initialize()
-        }).throw()
+        }).fail
     })
 
     it('should initialize when using an orgId and appId', function(done) {
         Usergrid.initialize(config.usergrid.orgId, config.usergrid.appId)
         Usergrid.orgId.should.equal(config.usergrid.orgId)
         Usergrid.appId.should.equal(config.usergrid.appId)
-        Usergrid.should.be.ok
+        Usergrid.should.be.an.instanceof(UsergridClient)
         done()
     })
 });
 
 describe('Usergrid.GET', function() {
-    
+
     this.slow(1000)
     this.timeout(6000)
 
-    it('should make a GET call to usergrid and retrieve entities', function(done) {
-        Usergrid.GET('tests', {
-            headers: {
-                'User-Agent': 'request'
-            }
-        }, function(err, usergridResponse) {
-            usergridResponse.statusCode.should.equal(200)
-            usergridResponse.entities.should.be.an.instanceOf(Array)
-            usergridResponse.first.should.be.an.instanceOf(Object)
-            usergridResponse.last.should.be.an.instanceOf(Object)
-            usergridResponse.first.uuid.should.be.an.instanceOf(String)
-            usergridResponse.last.uuid.should.be.an.instanceOf(String)
-            done()
+    describe('make a GET call to Usergrid and retrieve entities', function() {
+        var response
+        before(function(done) {
+            Usergrid.GET(_collection, function(err, usergridResponse) {
+                response = usergridResponse
+                done()
+            })
+        })
+
+        it('should return a 200 ok', function() {
+            response.statusCode.should.equal(200)
+        })
+
+        it('response.entities should be an array', function() {
+            response.entities.should.be.an.Array
+        })
+
+        it('response.first should exist and have a valid uuid', function() {
+            response.first.should.be.an.Object.and.have.property('uuid').with.a.lengthOf(36)
+        })
+
+        it('response.entity should exist and have a valid uuid', function() {
+            response.entity.should.be.an.Object.and.have.property('uuid').with.a.lengthOf(36)
+        })
+
+        it('response.last should exist and have a valid uuid', function() {
+            response.last.should.be.an.Object.and.have.property('uuid').with.a.lengthOf(36)
         })
     })
 })
 
-// Usergrid.init('peter', 'frog')
-// var client = new UsergridClient('bob', 'joe')
+describe('Usergrid.POST', function() {
 
+    this.slow(1000)
+    this.timeout(3000)
 
+    describe('make a POST call to Usergrid and create an entity', function() {
 
-// Usergrid.POST("https://api.usergrid.com/brandon.apigee/sandbox/tests", {
-//     headers: {
-//         'User-Agent': 'request'
-//     },
-//     body: {
-//         "this": "that"
-//     }
-// }, function(err, usergridResponse) {
-//     console.log('test4', usergridResponse.entities[0].this);
-// })
+        var response
+        before(function(done) {
+            Usergrid.POST(_collection, {
+                author: 'Sir Arthur Conan Doyle'
+            }, function(err, usergridResponse) {
+                response = usergridResponse
+                _uuid = usergridResponse.entity.uuid
+                done()
+            })
+        })
 
-// Usergrid.GET("https://api.usergrid.com/brandon.apigee/sandbox/tests", {
-//     headers: {
-//         'User-Agent': 'request'
-//     },
-//     qs: {
-//         ql: "where this = 'that'"
-//     }
-// }, function(err, usergridResponse) {
-//     console.log('test5', usergridResponse.entities[0].this);
-// })
+        it('should return a 200 ok', function() {
+            response.statusCode.should.equal(200)
+        })
 
-// // client.GET("https://api.usergrid.com/brandon.apigee/sandbox/tests", {
-// //     headers: {
-// //         'User-Agent': 'request'
-// //     }
-// // }, function(err, usergridResponse) {
-// //     console.log('test1', usergridResponse.entities.length);
-// //     console.log('test2', usergridResponse.first.uuid);
-// //     console.log('test3', usergridResponse.last.uuid);
-// // })
+        it('response.entities should be an array', function() {
+            response.entities.should.be.an.Array.with.a.lengthOf(1)
+        })
 
+        it('response.entity should exist and have a valid uuid', function() {
+            response.entity.should.be.an.Object.and.have.property('uuid').with.a.lengthOf(36)
+        })
 
-// // Usergrid.initialize('bob', 'joe')
+        it('response.entity.author should equal \'Sir Arthur Conan Doyle\'', function() {
+            response.entity.should.have.property('author').equal('Sir Arthur Conan Doyle')
+        })
+    })
+})
 
-// // Usergrid.GET("https://api.usergrid.com/brandon.apigee/sandbox/tests", {
-// //     headers: {
-// //         'User-Agent': 'request'
-// //     }
-// // }, function(err, usergridResponse) {
-// //     console.log('test1', usergridResponse.entities.length);
-// //     console.log('test2', usergridResponse.first.uuid);
-// //     console.log('test3', usergridResponse.last.uuid);
-// // })
+describe('Usergrid.PUT', function() {
 
-// // Usergrid.GET({
-// //     url: "https://api.usergrid.com/brandon.apigee/sandbox/tests",
-// // }, function(err, usergridResponse) {
-// //     console.log('test2', usergridResponse.first.uuid);
-// // })
+    this.slow(1000)
+    this.timeout(3000)
 
-// // Usergrid.GET("https://api.usergrid.com/the100/slack/games", function(err, usergridResponse) {
-// //     console.log('test3', usergridResponse.error);
-// // })
\ No newline at end of file
+    describe('make a PUT call to Usergrid and update an entity', function() {
+
+        var response
+        before(function(done) {
+            Usergrid.PUT(_collection, _uuid, {
+                narrator: 'Peter Doyle'
+            }, function(err, usergridResponse) {
+                response = usergridResponse
+                done()
+            })
+        })
+
+        it('should return a 200 ok', function() {
+            response.statusCode.should.equal(200)
+        })
+
+        it('response.entities should be an array', function() {
+            response.entities.should.be.an.Array.with.a.lengthOf(1)
+        })
+
+        it('response.entity should exist and its uuid should the uuid from the previous POST requets', function() {
+            response.entity.should.be.an.Object.and.have.property('uuid').equal(_uuid)
+        })
+
+        it('response.entity.narrator should equal \'Peter Doyle\'', function() {
+            response.entity.should.have.property('narrator').equal('Peter Doyle')
+        })
+    })
+})
+
+describe('Usergrid.DELETE', function() {
+
+    this.slow(1000)
+    this.timeout(6000)
+
+    describe('make a DELETE call to Usergrid and delete an entity', function() {
+        var response
+        before(function(done) {
+            Usergrid.DELETE(_collection, _uuid, function(err, usergridResponse) {
+                Usergrid.GET(_collection, _uuid, function(err, usergridResponse) {
+                    response = usergridResponse
+                    done()
+                })
+            })
+        })
+
+        it('should return a 200 ok', function() {
+            // This should check for 404, but because of a Usergrid bug, it returns 401 instead of 404.
+            response.statusCode.should.not.equal(200)
+        })
+
+        it('response.error.name should equal \'service_resource_not_found\'', function() {
+            response.error.name.should.equal('service_resource_not_found')
+        })
+    })
+})
\ No newline at end of file
diff --git a/usergrid.js b/usergrid.js
index ee8deff..0975a91 100644
--- a/usergrid.js
+++ b/usergrid.js
@@ -1,7 +1,6 @@
 'use strict'
 
 var UsergridClient = require('./lib/client'),
-    ok = require('objectkit'),
     helpers = require('./helpers'),
     util = require("util")
 
@@ -10,7 +9,7 @@
         Object.setPrototypeOf(Usergrid, new UsergridClient(orgId, appId))
     }
 }
+
 Usergrid.init = Usergrid.initialize
 
-// Exports
 module.exports = Usergrid
\ No newline at end of file