From 79ebe72c6c4f1e0619b1ea1f7d74a52ce8da7af1 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 25 Mar 2015 16:18:24 -0700 Subject: [PATCH] [Core] Add test cases Add test cases for model cache to ensure it maintains a single instance of each model. WTD-1033. --- .../test/models/CachingModelDecoratorSpec.js | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/platform/core/test/models/CachingModelDecoratorSpec.js b/platform/core/test/models/CachingModelDecoratorSpec.js index 4718cc94b6..6095c0aaed 100644 --- a/platform/core/test/models/CachingModelDecoratorSpec.js +++ b/platform/core/test/models/CachingModelDecoratorSpec.js @@ -19,6 +19,25 @@ define( }; } + function fakePromise() { + var chains = [], + callbacks = []; + + return { + then: function (callback) { + var next = fakePromise(); + callbacks.push(callback); + chains.push(next); + return next; + }, + resolve: function (value) { + callbacks.forEach(function (cb, i) { + chains[i].resolve(cb(value)); + }); + } + }; + } + beforeEach(function () { mockCallback = jasmine.createSpy(); mockModelService = jasmine.createSpyObj('modelService', ['getModels']); @@ -54,6 +73,59 @@ define( expect(mockCallback).toHaveBeenCalledWith(testModels); }); + it("ensures a single object instance, even for multiple concurrent calls", function () { + var promiseA, promiseB, mockCallback = jasmine.createSpy(); + + promiseA = fakePromise(); + promiseB = fakePromise(); + + // Issue two calls before those promises resolve + mockModelService.getModels.andReturn(promiseA); + decorator.getModels(['a']); + mockModelService.getModels.andReturn(promiseB); + decorator.getModels(['a']).then(mockCallback); + + // Then resolve those promises. Note that we're whiteboxing here + // to figure out which promises to resolve (that is, we know that + // two thens are chained after each getModels) + promiseA.resolve(testModels); + promiseB.resolve({ + a: { someNewKey: "some other value" } + }); + + // Ensure that we have a pointer-identical instance + expect(mockCallback.mostRecentCall.args[0].a) + .toEqual({ someNewKey: "some other value" }); + expect(mockCallback.mostRecentCall.args[0].a) + .toBe(testModels.a); + }); + + it("is robust against updating with undefined values", function () { + var promiseA, promiseB, mockCallback = jasmine.createSpy(); + + promiseA = fakePromise(); + promiseB = fakePromise(); + + // Issue two calls before those promises resolve + mockModelService.getModels.andReturn(promiseA); + decorator.getModels(['a']); + mockModelService.getModels.andReturn(promiseB); + decorator.getModels(['a']).then(mockCallback); + + // Some model providers might erroneously add undefined values + // under requested keys, so handle that + promiseA.resolve({ + a: undefined + }); + promiseB.resolve({ + a: { someNewKey: "some other value" } + }); + + // Should still have gotten the model + expect(mockCallback.mostRecentCall.args[0].a) + .toEqual({ someNewKey: "some other value" }); + }); + }); }