diff --git a/docs/TODO.md b/docs/TODO.md index 6be7853..c0f1041 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -6,7 +6,6 @@ - heroku: reload game.repo from s3 at dyno startup, save periodically - Documentation - Rule engine - - [!] Handle 'No matching document found' version errors while executing rule and revert execution - provide rule triggering inside rules, with reloading when imported ruless changed (IA ?) - Rheia @@ -41,7 +40,9 @@ - remove item type property does not update existing items - bug with map value when retrieving items with search - fix from handling at event creation - - save new item on a new map : mapId stored in DB, but map object not affected to item (modelWatcher does not send the map) + - save new item on a new map : mapId stored in DB, but map object not affected to item (modelWatcher does not send + the map) + - Avoid 'No matching document found' version errors while executing rule: disabled versionning cause conflict can't be property handled, and data erasure is acceptable - ImageService to upload and associate images to types - remove all images when removing a type - Field type CRUD diff --git a/hyperion/src/model/typeFactory.coffee b/hyperion/src/model/typeFactory.coffee index 7ffdd12..d9f148b 100644 --- a/hyperion/src/model/typeFactory.coffee +++ b/hyperion/src/model/typeFactory.coffee @@ -176,7 +176,6 @@ module.exports = (typeName, spec, options = {}) -> when 'deletion' delete caches[typeName][changes.id] - spec.versionKey = false if options.typeProperties # event properties definition, stored by names @@ -224,7 +223,11 @@ module.exports = (typeName, spec, options = {}) -> options._id = false spec._id = String - + # Disable versionning on array properties. + # Versionning avoid data erasure, but the single-thread architecture of Hyperion already enforece this. + # In case of cached values reuse, as we can't handle conflict, we rather prefer to erase data + options.versionKey = false + # Abstract schema, that can contains i18n attributes AbstractType = new mongoose.Schema spec, options diff --git a/package.json b/package.json index 0174b68..1ef4129 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,12 @@ "express": "3.10.3", "fs-extra": "0.9.1", "gift": "0.4.2", + "gulp": "3.7.0", + "gulp-clean": "0.3.0", + "gulp-coffee": "2.0.1", + "gulp-plumber": "0.6.2", + "gulp-stylus": "1.0.2", + "gulp-util": "2.2.16", "isemail": "1.0.1", "js-yaml": "3.0.2", "jshint": "2.5.1", @@ -37,12 +43,6 @@ }, "devDependencies": { "chai": "1.9.1", - "gulp": "3.7.0", - "gulp-clean": "0.3.0", - "gulp-coffee": "2.0.1", - "gulp-plumber": "0.6.2", - "gulp-stylus": "1.0.2", - "gulp-util": "2.2.16", "mocha": "1.20.1", "phantom-proxy": "0.1.792", "request": "2.36.0", @@ -51,8 +51,8 @@ }, "scripts": { "start": "node hyperion/bin/start", - "postinstall": "gulp cleanBuild", - "test": "gulp test" + "postinstall": "node node_modules/gulp/bin/gulp.js cleanBuild", + "test": "node node_modules/gulp/bin/gulp.js test" }, "licence": "LGPL v3", "engines": { diff --git a/test/testRuleService.coffee b/test/testRuleService.coffee index 74a2bf6..16747f4 100644 --- a/test/testRuleService.coffee +++ b/test/testRuleService.coffee @@ -19,6 +19,7 @@ _ = require 'underscore' async = require 'async' +{MongoClient, Server} = require 'mongodb' Executable = require '../hyperion/src/model/Executable' Item = require '../hyperion/src/model/Item' Event = require '../hyperion/src/model/Event' @@ -610,6 +611,52 @@ describe 'RuleService tests', -> expect(result).to.satisfy (obj) -> player.equals obj done() + it 'should data erasure occurs during save', (done) -> + # given an item + new ItemType(id: 'chopper').save (err, type) -> + return done err if err? + new Item(type: type).save (err, item) -> + return done err if err? + # given a rule modifing player + script.content = """Rule = require 'hyperion/model/Rule' + Player = require 'hyperion/model/Player' + class MyRule extends Rule + canExecute: (actor, target, context, callback) => + callback null, if actor._className is 'Item' then [] else null + execute: (actor, target, params, context, callback) => + # reuse cached values + Player.findCached ["#{player.id}"], (err, [player]) => + player.characters.push actor + @saved.push player + callback null, null + module.exports = new MyRule()""" + script.save (err) -> + return done err if err? + # given a client to mongoDB + new MongoClient(new Server utils.confKey('mongo.host'), utils.confKey 'mongo.port', 27017).open (err, client) -> + return done "Unable to open second connection to Mongo #{err}" if err? + db = client.db utils.confKey('mongo.db') + db.collection 'players', (err, collection) -> + return done "Unable to open second connection to Mongo #{err}" if err? + + # given a modification into db + collection.update {_id: player._id}, {$push:{characters: event1.id}}, (err) -> + return done "Unable to modify player in DB #{err}" if err? + + collection.find(_id: player._id).toArray (err, [player]) -> + return done "Unable to consult cached player #{err}" if err? + expect(player).to.have.property('characters').that.has.lengthOf(1).and.that.include event1.id + + # when executing this rule on the player + service.execute 'rule0', item.id, item.id, null, player.email, (err, result)-> + expect(err).not.to.exist + + # then player in db has rule values + collection.find(_id: player._id).toArray (err, [result]) -> + return done err if err? + expect(result).to.have.property('characters').that.has.lengthOf(1).and.that.include item.id + done() + describe 'given items, events, fields and a dumb rule', -> beforeEach (done) ->