unsafe-mode.test.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. var assert = require('assert');
  2. var util = require('util');
  3. var _ = require('@sailshq/lodash');
  4. var M = require('../lib/Machine.constructor');
  5. // ██╗ ██╗ █████╗ ██████╗ ███╗ ██╗██╗███╗ ██╗ ██████╗
  6. // ▄ ██╗▄▄ ██╗▄██║ ██║██╔══██╗██╔══██╗████╗ ██║██║████╗ ██║██╔════╝ ▄ ██╗▄▄ ██╗▄
  7. // ████╗ ████╗██║ █╗ ██║███████║██████╔╝██╔██╗ ██║██║██╔██╗ ██║██║ ███╗ ████╗ ████╗
  8. // ▀╚██╔▀▀╚██╔▀██║███╗██║██╔══██║██╔══██╗██║╚██╗██║██║██║╚██╗██║██║ ██║▀╚██╔▀▀╚██╔▀
  9. // ╚═╝ ╚═╝ ╚███╔███╔╝██║ ██║██║ ██║██║ ╚████║██║██║ ╚████║╚██████╔╝ ╚═╝ ╚═╝
  10. // ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═══╝ ╚═════╝
  11. //
  12. // █████╗ ██╗ ██╗ ██╗ ██╗███████╗███████╗██████╗ ██╗ █████╗ ███╗ ██╗██████╗
  13. // ██╔══██╗██║ ██║ ██║ ██║██╔════╝██╔════╝██╔══██╗██║ ██╔══██╗████╗ ██║██╔══██╗
  14. // ███████║██║ ██║ ██║ ██║███████╗█████╗ ██████╔╝██║ ███████║██╔██╗ ██║██║ ██║
  15. // ██╔══██║██║ ██║ ██║ ██║╚════██║██╔══╝ ██╔══██╗██║ ██╔══██║██║╚██╗██║██║ ██║
  16. // ██║ ██║███████╗███████╗ ╚██████╔╝███████║███████╗██║ ██║███████╗██║ ██║██║ ╚████║██████╔╝
  17. // ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝
  18. //
  19. // ████████╗██╗ ██╗██████╗ ███████╗ ███████╗ █████╗ ███████╗███████╗████████╗██╗ ██╗
  20. // ╚══██╔══╝╚██╗ ██╔╝██╔══██╗██╔════╝ ██╔════╝██╔══██╗██╔════╝██╔════╝╚══██╔══╝╚██╗ ██╔╝
  21. // ██║ ╚████╔╝ ██████╔╝█████╗█████╗███████╗███████║█████╗ █████╗ ██║ ╚████╔╝
  22. // ██║ ╚██╔╝ ██╔═══╝ ██╔══╝╚════╝╚════██║██╔══██║██╔══╝ ██╔══╝ ██║ ╚██╔╝
  23. // ██║ ██║ ██║ ███████╗ ███████║██║ ██║██║ ███████╗ ██║ ██║
  24. // ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝ ╚═╝ ╚═╝
  25. //
  26. // ██████╗ ██████╗ ███╗ ██╗████████╗██████╗ ██████╗ ██╗ ███████╗ █████╗ ██████╗ ███████╗
  27. // ██╔════╝██╔═══██╗████╗ ██║╚══██╔══╝██╔══██╗██╔═══██╗██║ ██╔════╝ ██╔══██╗██╔══██╗██╔════╝
  28. // ██║ ██║ ██║██╔██╗ ██║ ██║ ██████╔╝██║ ██║██║ ███████╗ ███████║██████╔╝█████╗
  29. // ██║ ██║ ██║██║╚██╗██║ ██║ ██╔══██╗██║ ██║██║ ╚════██║ ██╔══██║██╔══██╗██╔══╝
  30. // ╚██████╗╚██████╔╝██║ ╚████║ ██║ ██║ ██║╚██████╔╝███████╗███████║ ██║ ██║██║ ██║███████╗
  31. // ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
  32. //
  33. // ███████╗██╗ ██╗██████╗ ███████╗██████╗ ██╗███╗ ███╗███████╗███╗ ██╗████████╗ █████╗ ██╗ ██╗██╗
  34. // ██╔════╝╚██╗██╔╝██╔══██╗██╔════╝██╔══██╗██║████╗ ████║██╔════╝████╗ ██║╚══██╔══╝██╔══██╗██║ ██║██║
  35. // █████╗ ╚███╔╝ ██████╔╝█████╗ ██████╔╝██║██╔████╔██║█████╗ ██╔██╗ ██║ ██║ ███████║██║ ██║██║
  36. // ██╔══╝ ██╔██╗ ██╔═══╝ ██╔══╝ ██╔══██╗██║██║╚██╔╝██║██╔══╝ ██║╚██╗██║ ██║ ██╔══██║██║ ╚═╝╚═╝
  37. // ███████╗██╔╝ ██╗██║ ███████╗██║ ██║██║██║ ╚═╝ ██║███████╗██║ ╚████║ ██║ ██║ ██║███████╗██╗██╗
  38. // ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝╚═╝
  39. //
  40. describe('Unsafe mode', function() {
  41. it('should not coerce input data into proper types', function(done) {
  42. var _inputs;
  43. var sampleMachineDef = {
  44. inputs: {
  45. foo: {
  46. example: 100
  47. },
  48. bar: {
  49. example: 'foobar'
  50. }
  51. },
  52. exits: {
  53. success: {
  54. example: 'hello'
  55. },
  56. error: {
  57. example: 'world'
  58. }
  59. },
  60. fn: function (inputs, exits, deps) {
  61. _inputs = inputs;
  62. exits(null, 'foo');
  63. }
  64. };
  65. try {
  66. var live = M.build(sampleMachineDef)
  67. .configure({
  68. foo: '20',
  69. bar: 20
  70. });
  71. // Set experimental flags:
  72. live._unsafeMode = true;
  73. live._runTimeTypeCheck = false;
  74. live._inputCoercion = false;
  75. live._exitCoercion = false;
  76. live.exec(function(err, result) {
  77. if(err) { return done(err); }
  78. assert.strictEqual(_inputs.foo,'20');
  79. assert.strictEqual(_inputs.bar,20);
  80. done();
  81. });
  82. }
  83. catch (e){
  84. assert(false, 'Should not throw');
  85. }
  86. });
  87. it('should not fail if input expects string, but empty object ({}) is provided', function(done) {
  88. testInputConfiguration({
  89. example: 'asdf',
  90. actual: {}
  91. }, function (err, result){
  92. if (!err) {
  93. return done();
  94. }
  95. return done(new Error('Unexpected error: ', err));
  96. });
  97. });
  98. it('should fail if input expects string, but empty array ([]) is provided', function(done) {
  99. testInputConfiguration({
  100. example: 'asdf',
  101. actual: []
  102. }, function (err, result){
  103. if (!err) {
  104. return done();
  105. }
  106. return done(new Error('Unexpected error: ', err));
  107. });
  108. });
  109. it('should fail if input expects string, but `{foo:"bar"}` is provided', function(done) {
  110. testInputConfiguration({
  111. example: 'asdf',
  112. actual: {foo: 'bar'}
  113. }, function (err, result){
  114. if (!err) {
  115. return done();
  116. }
  117. return done(new Error('Unexpected error: ', err));
  118. });
  119. });
  120. it('should fail if input expects string, but `{foo:{bar: "baz"}}` is provided', function(done) {
  121. testInputConfiguration({
  122. example: 'asdf',
  123. actual: {foo:{bar: 'baz'}}
  124. }, function (err, result){
  125. if (!err) {
  126. return done();
  127. }
  128. return done(new Error('Unexpected error: ', err));
  129. });
  130. });
  131. it('should fail if input expects number, but `{foo:{bar: "baz"}}` is provided', function(done) {
  132. testInputConfiguration({
  133. example: 1234,
  134. actual: {foo:{bar: 'baz'}}
  135. }, function (err, result){
  136. if (!err) {
  137. return done();
  138. }
  139. return done(new Error('Unexpected error: ', err));
  140. });
  141. });
  142. });
  143. describe('_inputCoercion flag (+assorted sanity checks)', function() {
  144. var machine = {
  145. inputs: {
  146. foo: {
  147. example: 'foo bar'
  148. },
  149. bar: {
  150. example: 2
  151. }
  152. },
  153. exits: {
  154. success: {},
  155. error: {}
  156. },
  157. fn: function (inputs, exits, deps) {
  158. exits();
  159. }
  160. };
  161. it('should run with valid inputs', function(done) {
  162. M.build(machine)
  163. .configure({
  164. foo: 'hello',
  165. bar: 4
  166. })
  167. .exec(function(err, result) {
  168. if(err) { return done(err); }
  169. done();
  170. });
  171. });
  172. it('should error with mildly-invalid inputs when input coercion is off', function(done) {
  173. var live = M.build(machine)
  174. .configure({
  175. foo: 'hello',
  176. bar: '4'
  177. });
  178. live._inputCoercion = false;
  179. live.exec(function(err, result) {
  180. assert(err, 'expected error providing `"4"` to an input with example === `4`');
  181. done();
  182. });
  183. });
  184. it('should not error with mildly-invalid inputs when input coercion is on', function(done) {
  185. M.build(machine)
  186. .configure({
  187. foo: 'hello',
  188. bar: '4'
  189. })
  190. .exec(function(err, result) {
  191. if(err) { return done(err); }
  192. done();
  193. });
  194. });
  195. it('should error when undeclared exits are configured', function(done) {
  196. try {
  197. var live = M.build(machine)
  198. .configure({
  199. foo: 'hello',
  200. bar: 4
  201. });
  202. live._inputCoercion = false;
  203. live.exec({
  204. success: function(){},
  205. error: function() {},
  206. baz: function() {},
  207. boop: function() {}
  208. });
  209. return done(new Error('Expected an error regarding undeclared exits `baz, boop`.'));
  210. } catch (e) {
  211. return done();
  212. }
  213. });
  214. });
  215. ////////////////////////////////////////////////////////////////////////////
  216. ////////////////////////////////////////////////////////////////////////////
  217. ////////////////////////////////////////////////////////////////////////////
  218. ////////////////////////////////////////////////////////////////////////////
  219. ////////////////////////////////////////////////////////////////////////////
  220. //////////////////////////////////////////////////// HELPERS ///////////////
  221. function testInputConfiguration(options, cb){
  222. var _inputsInFn;
  223. var outputValue;
  224. var live = M.build({
  225. inputs: {
  226. x: (function _determineInputDefinition(){
  227. var def = {};
  228. if (!_.isUndefined(options.example)) {
  229. def.example = options.example;
  230. }
  231. return def;
  232. })()
  233. },
  234. exits: {
  235. error: {},
  236. success: {}
  237. },
  238. fn: function (inputs, exits) {
  239. _inputsInFn = inputs;
  240. exits(null, outputValue);
  241. }
  242. })
  243. .configure({
  244. x: options.actual
  245. });
  246. // Set experimental flags:
  247. live._unsafeMode = true;
  248. live._runTimeTypeCheck = false;
  249. live._inputCoercion = false;
  250. live._exitCoercion = false;
  251. live.exec(function (err, result){
  252. return cb(err, result);
  253. });
  254. }