You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tez.apache.org by sr...@apache.org on 2016/01/20 18:05:58 UTC

[32/50] [abbrv] tez git commit: TEZ-2985. Tez UI 2: Create loader and entity classes (sree)

TEZ-2985. Tez UI 2: Create loader and entity classes (sree)


Project: http://git-wip-us.apache.org/repos/asf/tez/repo
Commit: http://git-wip-us.apache.org/repos/asf/tez/commit/e673284f
Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/e673284f
Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/e673284f

Branch: refs/heads/TEZ-2980
Commit: e673284f1e1df78597e49d5d296b65699dbce4be
Parents: f1d1084
Author: Sreenath Somarajapuram <sr...@apache.org>
Authored: Mon Jan 4 03:25:04 2016 +0530
Committer: Sreenath Somarajapuram <sr...@apache.org>
Committed: Wed Jan 20 22:26:20 2016 +0530

----------------------------------------------------------------------
 TEZ-2980-CHANGES.txt                            |   1 +
 .../src/main/webapp/app/adapters/abstract.js    |  54 ----
 tez-ui2/src/main/webapp/app/adapters/loader.js  |  58 ++++
 tez-ui2/src/main/webapp/app/entities/entity.js  |  65 ++++-
 .../src/main/webapp/app/initializers/loader.js  |  27 ++
 .../src/main/webapp/app/serializers/abstract.js |  26 --
 .../src/main/webapp/app/serializers/loader.js   |  81 ++++++
 tez-ui2/src/main/webapp/app/services/loader.js  | 145 ++++++++++
 .../webapp/tests/unit/adapters/abstract-test.js |  39 ---
 .../webapp/tests/unit/adapters/loader-test.js   | 137 ++++++++++
 .../webapp/tests/unit/entities/entity-test.js   | 139 ++++++++++
 .../tests/unit/initializers/loader-test.js      |  40 +++
 .../tests/unit/serializers/abstract-test.js     |  31 ---
 .../tests/unit/serializers/loader-test.js       | 193 ++++++++++++++
 .../webapp/tests/unit/services/loader-test.js   | 267 +++++++++++++++++++
 15 files changed, 1152 insertions(+), 151 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/TEZ-2980-CHANGES.txt
----------------------------------------------------------------------
diff --git a/TEZ-2980-CHANGES.txt b/TEZ-2980-CHANGES.txt
index da361d6..4cf5c4a 100644
--- a/TEZ-2980-CHANGES.txt
+++ b/TEZ-2980-CHANGES.txt
@@ -6,3 +6,4 @@ ALL CHANGES:
   TEZ-3019. Tez UI 2: Replace BaseURL with Host
   TEZ-2984. Tez UI 2: Create abstract classes
   TEZ-3020. Tez UI 2: Add entity blueprint
+  TEZ-2985. Tez UI 2: Create loader and entity classes

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/app/adapters/abstract.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/adapters/abstract.js b/tez-ui2/src/main/webapp/app/adapters/abstract.js
deleted file mode 100644
index aca0faf..0000000
--- a/tez-ui2/src/main/webapp/app/adapters/abstract.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*global more*/
-
-/**
- * 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.
- */
-
-import Ember from 'ember';
-import DS from 'ember-data';
-
-var MoreString = more.String;
-
-export default DS.RESTAdapter.extend({
-  ajax: function(url, method, hash) {
-    return this._super(url, method, Ember.$.extend(hash || {}, {
-      crossDomain: true,
-      xhrFields: {
-        withCredentials: true
-      }
-    }));
-  },
-  buildURL: function(type, id, record) {
-    var url = this._super(type, undefined, record);
-    return MoreString.fmt(url, record);
-  },
-  findQuery: function(store, type, query) {
-    var record = query.metadata;
-    delete query.metadata;
-
-    return this.ajax(this.buildURL(
-        Ember.String.pluralize(type.typeKey),
-        record.id,
-        Ember.Object.create(record)
-      ),
-      'GET',
-      {
-        data: query
-      }
-    );
-  }
-});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/app/adapters/loader.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/adapters/loader.js b/tez-ui2/src/main/webapp/app/adapters/loader.js
new file mode 100644
index 0000000..d4b502c
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/adapters/loader.js
@@ -0,0 +1,58 @@
+/*global more*/
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+
+var MoreString = more.String;
+
+export default DS.RESTAdapter.extend({
+  _isLoader: true,
+
+  buildURL: function(modelName, id, snapshot, requestType, query, params) {
+    var url = this._super(modelName, id, snapshot, null, query);
+    return params ? MoreString.fmt(url, params) : url;
+  },
+
+  _loaderAjax: function (url, queryParams, nameSpace) {
+    if (this.sortQueryParams && queryParams) {
+      queryParams = this.sortQueryParams(queryParams);
+    }
+
+    // Inject nameSpace
+    return this.ajax(url, 'GET', { data: queryParams }).then(function (data) {
+      return {
+        nameSpace: nameSpace,
+        data: data
+      };
+    });
+  },
+
+  queryRecord: function(store, type, query) {
+    var queryParams = query.params,
+        url = this.buildURL(type.modelName, query.id, null, null, queryParams, query.urlParams);
+    return this._loaderAjax(url, queryParams, query.nameSpace);
+  },
+
+  query: function (store, type, query/*, recordArray*/) {
+    var queryParams = query.params,
+        url = this.buildURL(type.modelName, null, null, 'query', queryParams, query.urlParams);
+    return this._loaderAjax(url, queryParams, query.nameSpace);
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/app/entities/entity.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/entities/entity.js b/tez-ui2/src/main/webapp/app/entities/entity.js
index 3d858c8..4d524fe 100644
--- a/tez-ui2/src/main/webapp/app/entities/entity.js
+++ b/tez-ui2/src/main/webapp/app/entities/entity.js
@@ -1,3 +1,4 @@
+/*global more*/
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,5 +19,67 @@
 
 import Ember from 'ember';
 
-export default Ember.ObjectProxy.extend({
+var MoreObject = more.Object;
+
+export default Ember.Object.extend({
+
+  loadRelations: function (loader, model) {
+    var needsPromise = this.loadNeeds(loader, model);
+
+    if(needsPromise) {
+      return needsPromise.then(function () {
+        return model;
+      });
+    }
+
+    return model;
+  },
+
+  normalizeNeed: function(name, options) {
+    var attrName = name,
+        attrType = name,
+        idKey = options,
+        lazy = false;
+
+    if(typeof options === 'object') {
+      attrType = options.type || attrType;
+      idKey = options.idKey || idKey;
+      if(options.lazy) {
+        lazy = true;
+      }
+    }
+
+    return {
+      name: attrName,
+      type: attrType,
+      idKey: idKey,
+      lazy: lazy
+    };
+  },
+
+  loadNeeds: function (loader, parentModel) {
+    var needLoaders = [],
+        that = this,
+        needs = parentModel.get("needs");
+
+    if(needs) {
+      MoreObject.forEach(needs, function (name, options) {
+        var need = that.normalizeNeed(name, options),
+            needLoader = loader.queryRecord(need.type, parentModel.get(need.idKey));
+
+        needLoader.then(function (model) {
+          parentModel.set(need.name, model);
+        });
+
+        if(!need.lazy) {
+          needLoaders.push(needLoader);
+        }
+      });
+    }
+
+    if(needLoaders.length) {
+      return Ember.RSVP.all(needLoaders);
+    }
+  },
+
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/app/initializers/loader.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/initializers/loader.js b/tez-ui2/src/main/webapp/app/initializers/loader.js
new file mode 100644
index 0000000..2956d2c
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/initializers/loader.js
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+export function initialize(application) {
+  application.inject('route', 'loader', 'service:loader');
+  application.inject('entity', 'loader', 'service:loader');
+}
+
+export default {
+  name: 'loader',
+  initialize
+};

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/app/serializers/abstract.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/serializers/abstract.js b/tez-ui2/src/main/webapp/app/serializers/abstract.js
deleted file mode 100644
index c032c30..0000000
--- a/tez-ui2/src/main/webapp/app/serializers/abstract.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * 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.
- */
-
-import Ember from 'ember';
-import DS from 'ember-data';
-
-export default DS.RESTSerializer.extend({
-  normalize: function(type, hash /*, prop */) {
-    return Ember.JsonMapper.map(hash, this.get('map'));
-  }
-});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/app/serializers/loader.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/serializers/loader.js b/tez-ui2/src/main/webapp/app/serializers/loader.js
new file mode 100644
index 0000000..9c97886
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/serializers/loader.js
@@ -0,0 +1,81 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import DS from 'ember-data';
+
+// TODO - Move to more js
+function mapObject(hash, map) {
+  var mappedObject = Ember.Object.create();
+  for (var key in map) {
+    mappedObject.set(key, Ember.get(hash, map[key]));
+  }
+  return mappedObject;
+}
+
+export default DS.JSONSerializer.extend({
+  _isLoader: true,
+
+  maps: null,
+
+  extractId: function (modelClass, resourceHash) {
+    var id = this._super(modelClass, resourceHash.data),
+        nameSpace = resourceHash.nameSpace;
+
+    if(nameSpace) {
+      return nameSpace + ":" + id;
+    }
+    return id;
+  },
+  extractAttributes: function (modelClass, resourceHash) {
+    var maps = this.get('maps'),
+        data = resourceHash.data;
+    return this._super(modelClass, maps ? mapObject(data, maps) : data);
+  },
+  extractRelationships: function (modelClass, resourceHash) {
+    return this._super(modelClass, resourceHash.data);
+  },
+
+  extractSinglePayload: function (payload) {
+    return payload;
+  },
+  extractArrayPayload: function (payload) {
+    return payload;
+  },
+
+  normalizeSingleResponse: function (store, primaryModelClass, payload, id, requestType) {
+    payload.data = this.extractSinglePayload(payload.data);
+    return this._super(store, primaryModelClass, payload, id, requestType);
+  },
+
+  normalizeArrayResponse: function (store, primaryModelClass, payload, id, requestType) {
+    var nameSpace = payload.nameSpace;
+
+    // convert into a _normalizeResponse friendly format
+    payload = this.extractArrayPayload(payload.data);
+    Ember.assert("Loader expects an array in return for a query", Array.isArray(payload));
+    payload = payload.map(function (item) {
+      return {
+        nameSpace: nameSpace,
+        data: item
+      };
+    });
+
+    return this._super(store, primaryModelClass, payload, id, requestType);
+  }
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/app/services/loader.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/services/loader.js b/tez-ui2/src/main/webapp/app/services/loader.js
new file mode 100644
index 0000000..054a6b5
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/services/loader.js
@@ -0,0 +1,145 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Service.extend({
+
+  nameSpace: '',
+  store: Ember.inject.service('store'),
+  cache: null,
+
+  _setOptions: function (options) {
+    var nameSpace = options.nameSpace;
+    if(nameSpace) {
+      // We need to validate only if nameSpace is passed. Else it would be stored in the global space
+      Ember.assert(`Invalid nameSpace. Please pass a string instead of ${Ember.inspect(nameSpace)}`, typeof nameSpace === 'string');
+      this.set("nameSpace", nameSpace);
+    }
+  },
+
+  init: function (options) {
+    this._super();
+    this._setOptions(options || {});
+    this.set("cache", Ember.Object.create());
+  },
+
+  checkRequisite: function (type) {
+    var store = this.get("store"),
+        adapter = store.adapterFor(type),
+        serializer = store.serializerFor(type);
+
+    Ember.assert(
+      `No loader adapter found for type ${type}. Either extend loader and create a custom adapter or extend ApplicationAdapter from loader.`,
+      adapter && adapter._isLoader
+    );
+    Ember.assert(
+      `No loader serializer found for type ${type}. Either extend loader and create a custom serializer or extend ApplicationSerializer from loader.`,
+      serializer && serializer._isLoader
+    );
+  },
+
+  lookup: function (type, name) {
+    name = Ember.String.dasherize(name);
+    return this.get("container").lookup(type + ":" + name);
+  },
+
+  entityFor: function (entityName) {
+    var entity = this.lookup("entitie", entityName);
+    if(!entity) {
+      entity = this.lookup("entitie", "entity");
+    }
+    entity.name = entityName;
+    return entity;
+  },
+
+  getCacheKey: function (type, query, id) {
+    var parts = [type];
+
+    if(id) {
+      parts.push(id);
+    }
+    if(query) {
+      parts.push(JSON.stringify(query));
+    }
+
+    return parts.join(":");
+  },
+
+  queryRecord: function(type, id, query, urlParams, options) {
+    var entity = this.entityFor(type),
+        cache = this.get("cache"),
+        cacheKey = this.getCacheKey(type, query, id),
+        that = this,
+        record;
+
+    this.checkRequisite(type);
+
+    options = options || {};
+    if(!options.reload) {
+      record = cache.get(cacheKey);
+      if(record) {
+        return record;
+      }
+    }
+
+    record = this.get('store').queryRecord(type, {
+      id: id,
+      nameSpace: this.get('nameSpace'),
+      params: query,
+      urlParams: urlParams
+    }).then(function (record) {
+      return entity.loadRelations(that, record);
+    });
+
+    cache.set(cacheKey, record);
+    return record;
+  },
+  query: function(type, query, urlParams, options) {
+    var entity = this.entityFor(type),
+        cache = this.get("cache"),
+        cacheKey = this.getCacheKey(type, query),
+        that = this,
+        records;
+
+    this.checkRequisite(type);
+
+    options = options || {};
+    if(!options.reload) {
+      records = cache.get(cacheKey);
+      if(records) {
+        return records;
+      }
+    }
+
+    records = this.get('store').query(type, {
+      nameSpace: this.get('nameSpace'),
+      params: query,
+      urlParams: urlParams
+    }).then(function (records) {
+      return Ember.RSVP.all(records.map(function (record) {
+        return entity.loadRelations(that, record);
+      })).then(function () {
+       return records;
+      });
+    });
+
+    cache.set(cacheKey, records);
+    return records;
+  }
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/tests/unit/adapters/abstract-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/adapters/abstract-test.js b/tez-ui2/src/main/webapp/tests/unit/adapters/abstract-test.js
deleted file mode 100644
index 00be0ac..0000000
--- a/tez-ui2/src/main/webapp/tests/unit/adapters/abstract-test.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * 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.
- */
-
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('adapter:abstract', 'Unit | Adapter | abstract', {
-  // Specify the other units that are required for this test.
-  // needs: ['serializer:foo']
-});
-
-test('Basic creation', function(assert) {
-  let adapter = this.subject();
-
-  assert.ok(adapter);
-});
-
-test('buildURL test', function(assert) {
-  let adapter = this.subject();
-
-  assert.equal(adapter.buildURL("{x}/{y}/type", null, {
-    x: "x_x",
-    y: "y_y"
-  }), "/x_x/y_y/types");
-});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/tests/unit/adapters/loader-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/adapters/loader-test.js b/tez-ui2/src/main/webapp/tests/unit/adapters/loader-test.js
new file mode 100644
index 0000000..7b4a2df
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/unit/adapters/loader-test.js
@@ -0,0 +1,137 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('adapter:loader', 'Unit | Adapter | loader', {
+  // Specify the other units that are required for this test.
+  // needs: ['serializer:foo']
+});
+
+test('Basic creation', function(assert) {
+  let adapter = this.subject();
+
+  assert.ok(adapter);
+  assert.ok(adapter._isLoader);
+  assert.ok(adapter.buildURL);
+  assert.ok(adapter._loaderAjax);
+  assert.ok(adapter.queryRecord);
+  assert.ok(adapter.query);
+});
+
+test('buildURL test', function(assert) {
+  let adapter = this.subject();
+
+  assert.equal(adapter.buildURL("dag"), "/dags");
+  assert.equal(adapter.buildURL("dag", "dag1"), "/dags/dag1");
+  assert.equal(adapter.buildURL("{x}dag", "dag1", null, null, null, {x: "x_x"}), "/x_xdags/dag1", "Test for substitution");
+});
+
+test('_loaderAjax test', function(assert) {
+  let adapter = this.subject(),
+      testURL = "/dags",
+      testQueryParams = { x:1 },
+      testRecord = {},
+      testNameSpace = "ns";
+
+  assert.expect(2 + 1 + 2);
+
+  adapter.ajax = function (url, method/*, options*/) {
+
+    assert.equal(url, testURL);
+    assert.equal(method, "GET");
+
+    return Ember.RSVP.resolve(testRecord);
+  };
+
+  adapter.sortQueryParams = function (queryParams) {
+    assert.ok(queryParams, "sortQueryParams was called with query params");
+  };
+
+  adapter._loaderAjax(testURL, testQueryParams, testNameSpace).then(function (data) {
+    assert.equal(data.nameSpace, testNameSpace, "Namespace returned");
+    assert.equal(data.data, testRecord, "Test record returned");
+  });
+});
+
+test('queryRecord test', function(assert) {
+  let adapter = this.subject(),
+      testURL = "/dags",
+      testModel = { modelName: "testModel" },
+      testStore = {},
+      testQuery = {
+        id: "test1",
+        params: {},
+        urlParams: {},
+        nameSpace: "ns"
+      };
+
+  assert.expect(4 + 3);
+
+  adapter.buildURL = function (modelName, id, snapshot, requestType, query, params) {
+    assert.equal(modelName, testModel.modelName);
+    assert.equal(id, testQuery.id);
+    assert.equal(query, testQuery.params);
+    assert.equal(params, testQuery.urlParams);
+
+    return testURL;
+  };
+
+  adapter._loaderAjax = function (url, queryParams, nameSpace) {
+    assert.equal(url, testURL);
+    assert.equal(queryParams, testQuery.params);
+    assert.equal(nameSpace, testQuery.nameSpace);
+  };
+
+  adapter.queryRecord(testStore, testModel, testQuery);
+});
+
+test('query test', function(assert) {
+  let adapter = this.subject(),
+      testURL = "/dags",
+      testModel = { modelName: "testModel" },
+      testStore = {},
+      testQuery = {
+        id: "test1",
+        params: {},
+        urlParams: {},
+        nameSpace: "ns"
+      };
+
+  assert.expect(5 + 3);
+
+  adapter.buildURL = function (modelName, id, snapshot, requestType, query, params) {
+    assert.equal(modelName, testModel.modelName);
+    assert.equal(id, null);
+    assert.equal(requestType, "query");
+    assert.equal(query, testQuery.params);
+    assert.equal(params, testQuery.urlParams);
+
+    return testURL;
+  };
+
+  adapter._loaderAjax = function (url, queryParams, nameSpace) {
+    assert.equal(url, testURL);
+    assert.equal(queryParams, testQuery.params);
+    assert.equal(nameSpace, testQuery.nameSpace);
+  };
+
+  adapter.query(testStore, testModel, testQuery);
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js b/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js
new file mode 100644
index 0000000..23e349d
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js
@@ -0,0 +1,139 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('entitie:entity', 'Unit | Entity | entity', {
+  // Specify the other units that are required for this test.
+  // needs: ['entitie:foo']
+});
+
+test('Basic creation', function(assert) {
+  let adapter = this.subject();
+
+  assert.ok(adapter);
+  assert.ok(adapter.loadRelations);
+  assert.ok(adapter.normalizeNeed);
+  assert.ok(adapter.loadNeeds);
+});
+
+test('loadRelations creation', function(assert) {
+  let adapter = this.subject(),
+      testLoader = {},
+      testModel = {},
+      relationsPromise;
+
+  assert.expect(2 + 1 + 2 + 2);
+
+  // Test model without needs
+  adapter.loadNeeds = function (loader, model) {
+    assert.equal(loader, testLoader);
+    assert.equal(model, testModel);
+
+    return null;
+  };
+  relationsPromise = adapter.loadRelations(testLoader, testModel);
+
+  assert.equal(relationsPromise, testModel, "Model without needs");
+
+  // Test model with needs
+  adapter.loadNeeds = function (loader, model) {
+    assert.equal(loader, testLoader);
+    assert.equal(model, testModel);
+
+    return Ember.RSVP.resolve();
+  };
+  relationsPromise = adapter.loadRelations(testLoader, testModel);
+
+  assert.notEqual(relationsPromise, testModel);
+  relationsPromise.then(function (model) {
+    assert.equal(model, testModel);
+  });
+
+});
+
+test('normalizeNeed creation', function(assert) {
+  let adapter = this.subject();
+
+  assert.deepEqual(adapter.normalizeNeed("app", "appKey"), {
+    name: "app",
+    type: "app",
+    idKey: "appKey",
+    lazy: false
+  }, "Test 1");
+
+  assert.deepEqual(adapter.normalizeNeed( "app", { idKey: "appKey" }), {
+    name: "app",
+    type: "app",
+    idKey: "appKey",
+    lazy: false
+  }, "Test 2");
+
+  assert.deepEqual(adapter.normalizeNeed( "app", { type: "application", idKey: "appKey" }), {
+    name: "app",
+    type: "application",
+    idKey: "appKey",
+    lazy: false
+  }, "Test 3");
+
+  assert.deepEqual(adapter.normalizeNeed( "app", { lazy: true, idKey: "appKey" }), {
+    name: "app",
+    type: "app",
+    idKey: "appKey",
+    lazy: true
+  }, "Test 4");
+});
+
+test('loadNeeds creation', function(assert) {
+  let adapter = this.subject(),
+      loader,
+      testModel = Ember.Object.create({
+        needs: {
+          app: "appID",
+          foo: "fooID"
+        },
+        appID: 1,
+        fooID: 2
+      });
+
+  assert.expect(1 + 2 + 1);
+
+  assert.equal(adapter.loadNeeds(loader, Ember.Object.create()), null, "Model without needs");
+
+  loader = {
+    queryRecord: function (type, id) {
+
+      // Must be called twice, once for each record
+      switch(type) {
+        case "app":
+          assert.equal(id, testModel.get("appID"));
+        break;
+        case "foo":
+          assert.equal(id, testModel.get("fooID"));
+        break;
+      }
+
+      return Ember.RSVP.resolve();
+    }
+  };
+  adapter.loadNeeds(loader, testModel).then(function () {
+    assert.ok(true);
+  });
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/tests/unit/initializers/loader-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/initializers/loader-test.js b/tez-ui2/src/main/webapp/tests/unit/initializers/loader-test.js
new file mode 100644
index 0000000..cc32e92
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/unit/initializers/loader-test.js
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import LoaderInitializer from '../../../initializers/loader';
+import { module, test } from 'qunit';
+
+let application;
+
+module('Unit | Initializer | loader', {
+  beforeEach() {
+    Ember.run(function() {
+      application = Ember.Application.create();
+      application.deferReadiness();
+    });
+  }
+});
+
+// Replace this with your real tests.
+test('it works', function(assert) {
+  LoaderInitializer.initialize(application);
+
+  // you would normally confirm the results of the initializer here
+  assert.ok(true);
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/tests/unit/serializers/abstract-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/serializers/abstract-test.js b/tez-ui2/src/main/webapp/tests/unit/serializers/abstract-test.js
deleted file mode 100644
index 006d69c..0000000
--- a/tez-ui2/src/main/webapp/tests/unit/serializers/abstract-test.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * 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.
- */
-
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('abstract', 'Unit | Serializer | abstract', {
-  // Specify the other units that are required for this test.
-  needs: ['serializer:abstract']
-});
-
-test('it serializes records', function(assert) {
-  let record = this.subject();
-  let serializedRecord = record.serialize();
-
-  assert.ok(serializedRecord);
-});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/tests/unit/serializers/loader-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/serializers/loader-test.js b/tez-ui2/src/main/webapp/tests/unit/serializers/loader-test.js
new file mode 100644
index 0000000..5add84a
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/unit/serializers/loader-test.js
@@ -0,0 +1,193 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('serializer:loader', 'Unit | Serializer | loader', {
+  // Specify the other units that are required for this test.
+  // needs: ['serializer:loader']
+});
+
+test('Basic creation test', function(assert) {
+  let serializer = this.subject();
+
+  assert.ok(serializer);
+  assert.ok(serializer._isLoader);
+
+  assert.ok(serializer.extractId);
+  assert.ok(serializer.extractAttributes);
+  assert.ok(serializer.extractRelationships);
+
+  assert.ok(serializer.extractSinglePayload);
+  assert.ok(serializer.extractArrayPayload);
+
+  assert.ok(serializer.normalizeSingleResponse);
+  assert.ok(serializer.normalizeArrayResponse);
+});
+
+test('extractId test', function(assert) {
+  let serializer = this.subject(),
+    modelClass = {},
+    resourceHash = {
+      nameSpace: "ns",
+      data: {
+        id: 1,
+        entityID: 3
+      }
+    };
+
+  assert.equal(serializer.extractId(modelClass, resourceHash), "ns:1", "With name-space");
+  assert.equal(serializer.extractId(modelClass, { data: {id: 2} }), 2, "Without name-space");
+
+  serializer.primaryKey = "entityID";
+  assert.equal(serializer.extractId(modelClass, resourceHash), "ns:3", "Different primary key");
+});
+
+test('extractAttributes test', function(assert) {
+  let serializer = this.subject(),
+    modelClass = {
+      eachAttribute: function (callback) {
+        callback("id", {type: "string"});
+        callback("appID", {type: "string"});
+        callback("status", {type: "string"});
+      }
+    },
+    resourceHash = {
+      nameSpace: "ns",
+      data: {
+        id: 1,
+        appID: 2,
+        applicationID: 3,
+        info: {
+          status: "SUCCESS"
+        }
+      }
+    };
+
+  assert.deepEqual(serializer.extractAttributes(modelClass, resourceHash), {
+    id: 1,
+    appID: 2
+  });
+
+  serializer.maps = {
+    id: "id",
+    appID: "applicationID",
+    status: "info.status"
+  };
+
+  assert.deepEqual(serializer.extractAttributes(modelClass, resourceHash), {
+    id: 1,
+    appID: 3,
+    status: "SUCCESS"
+  });
+});
+
+test('extractRelationships test', function(assert) {
+  let serializer = this.subject(),
+    modelClass = {
+      eachAttribute: Ember.K,
+      eachRelationship: function (callback) {
+        callback("app", {
+          key: "app",
+          kind: "belongsTo",
+          options: {},
+          parentType: "parent",
+          type: "app"
+        });
+      },
+      eachTransformedAttribute: Ember.K
+    },
+    resourceHash = {
+      nameSpace: "ns",
+      data: {
+        id: 1,
+        app: "",
+      }
+    };
+
+  assert.deepEqual(serializer.extractRelationships(modelClass, resourceHash), {
+    app: {
+      data: {
+        id: null,
+        type:"app"
+      }
+    }
+  });
+
+});
+
+test('normalizeSingleResponse test', function(assert) {
+  let serializer = this.subject(),
+    modelClass = {
+      eachAttribute: function (callback) {
+        callback("id", {type: "string"});
+        callback("appID", {type: "string"});
+        callback("status", {type: "string"});
+      },
+      eachRelationship: Ember.K,
+      eachTransformedAttribute: Ember.K
+    },
+    resourceHash = {
+      nameSpace: "ns",
+      data: {
+        id: 1,
+        appID: 2,
+        applicationID: 3,
+        info: {
+          status: "SUCCESS"
+        }
+      }
+    };
+
+  var response = serializer.normalizeSingleResponse({}, modelClass, resourceHash, null, null);
+
+  assert.equal(response.data.id, "ns:1");
+  assert.equal(response.data.attributes.id, 1);
+  assert.equal(response.data.attributes.appID, 2);
+});
+
+test('normalizeArrayResponse test', function(assert) {
+  let serializer = this.subject(),
+    modelClass = {
+      eachAttribute: function (callback) {
+        callback("id", {type: "string"});
+        callback("appID", {type: "string"});
+        callback("status", {type: "string"});
+      },
+      eachRelationship: Ember.K,
+      eachTransformedAttribute: Ember.K
+    },
+    resourceHash = {
+      nameSpace: "ns",
+      data: [{
+        id: 1,
+        appID: 2,
+      },{
+        id: 2,
+        appID: 4,
+      }]
+    };
+
+  var response = serializer.normalizeArrayResponse({}, modelClass, resourceHash, null, null);
+
+  assert.equal(response.data.length, 2);
+  assert.deepEqual(response.data[0].id, "ns:1");
+  assert.deepEqual(response.data[1].id, "ns:2");
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/e673284f/tez-ui2/src/main/webapp/tests/unit/services/loader-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/services/loader-test.js b/tez-ui2/src/main/webapp/tests/unit/services/loader-test.js
new file mode 100644
index 0000000..548aca8
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/unit/services/loader-test.js
@@ -0,0 +1,267 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:loader', 'Unit | Service | loader', {
+  // Specify the other units that are required for this test.
+  // needs: ['service:foo']
+});
+
+test('Basic creation test', function(assert) {
+  let service = this.subject();
+
+  assert.ok(service.cache);
+  assert.ok(service.store);
+  assert.ok(service._setOptions);
+
+  assert.ok(service.checkRequisite);
+
+  assert.ok(service.lookup);
+  assert.ok(service.entityFor);
+
+  assert.ok(service.getCacheKey);
+
+  assert.ok(service.queryRecord);
+  assert.ok(service.query);
+});
+
+test('_setOptions test', function(assert) {
+  let service = this.subject();
+
+  assert.equal(service.get("nameSpace"), '');
+
+  service._setOptions({
+    nameSpace: "ns"
+  });
+
+  assert.equal(service.get("nameSpace"), 'ns');
+});
+
+test('checkRequisite test', function(assert) {
+  let service = this.subject(),
+      testType = "type";
+
+  assert.expect(3 + 3 + 2);
+
+  // Not found
+  service.store = {
+    adapterFor: function (type) {
+      assert.equal(type, testType);
+    },
+    serializerFor: function (type) {
+      assert.equal(type, testType);
+    }
+  };
+  assert.throws(function () {
+    service.checkRequisite(testType);
+  });
+
+  // Not loader found
+  service.store = {
+    adapterFor: function (type) {
+      assert.equal(type, testType);
+      return {};
+    },
+    serializerFor: function (type) {
+      assert.equal(type, testType);
+      return {};
+    }
+  };
+  assert.throws(function () {
+    service.checkRequisite(testType);
+  });
+
+  service.store = {
+    adapterFor: function (type) {
+      assert.equal(type, testType);
+      return { _isLoader: true };
+    },
+    serializerFor: function (type) {
+      assert.equal(type, testType);
+      return { _isLoader: true };
+    }
+  };
+
+  service.checkRequisite(testType);
+});
+
+test('lookup test', function(assert) {
+  let service = this.subject();
+
+  assert.expect(1);
+
+  service.container.lookup = function (fullName) {
+    assert.equal(fullName, "typ:na-me");
+  };
+
+  service.lookup("typ", "NaMe");
+});
+
+test('entityFor test', function(assert) {
+  let service = this.subject(),
+      testName = "abc",
+      entity;
+
+  assert.expect(3 + 4 + 3);
+
+  // All lookups fail
+  service.lookup = function (type, name) {
+    if(name === testName) {
+      assert.equal(type, "entitie");
+    }
+    if(name === "entity") {
+      assert.equal(type, "entitie");
+    }
+  };
+  assert.throws(function () {
+    service.entityFor(testName);
+  }, "All lookups fail");
+
+  // Default lookups succeeded
+  service.lookup = function (type, name) {
+    if(name === testName) {
+      assert.equal(type, "entitie");
+    }
+    if(name === "entity") {
+      assert.equal(type, "entitie");
+      return {
+        actualName: "entity"
+      };
+    }
+  };
+  entity = service.entityFor(testName);
+  assert.equal(entity.actualName, "entity", "Default lookups succeeded");
+  assert.equal(entity.name, testName, "Default lookups succeeded");
+
+  // Primary lookups succeeded
+  service.lookup = function (type, name) {
+    if(name === testName) {
+      assert.equal(type, "entitie");
+      return {
+        actualName: name
+      };
+    }
+    if(name === "entity") {
+      assert.equal(type, "entitie"); // Shouldn't be called
+    }
+  };
+  entity = service.entityFor(testName);
+  assert.equal(entity.name, testName, "Default lookups succeeded");
+  assert.equal(entity.name, testName, "Default lookups succeeded");
+});
+
+test('getCacheKey test', function(assert) {
+  let service = this.subject();
+
+  assert.equal(service.getCacheKey("type"), "type");
+  assert.equal(service.getCacheKey("type", {a:1}), 'type:{"a":1}');
+  assert.equal(service.getCacheKey("type", null, 1), "type:1");
+  assert.equal(service.getCacheKey("type", {a:1}, 1), 'type:1:{"a":1}');
+});
+
+test('queryRecord test', function(assert) {
+  let service = this.subject(),
+      testNameSpace = "ns",
+      testQueryParams = {},
+      testUrlParams = {},
+      testType = "type",
+      testRecord = {},
+      testID = 1,
+      cacheKey = service.getCacheKey(testType, testQueryParams, testID);
+
+  assert.expect(3 + 5 + 3);
+
+  service.nameSpace = testNameSpace;
+  service.checkRequisite = Ember.K;
+  service.entityFor = function (type) {
+    assert.equal(type, testType);
+
+    return {
+      loadRelations: function (thisService, record) {
+        assert.equal(thisService, service);
+        assert.equal(record, testRecord);
+
+        return record;
+      }
+    };
+  };
+  service.get("store").queryRecord = function (type, query) {
+    assert.equal(type, testType);
+
+    assert.equal(query.id, testID);
+    assert.equal(query.nameSpace, testNameSpace);
+    assert.equal(query.params, testQueryParams);
+    assert.equal(query.urlParams, testUrlParams);
+
+    return Ember.RSVP.resolve(testRecord);
+  };
+
+  service.cache = Ember.Object.create();
+  assert.notOk(service.get("cache").get(cacheKey));
+  service.queryRecord(testType, testID, testQueryParams, testUrlParams).then(function (record) {
+    assert.equal(record, testRecord);
+  });
+  assert.ok(service.get("cache").get(cacheKey));
+});
+
+test('query test', function(assert) {
+  let service = this.subject(),
+      testNameSpace = "ns",
+      testQueryParams = {},
+      testUrlParams = {},
+      testType = "type",
+      testRecord = {},
+      testRecords = [testRecord, testRecord],
+      cacheKey = service.getCacheKey(testType, testQueryParams);
+
+  assert.expect(1 + (2 + 2) + 4 + 3);
+
+  service.nameSpace = testNameSpace;
+  service.checkRequisite = Ember.K;
+  service.entityFor = function (type) {
+    assert.equal(type, testType);
+
+    return {
+      loadRelations: function (thisService, record) {
+        assert.equal(thisService, service);
+        assert.equal(record, testRecord);
+
+        return record;
+      }
+    };
+  };
+  service.get("store").query = function (type, query) {
+    assert.equal(type, testType);
+
+    assert.equal(query.nameSpace, testNameSpace);
+    assert.equal(query.params, testQueryParams);
+    assert.equal(query.urlParams, testUrlParams);
+
+    return Ember.RSVP.resolve(testRecords);
+  };
+
+  service.cache = Ember.Object.create();
+  assert.notOk(service.get("cache").get(cacheKey));
+  service.query(testType, testQueryParams, testUrlParams).then(function (records) {
+    assert.equal(records, testRecords);
+  });
+  assert.ok(service.get("cache").get(cacheKey));
+});