Skip to content

Commit e527b92

Browse files
Tom KirkpatrickTom Kirkpatrick
authored andcommitted
fix: reset state machine config after force override
1 parent 52712f9 commit e527b92

File tree

8 files changed

+86
-47
lines changed

8 files changed

+86
-47
lines changed

lib/index.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,12 @@ module.exports = function loopbackComponentFsm(app) {
4242
const cacheKey = generateCacheKey(instance)
4343
let cache = _.get(app.locals, cacheKey)
4444

45-
debug('Fetching cached state machine found for subscription %s (cache key=%s)', instance.id, cacheKey)
46-
4745
if (cache) {
48-
debug('Cached state machine found for subscription %s', instance.id)
46+
debug('Fetched cached state machine for instance %s (cache key=%s)', instance.id, cacheKey)
4947
return cache
5048
}
49+
debug('No cached state machine for instance %s (cache key=%s)', instance.id, cacheKey)
5150

52-
debug('No cached state machine found for subscription %s', instance.id)
5351
let config = getStateMachineConfig(modelName)
5452

5553
if (!config) {
@@ -58,7 +56,9 @@ module.exports = function loopbackComponentFsm(app) {
5856

5957
config = Object.assign(config, { initial: instance.status })
6058
cache = new StateMachine(config)
61-
debug('Caching state machine subscription %s: %o', instance.id, cache)
59+
debug('Created new state machine for instance %s with config %o', instance.id, config)
60+
61+
debug('Caching state machine for instance %s', instance.id)
6262
_.set(app.locals, cacheKey, cache)
6363

6464
return cache
@@ -78,7 +78,7 @@ module.exports = function loopbackComponentFsm(app) {
7878
debug('Deleting cached state machine for subscription %s (cache key=%s)', instance.id, cacheKey)
7979

8080
if (!_.get(app.locals, cacheKey)) {
81-
debug('Existing cached state machine not found for subscription %s (cache key=%s)', instance.id, cacheKey)
81+
debug('Existing cached state machine not for instance %s (cache key=%s)', instance.id, cacheKey)
8282
return false
8383
}
8484

lib/mixins/state-machine.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,26 @@ module.exports = function StateMachine(Model, settings) {
133133
const forceEventSetting = _.get(settings, `events[${eventNameIndex}].settings.allowForce`)
134134
const force = _.get(params, 'force')
135135

136+
const origFrom = Model.__FSM_CONFIG__.events[eventNameIndex].from
137+
const newFrom = [ ...origFrom, this.status ]
138+
136139
// If force has been requested, override the state machine config.
137140
if (force && (forceFsmSetting || forceEventSetting)) {
138-
_.assign(settings.events[eventNameIndex].from, [ this.status ])
141+
debug('Force option set - updating list of allowed states for %s to %o', eventName, newFrom)
142+
_.set(Model.__FSM_CONFIG__, `events[${eventNameIndex}].from`, newFrom)
139143
}
140144

141145
// Get the FSM.
142146
const fms = Model.app.getStateMachine(this)
143147

148+
// Reset the state machine config.
149+
// If force has been requested, override the state machine config.
150+
if (force && (forceFsmSetting || forceEventSetting)) {
151+
debug('Force option set - resetting list of allowed states for %s (index %s) to %o',
152+
eventName, eventNameIndex, origFrom)
153+
_.set(Model.__FSM_CONFIG__, `events[${eventNameIndex}].from`, origFrom)
154+
}
155+
144156
// Run the event method.
145157
return fms[eventName](this, ...args)
146158
.then(result => result)

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"condition-circle": "1.5.0",
4444
"cors": "2.8.3",
4545
"coveralls": "2.13.1",
46+
"dirty-chai": "2.0.0",
4647
"eslint": "2.13.1",
4748
"eslint-config-fullcube": "latest",
4849
"eslint-plugin-mocha": "4.11.0",
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict'
2+
3+
const Promise = require('bluebird')
4+
const log = require('loglevel')
5+
6+
log.enableAll()
7+
8+
module.exports = function OrderModel(Order) {
9+
// Prepare
10+
Order.observe('fsm:oneprepare', ctx => {
11+
log.info(`Preparing order ${ctx.instance.id}`)
12+
return Promise.delay(100)
13+
})
14+
Order.observe('fsm:onenteredprepared', ctx => {
15+
log.info(`Sucessfully prepared order ${ctx.instance.id}`)
16+
return Promise.resolve(ctx)
17+
})
18+
19+
// Cancel
20+
Order.observe('fsm:oncancel', ctx => {
21+
log.info(`Canceling order ${ctx.instance.id}`)
22+
return Promise.delay(100)
23+
})
24+
Order.observe('fsm:onenteredcanceled', ctx => {
25+
log.info(`Sucessfully canceled order ${ctx.instance.id}`)
26+
return Promise.resolve(ctx)
27+
})
28+
29+
// Deliver
30+
Order.observe('fsm:ondeliver', ctx => {
31+
log.info(`Delivering order ${ctx.instance.id}`)
32+
return Promise.delay(100)
33+
})
34+
Order.observe('fsm:onentereddelivered', ctx => {
35+
log.info(`Sucessfully delivered order ${ctx.instance.id}`)
36+
return Promise.resolve(ctx)
37+
})
38+
39+
}

test/fullcube-state-machine/common/models/order.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"status": {
1010
"type": "string",
1111
"required": true,
12-
"default": "prepare"
12+
"default": "prepared"
1313
}
1414
},
1515
"validations": [],
@@ -76,8 +76,8 @@
7676
"allowForce": true
7777
},
7878
"events": [
79-
{ "name": "cancel", "from": "prepare", "to": "canceled" },
80-
{ "name": "deliver", "from": "prepare", "to": "delivered", "settings": { "allowForce" : true } },
79+
{ "name": "cancel", "from": "prepared", "to": "canceled" },
80+
{ "name": "deliver", "from": "prepared", "to": "delivered", "settings": { "allowForce" : true } },
8181
{ "name": "prepare", "from": [ "none" ], "to": "prepared" }
8282
]
8383
}

test/fullcube-state-machine/common/providers/order.js

Lines changed: 0 additions & 29 deletions
This file was deleted.

test/fullcube-state-machine/common/providers/subscription.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ module.exports = class FcSubscription {
1010
this.instance = instance
1111
}
1212
activate() {
13-
return Promise.delay(2000).then(() => {
13+
return Promise.delay(100).then(() => {
1414
log.info(`Subscription ${this.instance.id} activated`)
1515
})
1616
}
1717

1818
cancel() {
19-
return Promise.delay(2000).then(() => {
19+
return Promise.delay(100).then(() => {
2020
log.info(`Subscription ${this.instance.id} canceled`)
2121
})
2222
}
2323

2424
reactivate() {
25-
return Promise.delay(2000).then(() => {
25+
return Promise.delay(100).then(() => {
2626
log.info(`Subscription ${this.instance.id} reactivated`)
2727
})
2828
}
2929

3030
expire() {
31-
return Promise.delay(2000).then(() => {
31+
return Promise.delay(100).then(() => {
3232
log.info(`Subscription ${this.instance.id} expired`)
3333
})
3434
}

test/test.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
/* eslint no-console: 0 */
2+
13
'use strict'
24

35
const Promise = require('bluebird')
46
const path = require('path')
57
const chai = require('chai')
68
const sinon = require('sinon')
79

10+
chai.use(require('dirty-chai'))
811
chai.use(require('sinon-chai'))
912

1013
const expect = chai.expect
@@ -275,10 +278,8 @@ describe('Cache', function() {
275278

276279
describe('Force status update', function() {
277280
beforeEach(function() {
278-
return Order.create({ status: 'prepare' })
279-
.then(order => {
280-
this.order = order
281-
})
281+
return Order.create()
282+
.then(order => (this.order = order))
282283
})
283284

284285
describe('allowed', function() {
@@ -308,14 +309,29 @@ describe('Force status update', function() {
308309

309310
describe('not allowed', function() {
310311
it('should not allow invalid state change', function() {
312+
this.deliveredSpy = sinon.spy()
313+
this.canceledSpy = sinon.spy()
314+
Order.observe('fsm:onentereddelivered', ctx => {
315+
this.deliveredSpy()
316+
return Promise.resolve(ctx)
317+
})
318+
Order.observe('fsm:onenteredcanceled', ctx => {
319+
this.canceledSpy()
320+
return Promise.resolve(ctx)
321+
})
311322
return this.order.deliver()
312323
.then(order => order.cancel())
313324
.catch(err => {
325+
expect(this.order).to.have.property('status', 'delivered')
314326
expect(err).to.have.property('message', 'Invalid event in current state')
315327
return this.order.reload().then(order => {
316328
expect(order).to.have.property('status', 'delivered')
317329
})
318330
})
331+
.finally(() => {
332+
expect(this.deliveredSpy).to.have.been.calledOnce()
333+
expect(this.canceledSpy).to.not.have.been.called()
334+
})
319335
})
320336
})
321337
})

0 commit comments

Comments
 (0)