You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by mr...@apache.org on 2016/09/02 16:27:12 UTC

[08/13] usergrid-javascript git commit: Initial commit of Usergrid Javascript SDK into its own repo

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/util/Ajax.js
----------------------------------------------------------------------
diff --git a/lib/modules/util/Ajax.js b/lib/modules/util/Ajax.js
new file mode 100644
index 0000000..4b8a381
--- /dev/null
+++ b/lib/modules/util/Ajax.js
@@ -0,0 +1,99 @@
+/*
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ *
+ *  @author ryan bridges (rbridges@apigee.com)
+ */
+
+//Ajax
+(function() {
+    var name = 'Ajax', global = this, overwrittenName = global[name], exports;
+
+    function partial(){
+        var args = Array.prototype.slice.call(arguments);
+        var fn=args.shift();
+        return fn.bind(this, args);
+    }
+    function Ajax() {
+        this.logger=new global.Logger(name);
+        var self=this;
+        function encode(data) {
+            var result = "";
+            if (typeof data === "string") {
+                result = data;
+            } else {
+                var e = encodeURIComponent;
+                for (var i in data) {
+                    if (data.hasOwnProperty(i)) {
+                        result += '&' + e(i) + '=' + e(data[i]);
+                    }
+                }
+            }
+            return result;
+        }
+        function request(m, u, d) {
+            var p = new Promise(), timeout;
+            self.logger.time(m + ' ' + u);
+            (function(xhr) {
+                xhr.onreadystatechange = function() {
+                    if(this.readyState === 4){
+                        self.logger.timeEnd(m + ' ' + u);
+                        clearTimeout(timeout);
+                        p.done(null, this);
+                    }
+                };
+                xhr.onerror=function(response){
+                    clearTimeout(timeout);
+                    p.done(response, null);
+                };
+                xhr.oncomplete=function(response){
+                    clearTimeout(timeout);
+                    self.logger.timeEnd(m + ' ' + u);
+                    self.info("%s request to %s returned %s", m, u, this.status );
+                };
+                xhr.open(m, u);
+                if (d) {
+                    if("object"===typeof d){
+                        d=JSON.stringify(d);
+                    }
+                    xhr.setRequestHeader("Content-Type", "application/json");
+                    xhr.setRequestHeader("Accept", "application/json");
+                }
+                timeout = setTimeout(function() {
+                    xhr.abort();
+                    p.done("API Call timed out.", null);
+                }, 30000);
+                //TODO stick that timeout in a config variable
+                xhr.send(encode(d));
+            }(new XMLHttpRequest()));
+            return p;
+        }
+        this.request=request;
+        this.get = partial(request,'GET');
+        this.post = partial(request,'POST');
+        this.put = partial(request,'PUT');
+        this.delete = partial(request,'DELETE');
+    }
+    global[name] =  new Ajax();
+    global[name].noConflict = function() {
+        if(overwrittenName){
+            global[name] = overwrittenName;
+        }
+        return exports;
+    };
+    return global[name];
+}());

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/util/Event.js
----------------------------------------------------------------------
diff --git a/lib/modules/util/Event.js b/lib/modules/util/Event.js
new file mode 100644
index 0000000..d826e04
--- /dev/null
+++ b/lib/modules/util/Event.js
@@ -0,0 +1,33 @@
+var UsergridEventable	= function(){
+    throw Error("'UsergridEventable' is not intended to be invoked directly");
+};
+UsergridEventable.prototype	= {
+    bind	: function(event, fn){
+        this._events = this._events || {};
+        this._events[event] = this._events[event]	|| [];
+        this._events[event].push(fn);
+    },
+    unbind	: function(event, fn){
+        this._events = this._events || {};
+        if( event in this._events === false  )	return;
+        this._events[event].splice(this._events[event].indexOf(fn), 1);
+    },
+    trigger	: function(event /* , args... */){
+        this._events = this._events || {};
+        if( event in this._events === false  )	return;
+        for(var i = 0; i < this._events[event].length; i++){
+            this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
+        }
+    }
+};
+UsergridEventable.mixin	= function(destObject){
+    var props	= ['bind', 'unbind', 'trigger'];
+    for(var i = 0; i < props.length; i ++){
+        if(props[i] in destObject.prototype){
+            console.warn("overwriting '"+props[i]+"' on '"+destObject.name+"'.");
+            console.warn("the previous version can be found at '_"+props[i]+"' on '"+destObject.name+"'.");
+            destObject.prototype['_'+props[i]]=destObject.prototype[props[i]];
+        }
+        destObject.prototype[props[i]]	= UsergridEventable.prototype[props[i]];
+    }
+};

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/util/Logger.js
----------------------------------------------------------------------
diff --git a/lib/modules/util/Logger.js b/lib/modules/util/Logger.js
new file mode 100644
index 0000000..c3cf579
--- /dev/null
+++ b/lib/modules/util/Logger.js
@@ -0,0 +1,89 @@
+/*
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ *
+ *  @author ryan bridges (rbridges@apigee.com)
+ */
+
+//Logger
+(function() {
+    var name = 'Logger', global = this, overwrittenName = global[name], exports;
+    /* logging */
+    function Logger(name) {
+        this.logEnabled = true;
+        this.init(name, true);
+    }
+    Logger.METHODS=[
+        "log", "error", "warn", "info", "debug", "assert", "clear", "count",
+        "dir", "dirxml", "exception", "group", "groupCollapsed", "groupEnd",
+        "profile", "profileEnd", "table", "time", "timeEnd", "trace"
+    ];
+    Logger.prototype.init=function(name, logEnabled){
+        this.name=name||"UNKNOWN";
+        this.logEnabled=logEnabled||true;
+        var addMethod=function(method){this[method]=this.createLogMethod(method);}.bind(this);
+        Logger.METHODS.forEach(addMethod);
+    };
+    Logger.prototype.createLogMethod=function(method){
+        return Logger.prototype.log.bind(this, method);
+    };
+    Logger.prototype.prefix=function(method, args){
+        var prepend='['+method.toUpperCase()+']['+name+"]:\t";
+        if(['log', 'error', 'warn', 'info'].indexOf(method)!==-1){
+            if("string"===typeof args[0]){
+                args[0]=prepend+args[0];
+            }else{
+                args.unshift(prepend);
+            }
+        }
+        return args;
+    };
+    Logger.prototype.log=function(){
+        var args=[].slice.call(arguments);
+        method=args.shift();
+        if(Logger.METHODS.indexOf(method)===-1){
+            method="log";
+        }
+        if(!(this.logEnabled && console && console[method]))return;
+        args=this.prefix(method, args);
+        console[method].apply(console, args);
+    };
+    Logger.prototype.setLogEnabled=function(logEnabled){
+        this.logEnabled=logEnabled||true;
+    };
+
+    Logger.mixin	= function(destObject){
+        destObject.__logger=new Logger(destObject.name||"UNKNOWN");
+        var addMethod=function(method){
+            if(method in destObject.prototype){
+                console.warn("overwriting '"+method+"' on '"+destObject.name+"'.");
+                console.warn("the previous version can be found at '_"+method+"' on '"+destObject.name+"'.");
+                destObject.prototype['_'+method]=destObject.prototype[method];
+            }
+            destObject.prototype[method]=destObject.__logger.createLogMethod(method);
+        };
+        Logger.METHODS.forEach(addMethod);
+    };
+    global[name] =  Logger;
+    global[name].noConflict = function() {
+        if(overwrittenName){
+            global[name] = overwrittenName;
+        }
+        return Logger;
+    };
+    return global[name];
+}());

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/util/Promise.js
----------------------------------------------------------------------
diff --git a/lib/modules/util/Promise.js b/lib/modules/util/Promise.js
new file mode 100644
index 0000000..76d0d04
--- /dev/null
+++ b/lib/modules/util/Promise.js
@@ -0,0 +1,101 @@
+/*
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ *
+ *  @author ryan bridges (rbridges@apigee.com)
+ */
+
+//Promise
+(function(global) {
+    var name = 'Promise', overwrittenName = global[name], exports;
+
+        function Promise() {
+            this.complete = false;
+            this.error = null;
+            this.result = null;
+            this.callbacks = [];
+        }
+        Promise.prototype.then = function(callback, context) {
+            var f = function() {
+                return callback.apply(context, arguments);
+            };
+            if (this.complete) {
+                f(this.error, this.result);
+            } else {
+                this.callbacks.push(f);
+            }
+        };
+        Promise.prototype.done = function(error, result) {
+            this.complete = true;
+            this.error = error;
+            this.result = result;
+            if(this.callbacks){
+                for (var i = 0; i < this.callbacks.length; i++) this.callbacks[i](error, result);
+                this.callbacks.length = 0;
+            }
+        };
+        Promise.join = function(promises) {
+            var p = new Promise(),
+                total = promises.length,
+                completed = 0,
+                errors = [],
+                results = [];
+
+            function notifier(i) {
+                return function(error, result) {
+                    completed += 1;
+                    errors[i] = error;
+                    results[i] = result;
+                    if (completed === total) {
+                        p.done(errors, results);
+                    }
+                };
+            }
+            for (var i = 0; i < total; i++) {
+                promises[i]().then(notifier(i));
+            }
+            return p;
+        };
+        Promise.chain = function(promises, error, result) {
+            var p = new Promise();
+            if (promises===null||promises.length === 0) {
+                p.done(error, result);
+            } else {
+                promises[0](error, result).then(function(res, err) {
+                    promises.splice(0, 1);
+                    //self.logger.info(promises.length)
+                    if(promises){
+                        Promise.chain(promises, res, err).then(function(r, e) {
+                            p.done(r, e);
+                        });
+                    }else{
+                        p.done(res, err);
+                    }
+                });
+            }
+            return p;
+        };
+
+    global[name] =  Promise;
+    global[name].noConflict = function() {
+        if(overwrittenName){
+            global[name] = overwrittenName;
+        }
+        return Promise;
+    };
+    return global[name];
+}(this));

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..72e2046
--- /dev/null
+++ b/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "usergrid",
+  "version": "0.11.0",
+  "description": "Detailed instructions follow but if you just want a quick example of how to get started with this SDK, here\u2019s a minimal HTML5 file that shows you how to include & initialize the SDK, as well as how to read & write data from Usergrid with it.",
+  "main": "usergrid.js",
+  "directories": {
+    "example": "examples"
+  },
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "Apache 2.0",
+  "devDependencies": {
+    "grunt": "~0.4.2",
+    "grunt-contrib-clean": "~0.5.0",
+    "grunt-contrib-watch": "~0.5.3",
+    "grunt-contrib-uglify": "~0.2.7",
+    "grunt-blanket-mocha": "~0.3.3",
+    "grunt-contrib-connect": "~0.6.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/tests/mocha/index.html
----------------------------------------------------------------------
diff --git a/tests/mocha/index.html b/tests/mocha/index.html
new file mode 100644
index 0000000..da47564
--- /dev/null
+++ b/tests/mocha/index.html
@@ -0,0 +1,60 @@
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Mocha Tests</title>
+  <link rel="stylesheet" href="../resources/css/mocha.css" />
+  <script src="../resources/js/mocha.js"></script>
+  <script>mocha.setup('bdd')</script>
+  <script src="../resources/js/blanket_mocha.min.js"></script>
+  <script type="text/javascript" src="../../node_modules/grunt-blanket-mocha/support/mocha-blanket.js"></script>
+	<script>
+      function assert(expr, msg) {
+        if (!expr) throw new Error(msg || 'failed');
+      }
+    </script>
+
+  <script src="../../usergrid.js" data-cover></script>
+  <script src="test.js"></script>
+<!-- run mocha -->
+    <script type="text/javascript" charset="utf-8">
+    	var _onload=onload||function(){};
+        onload = function(){
+        	_onload.apply(this, arguments);
+	        mocha.checkLeaks();
+	        mocha.globals(['']);
+	        var runner = mocha.run();
+	        /*runner.on('test end', function(test){
+	          console.log(test.fullTitle());
+	        });*/
+	      };
+    </script>
+
+  <script>
+    if (window.PHANTOMJS) {
+        blanket.options("reporter", "../../node_modules/grunt-blanket-mocha/support/grunt-reporter.js");
+    }
+  </script>
+
+</head>
+<body>
+	<div id="mocha"></div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/tests/mocha/test.js
----------------------------------------------------------------------
diff --git a/tests/mocha/test.js b/tests/mocha/test.js
new file mode 100644
index 0000000..ef4ff54
--- /dev/null
+++ b/tests/mocha/test.js
@@ -0,0 +1,1078 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/*
+	Creates a generic usergrid client with logging and buildCurl disabled
+
+ */
+function getClient() {
+	return new Usergrid.Client({
+		orgName: 'yourorgname',
+		appName: 'sandbox',
+		logging: false, //optional - turn on logging, off by default
+		buildCurl: true //optional - turn on curl commands, off by default
+	});
+}
+/*
+	A convenience function that will test for the presence of an API error
+	and run any number of additional tests
+ */
+function usergridTestHarness(err, data, done, tests, ignoreError) {
+	if (!ignoreError) assert(!err, (err)?err.error_description:"unknown");
+	if (tests) {
+		if ("function" === typeof tests) {
+			tests(err, data);
+		} else if (tests.length) {
+			tests.forEach(function(test) {
+				if ("function" === typeof test) {
+					test(err, data);
+				}
+			})
+		}
+	}
+	done();
+}
+describe('Ajax', function() {
+    var dogName="dog"+Math.floor(Math.random()*10000);
+    var dogData=JSON.stringify({type:"dog",name:dogName});
+    var dogURI='https://api.usergrid.com/yourorgname/sandbox/dogs'
+    it('should POST to a URI',function(done){
+        Ajax.post(dogURI, dogData).then(function(err, data){
+            assert(!err, err);
+            done();
+        })
+    })
+    it('should GET a URI',function(done){
+        Ajax.get(dogURI+'/'+dogName).then(function(err, data){
+            assert(!err, err);
+            done();
+        })
+    })
+    it('should PUT to a URI',function(done){
+        Ajax.put(dogURI+'/'+dogName, {"favorite":true}).then(function(err, data){
+            assert(!err, err);
+            done();
+        })
+    })
+    it('should DELETE a URI',function(done){
+        Ajax.delete(dogURI+'/'+dogName, dogData).then(function(err, data){
+            assert(!err, err);
+            done();
+        })
+    })
+});
+describe('UsergridError', function() {
+    var errorResponse={
+        "error":"service_resource_not_found",
+        "timestamp":1392067967144,
+        "duration":0,
+        "exception":"org.usergrid.services.exceptions.ServiceResourceNotFoundException",
+        "error_description":"Service resource not found"
+    };
+    it('should unmarshal a response from Usergrid into a proper Javascript error',function(done){
+        var error = UsergridError.fromResponse(errorResponse);
+        assert(error.name===errorResponse.error, "Error name not set correctly");
+        assert(error.message===errorResponse.error_description, "Error message not set correctly");
+        done();
+    });
+});
+describe('Usergrid', function(){
+    describe('SDK Version', function(){
+        it('should contain a minimum SDK version',function(){
+            var parts=Usergrid.VERSION.split('.').map(function(i){return i.replace(/^0+/,'')}).map(function(i){return parseInt(i)});
+
+            assert(parts[1]>=10, "expected minor version >=10");
+            assert(parts[1]>10||parts[2]>=8, "expected minimum version >=8");
+        });
+    });
+    describe('Usergrid Request/Response', function() {
+        var dogName="dog"+Math.floor(Math.random()*10000);
+        var dogData=JSON.stringify({type:"dog",name:dogName});
+        var dogURI='https://api.usergrid.com/yourorgname/sandbox/dogs'
+        it('should POST to a URI',function(done){
+            var req=new Usergrid.Request("POST", dogURI, {}, dogData, function(err, response){
+                console.error(err, response);
+                assert(!err, err);
+                assert(response instanceof Usergrid.Response, "Response is not and instance of Usergrid.Response");
+                done();
+            })
+        })
+        it('should GET a URI',function(done){
+            var req=new Usergrid.Request("GET", dogURI+'/'+dogName, {}, null, function(err, response){
+                assert(!err, err);
+                assert(response instanceof Usergrid.Response, "Response is not and instance of Usergrid.Response");
+                done();
+            })
+        })
+        it('should GET an array of entity data from the Usergrid.Response object',function(done){
+            var req=new Usergrid.Request("GET", dogURI, {}, null, function(err, response){
+                assert(!err, err);
+                assert(response instanceof Usergrid.Response, "Response is not and instance of Usergrid.Response");
+                var entities=response.getEntities();
+                assert(entities && entities.length, "Nothing was returned")
+                done();
+            })
+        })
+        it('should GET entity data from the Usergrid.Response object',function(done){
+            var req=new Usergrid.Request("GET", dogURI+'/'+dogName, {}, null, function(err, response){
+                var entity=response.getEntity();
+                assert(!err, err);
+                assert(response instanceof Usergrid.Response, "Response is not and instance of Usergrid.Response");
+                assert(entity, "Nothing was returned")
+                done();
+            })
+        })
+        it('should PUT to a URI',function(done){
+            var req=new Usergrid.Request("PUT", dogURI+'/'+dogName, {}, {favorite:true}, function(err, response){
+                assert(!err, err);
+                assert(response instanceof Usergrid.Response, "Response is not and instance of Usergrid.Response");
+                done();
+            })
+        })
+        it('should DELETE a URI',function(done){
+            var req=new Usergrid.Request("DELETE", dogURI+'/'+dogName, {}, null, function(err, response){
+                assert(!err, err);
+                assert(response instanceof Usergrid.Response, "Response is not and instance of Usergrid.Response");
+                done();
+            })
+        })
+        it('should NOT allow an invalid method',function(done){
+            try{
+                var req=new Usergrid.Request("INVALID", dogURI+'/'+dogName, {}, null, function(err, response){
+                    assert(true, "Should have thrown an UsergridInvalidHTTPMethodError");
+                    done();
+                })
+            }catch(e){
+                assert(e instanceof UsergridInvalidHTTPMethodError, "Error is not and instance of UsergridInvalidHTTPMethodError");
+                done()
+            }
+        })
+        it('should NOT allow an invalid URI',function(done){
+            try{
+                var req=new Usergrid.Request("GET", "://apigee.com", {}, null, function(err, response){
+                    assert(true, "Should have thrown an UsergridInvalidURIError");
+                    done();
+                })
+            }catch(e){
+                assert(e instanceof UsergridInvalidURIError, "Error is not and instance of UsergridInvalidURIError");
+                done()
+            }
+        })
+        it('should return a UsergridError object on an invalid URI',function(done){
+            var req=new Usergrid.Request("GET", dogURI+'/'+dogName+'zzzzz', {}, null, function(err, response){
+                assert(err, "Should have returned an error");
+                assert(response instanceof Usergrid.Response, "Response is not and instance of Usergrid.Response");
+                assert(err instanceof UsergridError, "Error is not and instance of UsergridError");
+                done();
+            })
+        })
+    });
+    describe('Usergrid Client', function() {
+        var client = getClient();
+        describe('Usergrid CRUD request', function() {
+            before(function(done) {
+                this.timeout(10000);
+                //Make sure our dog doesn't already exist
+                client.request({
+                    method: 'DELETE',
+                    endpoint: 'users/fred'
+                }, function(err, data) {
+                    done();
+                });
+            });
+            var options = {
+                method: 'GET',
+                endpoint: 'users'
+            };
+            it('should persist default query parameters', function(done) {
+                //create new client with default params
+                var client=new Usergrid.Client({
+                    orgName: 'yourorgname',
+                    appName: 'sandbox',
+                    logging: false, //optional - turn on logging, off by default
+                    buildCurl: true, //optional - turn on curl commands, off by default
+                    qs:{
+                        test1:'test1',
+                        test2:'test2'
+                    }
+                });
+                var default_qs=client.getObject('default_qs');
+                assert(default_qs.test1==='test1', "the default query parameters were not persisted");
+                assert(default_qs.test2==='test2', "the default query parameters were not persisted");
+                client.request({
+                    method: 'GET',
+                    endpoint: 'users'
+                }, function(err, data) {
+                    assert(data.params.test2[0]==='test2', "the default query parameters were not sent to the backend");
+                    assert(data.params.test1[0]==='test1', "the default query parameters were not sent to the backend");
+                    done();
+                });
+            });
+            it('should CREATE a new user', function(done) {
+                client.request({
+                    method: 'POST',
+                    endpoint: 'users',
+                    body: {
+                        username: 'fred',
+                        password: 'secret'
+                    }
+                }, function(err, data) {
+                    usergridTestHarness(err, data, done, [
+                        function(err, data) {
+                            assert(!err)
+                        }
+                    ]);
+                });
+            });
+            it('should RETRIEVE an existing user', function(done) {
+                client.request({
+                    method: 'GET',
+                    endpoint: 'users/fred',
+                    body: {}
+                }, function(err, data) {
+                    usergridTestHarness(err, data, done, [
+
+                        function(err, data) {
+                            assert(true)
+                        }
+                    ]);
+                });
+            });
+            it('should UPDATE an existing user', function(done) {
+                client.request({
+                    method: 'PUT',
+                    endpoint: 'users/fred',
+                    body: {
+                        newkey: 'newvalue'
+                    }
+                }, function(err, data) {
+                    usergridTestHarness(err, data, done, [
+
+                        function(err, data) {
+                            assert(true)
+                        }
+                    ]);
+                });
+            });
+            it('should DELETE the user from the database', function(done) {
+                client.request({
+                    method: 'DELETE',
+                    endpoint: 'users/fred'
+                }, function(err, data) {
+                    usergridTestHarness(err, data, done, [
+
+                        function(err, data) {
+                            assert(true)
+                        }
+                    ]);
+                });
+            });
+        });
+        describe('Usergrid REST', function() {
+            it('should return a list of users', function(done) {
+                client.request({
+                    method: 'GET',
+                    endpoint: 'users'
+                }, function(err, data) {
+                    usergridTestHarness(err, data, done, [
+                        function(err, data) {
+                            assert(data.entities.length>=0, "Request should return at least one user");
+                        }
+                    ]);
+                });
+            });
+            it('should return no entities when an endpoint does not exist', function(done) {
+                client.request({
+                    method: 'GET',
+                    endpoint: 'nonexistantendpoint'
+                }, function(err, data) {
+                    usergridTestHarness(err, data, done, [
+
+                        function(err, data) {
+                            assert(data.entities.length===0, "Request should return no entities");
+                        }
+                    ]);
+                });
+            });
+        });
+        describe('Usergrid convenience methods', function(){
+            before(function(){ client.logout();});
+            it('createEntity',function(done){
+                client.createEntity({type:'dog',name:'createEntityTestDog'}, function(err, response, dog){
+                    console.warn(err, response, dog);
+                    assert(!err, "createEntity returned an error")
+                    assert(dog, "createEntity did not return a dog")
+                    assert(dog.get("name")==='createEntityTestDog', "The dog's name is not 'createEntityTestDog'")
+                    done();
+                })
+            })
+            it('createEntity - existing entity',function(done){
+                    client.createEntity({type:'dog',name:'createEntityTestDog'}, function(err, response, dog){
+                        try{
+                            assert(err, "createEntity should return an error")
+                        }catch(e){
+                            assert(true, "trying to create an entity that already exists throws an error");
+                        }finally{
+                            done();
+                        }
+                    });
+            })
+            var testGroup;
+            it('createGroup',function(done){
+                client.createGroup({path:'dogLovers'},function(err, response, group){
+                        try{
+                            assert(!err, "createGroup returned an error")
+                        }catch(e){
+                            assert(true, "trying to create a group that already exists throws an error");
+                        }finally{
+                            done();
+                        }
+                    /*assert(!err, "createGroup returned an error: "+err);
+                    assert(group, "createGroup did not return a group");
+                    assert(group instanceof Usergrid.Group, "createGroup did not return a Usergrid.Group");
+                    testGroup=group;
+                    done();*/
+                })
+                done();
+            })
+            it('buildAssetURL',function(done){
+                var assetURL='https://api.usergrid.com/yourorgname/sandbox/assets/00000000-0000-0000-000000000000/data';
+                assert(assetURL===client.buildAssetURL('00000000-0000-0000-000000000000'), "buildAssetURL doesn't work")
+                done();
+            })
+            var dogEntity;
+            it('getEntity',function(done){
+                client.getEntity({type:'dog',name:'createEntityTestDog'}, function(err, response, dog){
+                    assert(!err, "createEntity returned an error")
+                    assert(dog, "createEntity returned a dog")
+                    assert(dog.get("uuid")!==null, "The dog's UUID was not returned")
+                    dogEntity=dog;
+                    done();
+                })
+            })
+            it('restoreEntity',function(done){
+                var serializedDog=dogEntity.serialize();
+                var dog=client.restoreEntity(serializedDog);
+                assert(dog, "restoreEntity did not return a dog")
+                assert(dog.get("uuid")===dogEntity.get("uuid"), "The dog's UUID was not the same as the serialized dog")
+                assert(dog.get("type")===dogEntity.get("type"), "The dog's type was not the same as the serialized dog")
+                assert(dog.get("name")===dogEntity.get("name"), "The dog's name was not the same as the serialized dog")
+
+                done();
+            })
+            var dogCollection;
+            it('createCollection',function(done){
+                client.createCollection({type:'dogs'},function(err, response, dogs){
+                    assert(!err, "createCollection returned an error");
+                    assert(dogs, "createCollection did not return a dogs collection");
+                    dogCollection=dogs;
+                    done();
+                })
+            })
+            it('restoreCollection',function(done){
+                var serializedDogs=dogCollection.serialize();
+                var dogs=client.restoreCollection(serializedDogs);
+                console.warn('restoreCollection',dogs, dogCollection);
+                assert(dogs._type===dogCollection._type, "The dog collection type was not the same as the serialized dog collection")
+                assert(dogs._qs==dogCollection._qs, "The query strings do not match")
+                assert(dogs._list.length===dogCollection._list.length, "The collections have a different number of entities")
+                done();
+            })
+            var activityUser;
+            before(function(done){
+                activityUser=new Usergrid.Entity({client:client,data:{"type":"user",'username':"testActivityUser"}});
+                console.warn(activityUser);
+                activityUser.fetch(function(err, data){
+                    console.warn(err, data, activityUser);
+                    if(err){
+                        activityUser.save(function(err, data){
+                            activityUser.set(data);
+                            done();
+                        });
+                    }else{
+                        activityUser.set(data);
+                        done();
+                    }
+                })
+            })
+            it('createUserActivity',function(done){
+                 var options = {
+                   "actor" : {
+                         "displayName" :"Test Activity User",
+                             "uuid" : activityUser.get("uuid"),
+                             "username" : "testActivityUser",
+                             "email" : "usergrid@apigee.com",
+                             "image" : {
+                                     "height" : 80,
+                                     "url" : "http://placekitten.com/80/80",
+                                     "width" : 80
+                             }
+                        },
+                        "verb" : "post",
+                       "content" : "test post for createUserActivity",
+                       "lat" : 48.856614,
+                       "lon" : 2.352222
+                     };
+                client.createUserActivity("testActivityUser", options, function(err, activity){
+                    assert(!err, "createUserActivity returned an error");
+                    assert(activity, "createUserActivity returned no activity object")
+                    done();
+                })
+            })
+            it('createUserActivityWithEntity',function(done){
+                    client.createUserActivityWithEntity(activityUser, "Another test activity with createUserActivityWithEntity", function(err, activity){
+                        assert(!err, "createUserActivityWithEntity returned an error "+err);
+                        assert(activity, "createUserActivityWithEntity returned no activity object")
+                        done();
+                    })
+            })
+            it('getFeedForUser',function(done){
+                client.getFeedForUser('testActivityUser', function(err, data, items){
+                    assert(!err, "getFeedForUser returned an error");
+                    assert(data, "getFeedForUser returned no data object")
+                    assert(items, "getFeedForUser returned no items array")
+                    done();
+                })
+            })
+            var testProperty="____test_item"+Math.floor(Math.random()*10000),
+                testPropertyValue="test"+Math.floor(Math.random()*10000),
+                testPropertyObjectValue={test:testPropertyValue};
+            it('set',function(done){
+                client.set(testProperty, testPropertyValue);
+                done();
+            })
+            it('get',function(done){
+                var retrievedValue=client.get(testProperty);
+                assert(retrievedValue===testPropertyValue, "Get is not working properly");
+                done();
+            })
+            it('setObject',function(done){
+                client.set(testProperty, testPropertyObjectValue);
+                done();
+            })
+            it('getObject',function(done){
+                var retrievedValue=client.get(testProperty);
+                assert(retrievedValue==testPropertyObjectValue, "getObject is not working properly");
+                done();
+            })
+            /*it('setToken',function(done){
+                client.setToken("dummytoken");
+                done();
+            })
+            it('getToken',function(done){
+                assert(client.getToken()==="dummytoken");
+                done();
+            })*/
+            it('remove property',function(done){
+                client.set(testProperty);
+                assert(client.get(testProperty)===null);
+                done();
+            })
+            var newUser;
+            it('signup',function(done){
+                client.signup("newUsergridUser", "Us3rgr1d15Aw3s0m3!", "usergrid@apigee.com", "Another Satisfied Developer", function(err, user){
+                    assert(!err, "signup returned an error");
+                    assert(user, "signup returned no user object")
+                    newUser=user;
+                    done();
+                })
+            })
+            it('login',function(done){
+                client.login("newUsergridUser", "Us3rgr1d15Aw3s0m3!", function(err, data, user){
+                    assert(!err, "login returned an error");
+                    assert(user, "login returned no user object")
+                    done();
+                })
+            })
+            /*it('reAuthenticateLite',function(done){
+                client.reAuthenticateLite(function(err){
+                    assert(!err, "reAuthenticateLite returned an error");
+                    done();
+                })
+            })*/
+            /*it('reAuthenticate',function(done){
+                client.reAuthenticate("usergrid@apigee.com", function(err, data, user, organizations, applications){
+                    assert(!err, "reAuthenticate returned an error");
+                    done();
+                })
+            })*/
+            /*it('loginFacebook',function(done){
+                assert(true, "Not sure how feasible it is to test this with Mocha")
+                done();
+            })*/
+            it('isLoggedIn',function(done){
+                assert(client.isLoggedIn()===true, "isLoggedIn is not detecting that we have logged in.")
+                done();
+            })
+            it('getLoggedInUser',function(done){
+                setTimeout(function(){
+                    client.getLoggedInUser(function(err, data, user){
+                        assert(!err, "getLoggedInUser returned an error");
+                        assert(user, "getLoggedInUser returned no user object")
+                        done();
+                    })
+                },1000);
+            })
+            before(function(done){
+                //please enjoy this musical interlude.
+                setTimeout(function(){done()},1000);
+            })
+            it('logout',function(done){
+                client.logout();
+                assert(null===client.getToken(), "we logged out, but the token still remains.")
+                done();
+            })
+            it('getLoggedInUser',function(done){
+                client.getLoggedInUser(function(err, data, user){
+                    assert(err, "getLoggedInUser should return an error after logout");
+                    assert(user, "getLoggedInUser should not return data after logout")
+                    done();
+                })
+            })
+            it('isLoggedIn',function(done){
+                assert(client.isLoggedIn()===false, "isLoggedIn still returns true after logout.")
+                done();
+            })
+            after(function (done) {
+                client.request({
+                    method: 'DELETE',
+                    endpoint: 'users/newUsergridUser'
+                }, function (err, data) {
+                    done();
+                });
+
+            })
+            it('buildCurlCall',function(done){
+                done();
+            })
+            it('getDisplayImage',function(done){
+                done();
+            })
+            after(function(done){
+                dogEntity.destroy();
+                //dogCollection.destroy();
+                //testGroup.destroy();
+                done();
+            })
+        });
+    });
+    describe('Usergrid Entity', function() {
+        var client = getClient();
+        var dog;
+        before(function(done) {
+            //Make sure our dog doesn't already exist
+            client.request({
+                method: 'DELETE',
+                endpoint: 'dogs/Rocky'
+            }, function(err, data) {
+                assert(true);
+                done();
+            });
+        });
+        it('should CREATE a new dog', function(done) {
+            var options = {
+                type: 'dogs',
+                name: 'Rocky'
+            }
+            dog=new Usergrid.Entity({client:client,data:options});
+            dog.save(function(err, entity) {
+                assert(!err, "dog not created");
+                done();
+            });
+        });
+        it('should RETRIEVE the dog', function(done) {
+            if (!dog) {
+                assert(false, "dog not created");
+                done();
+                return;
+            }
+            //once the dog is created, you can set single properties:
+            dog.fetch(function(err) {
+                assert(!err, "dog not fetched");
+                done();
+            });
+        });
+        it('should UPDATE the dog', function(done) {
+            if (!dog) {
+                assert(false, "dog not created");
+                done();
+                return;
+            }
+            //once the dog is created, you can set single properties:
+            dog.set('breed', 'Dinosaur');
+
+            //the set function can also take a JSON object:
+            var data = {
+                master: 'Fred',
+                state: 'hungry'
+            }
+            //set is additive, so previously set properties are not overwritten
+            dog.set(data);
+            //finally, call save on the object to save it back to the database
+            dog.save(function(err) {
+                assert(!err, "dog not saved");
+                done();
+            });
+        });
+        it('should DELETE the dog', function(done) {
+            if (!dog) {
+                assert(false, "dog not created");
+                done();
+                return;
+            }
+            //once the dog is created, you can set single properties:
+            dog.destroy(function(err) {
+                assert(!err, "dog not removed");
+                done();
+            });
+        });
+    });
+    describe('Usergrid Collections', function() {
+        var client = getClient();
+        var dog, dogs = {};
+
+        before(function(done) {
+            //Make sure our dog doesn't already exist
+            var options = {
+                type: 'dogs',
+                qs: {
+                    limit: 50
+                } //limit statement set to 50
+            }
+
+            client.createCollection(options, function(err, response, dogs) {
+                if (!err) {
+                    assert(!err, "could not retrieve list of dogs: " + dogs.error_description);
+                    //we got 50 dogs, now display the Entities:
+                    //do doggy cleanup
+                    //if (dogs.hasNextEntity()) {
+                    while (dogs.hasNextEntity()) {
+                        //get a reference to the dog
+                        var dog = dogs.getNextEntity();
+                        console.warn(dog);
+                        //notice('removing dog ' + dogname + ' from database');
+                        if(dog === null) continue;
+                        dog.destroy(function(err, data) {
+                            assert(!err, dog.get('name') + " not removed: " + data.error_description);
+                            if (!dogs.hasNextEntity()) {
+                                done();
+                            }
+                        });
+                    }
+                    //} else {
+                    done();
+                    //}
+                }
+            });
+        });
+        it('should CREATE a new dogs collection', function(done) {
+            var options = {
+                client:client,
+                type: 'dogs',
+                qs: {
+                    ql: 'order by index'
+                }
+            }
+            dogs=new Usergrid.Collection(options);
+            assert(dogs!==undefined&&dogs!==null, "could not create dogs collection");
+            done();
+        });
+        it('should CREATE dogs in the collection', function(done) {
+            this.timeout(10000);
+            var totalDogs = 30;
+            Array.apply(0, Array(totalDogs)).forEach(function(x, y) {
+                var dogNum = y + 1;
+                var options = {
+                    type: 'dogs',
+                    name: 'dog' + dogNum,
+                    index: y
+                }
+                dogs.addEntity(options, function(err, dog) {
+                    assert(!err, "dog not created");
+                    if (dogNum === totalDogs) {
+                        done();
+                    }
+                });
+            })
+        });
+        it('should RETRIEVE dogs from the collection', function(done) {
+            while (dogs.hasNextEntity()) {
+                //get a reference to the dog
+                dog = dogs.getNextEntity();
+            }
+            if (done) done();
+        });
+        it('should RETRIEVE the next page of dogs from the collection', function(done) {
+            if (dogs.hasNextPage()) {
+                dogs.getNextPage(function(err) {
+                    loop(done);
+                });
+            } else {
+                done();
+            }
+        });
+        it('should RETRIEVE the previous page of dogs from the collection', function(done) {
+            if (dogs.hasPreviousPage()) {
+                dogs.getPreviousPage(function(err) {
+                    loop(done);
+                });
+            } else {
+                done();
+            }
+        });
+        it('should RETRIEVE an entity by UUID.', function(done) {
+            var uuid=dogs.getFirstEntity().get("uuid")
+            dogs.getEntityByUUID(uuid,function(err, data){
+                assert(!err, "getEntityByUUID returned an error.");
+                assert(uuid==data.get("uuid"), "We didn't get the dog we asked for.");
+                done();
+            })
+        });
+        it('should RETRIEVE the first entity from the collection', function() {
+            assert(dogs.getFirstEntity(), "Could not retrieve the first dog");
+        });
+        it('should RETRIEVE the last entity from the collection', function() {
+            assert(dogs.getLastEntity(), "Could not retrieve the last dog");
+        });
+        it('should reset the paging', function() {
+            dogs.resetPaging();
+            assert(!dogs.hasPreviousPage(), "Could not resetPaging");
+        });
+        it('should reset the entity pointer', function() {
+            dogs.resetEntityPointer();
+            assert(!dogs.hasPrevEntity(), "Could not reset the pointer");
+            assert(dogs.hasNextEntity(), "Dog has no more entities");
+            assert(dogs.getNextEntity(), "Could not retrieve the next dog");
+        });
+        it('should RETRIEVE the next entity from the collection', function() {
+            assert(dogs.hasNextEntity(), "Dog has no more entities");
+            assert(dogs.getNextEntity(), "Could not retrieve the next dog");
+        });
+        it('should RETRIEVE the previous entity from the collection', function() {
+            assert(dogs.getNextEntity(), "Could not retrieve the next dog");
+            assert(dogs.hasPrevEntity(), "Dogs has no previous entities");
+            assert(dogs.getPrevEntity(), "Could not retrieve the previous dog");
+        });
+        it('should DELETE the entities from the collection', function(done) {
+            this.timeout(20000);
+            function remove(){
+                if(dogs.hasNextEntity()){
+                    dogs.destroyEntity(dogs.getNextEntity(),function(err, data){
+                        assert(!err, "Could not destroy dog.");
+                        remove();
+                    })
+                }else if(dogs.hasNextPage()){
+                    dogs.getNextPage();
+                    remove();
+                }else{
+                    done();
+                }
+            }
+            remove();
+        });
+    });
+    describe('Usergrid Counters', function() {
+        var client = getClient();
+        var counter;
+        var MINUTE = 1000 * 60;
+        var HOUR = MINUTE * 60;
+        var time = Date.now() - HOUR;
+
+        it('should CREATE a counter', function(done) {
+            counter = new Usergrid.Counter({
+                client: client,
+                data: {
+                    category: 'mocha_test',
+                    timestamp: time,
+                    name: "test",
+                    counters: {
+                        test: 0,
+                        test_counter: 0
+                    }
+                }
+            });
+            assert(counter, "Counter not created");
+            done();
+        });
+        it('should save a counter', function(done) {
+            counter.save(function(err, data) {
+                assert(!err, data.error_description);
+                done();
+            });
+        });
+        it('should reset a counter', function(done) {
+            time += MINUTE * 10
+            counter.set("timestamp", time);
+            counter.reset({
+                name: 'test'
+            }, function(err, data) {
+                assert(!err, data.error_description);
+                done();
+            });
+        });
+        it("should increment 'test' counter", function(done) {
+            time += MINUTE * 10
+            counter.set("timestamp", time);
+            counter.increment({
+                name: 'test',
+                value: 1
+            }, function(err, data) {
+                assert(!err, data.error_description);
+                done();
+            });
+        });
+        it("should increment 'test_counter' counter by 4", function(done) {
+            time += MINUTE * 10
+            counter.set("timestamp", time);
+            counter.increment({
+                name: 'test_counter',
+                value: 4
+            }, function(err, data) {
+                assert(!err, data.error_description);
+                done();
+            });
+        });
+        it("should decrement 'test' counter", function(done) {
+            time += MINUTE * 10
+            counter.set("timestamp", time);
+            counter.decrement({
+                name: 'test',
+                value: 1
+            }, function(err, data) {
+                assert(!err, data.error_description);
+                done();
+            });
+        });
+        it('should fetch the counter', function(done) {
+            counter.fetch(function(err, data) {
+                assert(!err, data.error_description);
+                done();
+            });
+        });
+        it('should fetch counter data', function(done) {
+            counter.getData({
+                resolution: 'all',
+                counters: ['test', 'test_counter']
+            }, function(err, data) {
+                assert(!err, data.error_description);
+                done();
+            });
+        });
+    });
+    describe('Usergrid Folders and Assets', function() {
+        var client = getClient();
+        var folder,
+            asset,
+            user,
+            image_type,
+            image_url = 'http://placekitten.com/160/90',
+        // image_url="https://api.usergrid.com/yourorgname/sandbox/assets/a4025e7a-8ab1-11e3-b56c-5d3c6e4ca93f/data",
+            test_image,
+            filesystem,
+            file_url,
+            filename = "kitten.jpg",
+            foldername = "kittens",
+            folderpath = '/test/' + Math.round(10000 * Math.random()),
+            filepath = [folderpath, foldername, filename].join('/');
+        before(function(done) {
+            var req = new XMLHttpRequest();
+            req.open('GET', image_url, true);
+            req.responseType = 'blob';
+            req.onload = function() {
+                test_image = req.response;
+                image_type = req.getResponseHeader('Content-Type');
+                done();
+            }
+            req.onerror = function(err) {
+                console.error(err);
+                done();
+            };
+            req.send(null);
+        });
+        before(function(done) {
+            this.timeout(10000);
+            client.request({
+                method: 'GET',
+                endpoint: 'Assets'
+            }, function(err, data) {
+                var assets = [];
+                if(data && data.entities && data.entities.length){
+                    assets.concat(data.entities.filter(function(asset) {
+                        return asset.name === filename
+                    }));
+                }
+                if (assets.length) {
+                    assets.forEach(function(asset) {
+                        client.request({
+                            method: 'DELETE',
+                            endpoint: 'assets/' + asset.uuid
+                        });
+                    });
+                    done();
+                } else {
+                    done();
+                }
+            });
+        });
+        before(function(done) {
+            this.timeout(10000);
+            client.request({
+                method: 'GET',
+                endpoint: 'folders'
+            }, function(err, data) {
+                var folders = [];
+                if(data && data.entities && data.entities.length){
+                    folders.concat(data.entities.filter(function(folder) {
+                        return folder.name === foldername
+                    }));
+                }
+                if (folders.length) {
+                    folders.forEach(function(folder) {
+                        client.request({
+                            method: 'DELETE',
+                            endpoint: 'folders/' + folder.uuid
+                        });
+                    });
+                    done();
+                } else {
+                    done();
+                }
+            });
+        });
+        before(function(done) {
+            this.timeout(10000);
+            user = new Usergrid.Entity({
+                client: client,
+                data: {
+                    type: 'users',
+                    username: 'assetuser'
+                }
+            });
+            user.fetch(function(err, data) {
+                if (err) {
+                    user.save(function() {
+                        done();
+                    })
+                } else {
+                    done();
+                }
+            })
+        });
+        it('should CREATE a folder', function(done) {
+            folder = new Usergrid.Folder({
+                client: client,
+                data: {
+                    name: foldername,
+                    owner: user.get("uuid"),
+                    path: folderpath
+                }
+            }, function(err, response, folder) {
+                assert(!err, err);
+                done();
+            });
+        });
+        it('should CREATE an asset', function(done) {
+            asset = new Usergrid.Asset({
+                client: client,
+                data: {
+                    name: filename,
+                    owner: user.get("uuid"),
+                    path: filepath
+                }
+            }, function(err, response, asset) {
+                if(err){
+                    assert(false, err);
+                }
+                done();
+            });
+        });
+        it('should RETRIEVE an asset', function(done) {
+            asset.fetch(function(err, response, entity){
+                if(err){
+                    assert(false, err);
+                }else{
+                    asset=entity;
+                }
+                done();
+            })
+        });
+        it('should upload asset data', function(done) {
+            this.timeout(5000);
+            asset.upload(test_image, function(err, response, asset) {
+                if(err){
+                    assert(false, err.error_description);
+                }
+                done();
+            });
+        });
+        it('should retrieve asset data', function(done) {
+            this.timeout(5000);
+            asset.download(function(err, response, asset) {
+                if(err){
+                    assert(false, err.error_description);
+                }
+                assert(asset.get('content-type') == test_image.type, "MIME types don't match");
+                assert(asset.get('size') == test_image.size, "sizes don't match");
+                done();
+            });
+        });
+        it('should add the asset to a folder', function(done) {
+            folder.addAsset({
+                asset: asset
+            }, function(err, data) {
+                if(err){
+                    assert(false, err.error_description);
+                }
+                done();
+            })
+        });
+        it('should list the assets from a folder', function(done) {
+            folder.getAssets(function(err, assets) {
+                if(err){
+                    assert(false, err.error_description);
+                }
+                done();
+            })
+        });
+        it('should remove the asset from a folder', function(done) {
+            folder.removeAsset({
+                asset: asset
+            }, function(err, data) {
+                if(err){
+                    assert(false, err.error_description);
+                }
+                done();
+            })
+        });
+        after(function(done) {
+            asset.destroy(function(err, data) {
+                if(err){
+                    assert(false, err.error_description);
+                }
+                done();
+            })
+        });
+        after(function(done) {
+            folder.destroy(function(err, data) {
+                if(err){
+                    assert(false, err.error_description);
+                }
+                done();
+            })
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/tests/qunit/apigee_test.html
----------------------------------------------------------------------
diff --git a/tests/qunit/apigee_test.html b/tests/qunit/apigee_test.html
new file mode 100644
index 0000000..2dae960
--- /dev/null
+++ b/tests/qunit/apigee_test.html
@@ -0,0 +1,31 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>QUnit Example</title>
+  <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.12.0.css">
+</head>
+<body>
+  <div id="qunit"></div>
+  <div id="qunit-fixture"></div>
+  <script src="http://code.jquery.com/qunit/qunit-1.12.0.js"></script>
+  <script src="tests.js"></script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/tests/qunit/tests.js
----------------------------------------------------------------------
diff --git a/tests/qunit/tests.js b/tests/qunit/tests.js
new file mode 100644
index 0000000..1d58b00
--- /dev/null
+++ b/tests/qunit/tests.js
@@ -0,0 +1,20 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+test( "hello test", function() {
+  ok( 1 == "1", "Passed!" );
+});