More reliable method for mutexed localStorage saves

Fixes #1883
This commit is contained in:
John Firebaugh
2013-10-10 14:59:48 -07:00
parent 7b09a97f6c
commit 81bc280aba
9 changed files with 156 additions and 60 deletions
+4
View File
@@ -189,6 +189,8 @@
<script src='../js/id/presets/collection.js'></script>
<script src='../js/id/presets/field.js'></script>
<script src='../js/id/util/session_mutex.js'></script>
<script src='../js/id/validate.js'></script>
<script src='../js/lib/locale.js'></script>
@@ -265,7 +267,9 @@
<script src="spec/geo.js"></script>
<script src="spec/taginfo.js"></script>
<script src="spec/util.js"></script>
<script src='spec/util/session_mutex.js'></script>
<script src="spec/behavior/hash.js"></script>
<script src="spec/behavior/hover.js"></script>
+2
View File
@@ -87,7 +87,9 @@
<script src="spec/geo.js"></script>
<script src="spec/taginfo.js"></script>
<script src="spec/util.js"></script>
<script src='spec/util/session_mutex.js'></script>
<script src="spec/behavior/hash.js"></script>
<script src="spec/behavior/hover.js"></script>
-46
View File
@@ -244,52 +244,6 @@ describe("iD.History", function () {
});
});
describe("#lock", function() {
it("acquires lock if possible", function() {
expect(history.lock()).to.be.true;
expect(history.lock()).to.be.false;
});
});
describe("#save", function() {
it("doesn't do anything if it doesn't have the lock", function() {
var key = history._getKey('saved_history');
context.storage(key, null);
history.save();
expect(context.storage(key)).to.be.null;
context.storage(key, 'something');
expect(context.storage(key)).to.equal('something');
history.save();
context.storage(key, null);
});
it("saves to localStorage", function() {
var node = iD.Node({ id: 'n' });
history.lock();
history.perform(iD.actions.AddEntity(node));
history.save();
var saved = JSON.parse(context.storage(history._getKey('saved_history')));
expect(saved.stack[1].modified[0]).to.eql('nv0');
});
});
describe("#restore", function() {
it("saves and restores a created and deleted entities", function() {
var node = iD.Node({ id: 'n' }),
node2 = iD.Node({ id: 'n2' });
history.lock();
history.perform(iD.actions.AddEntity(node));
history.perform(iD.actions.AddEntity(node2));
history.perform(iD.actions.DeleteNode('n2'));
history.save();
history.reset();
expect(history.graph().hasEntity('n')).to.be.undefined
history.restore();
expect(history.graph().entity('n').id).to.equal('n');
expect(history.graph().hasEntity('n2')).to.be.undefined;
});
});
describe("#toJSON", function() {
it("generates v2 JSON", function() {
var node = iD.Node({id: 'n-1'});
+94
View File
@@ -0,0 +1,94 @@
describe("iD.util.SessionMutex", function() {
var clock, a, b;
beforeEach(function () {
clock = sinon.useFakeTimers(Date.now());
});
afterEach(function() {
clock.restore();
if (a) a.unlock();
if (b) b.unlock();
});
describe("#lock", function() {
it("returns true when it gets a lock", function() {
a = iD.util.SessionMutex('name');
expect(a.lock()).to.equal(true);
});
it("returns true when already locked", function() {
a = iD.util.SessionMutex('name');
a.lock();
expect(a.lock()).to.equal(true);
});
it("returns false when the lock is held by another session", function() {
a = iD.util.SessionMutex('name');
a.lock();
b = iD.util.SessionMutex('name');
expect(b.lock()).to.equal(false);
});
});
describe("#locked", function() {
it("returns false by default", function() {
a = iD.util.SessionMutex('name');
expect(a.locked()).to.equal(false);
});
it("returns true when locked", function() {
a = iD.util.SessionMutex('name');
a.lock();
expect(a.locked()).to.equal(true);
});
it("returns false when unlocked", function() {
a = iD.util.SessionMutex('name');
a.lock();
a.unlock();
expect(a.locked()).to.equal(false);
});
});
describe("#unlock", function() {
it("unlocks the mutex", function() {
a = iD.util.SessionMutex('name');
a.lock();
a.unlock();
b = iD.util.SessionMutex('name');
expect(b.lock()).to.equal(true);
});
it("does nothing when the lock is held by another session", function() {
a = iD.util.SessionMutex('name');
a.lock();
b = iD.util.SessionMutex('name');
b.unlock();
expect(a.locked()).to.equal(true);
});
it("does nothing when not locked", function() {
a = iD.util.SessionMutex('name');
a.unlock();
expect(a.locked()).to.equal(false);
});
});
it("namespaces locks", function() {
a = iD.util.SessionMutex('a');
a.lock();
b = iD.util.SessionMutex('b');
expect(b.locked()).to.equal(false);
expect(b.lock()).to.equal(true);
});
it("automatically unlocks when a session crashes", function() {
// Tested manually.
});
});