stoobly-agent 1.4.2__py3-none-any.whl → 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/cli/helpers/handle_mock_service.py +6 -2
  3. stoobly_agent/app/cli/helpers/request_facade.py +5 -1
  4. stoobly_agent/app/cli/scaffold/constants.py +1 -1
  5. stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py +1 -0
  6. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +19 -19
  7. stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context +1 -1
  8. stoobly_agent/app/cli/scaffold/templates/constants.py +3 -3
  9. stoobly_agent/app/cli/scaffold/templates/factory.py +5 -5
  10. stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/configure +1 -8
  11. stoobly_agent/app/cli/scaffold/templates/workflow/mock/fixtures.yml +1 -1
  12. stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/configure +1 -8
  13. stoobly_agent/app/cli/scaffold/templates/workflow/test/fixtures.yml +1 -1
  14. stoobly_agent/app/cli/scaffold/workflow_command.py +3 -3
  15. stoobly_agent/app/cli/scaffold/workflow_create_command.py +2 -2
  16. stoobly_agent/app/cli/scaffold_cli.py +5 -5
  17. stoobly_agent/app/proxy/context.py +4 -0
  18. stoobly_agent/app/proxy/handle_mock_service.py +81 -54
  19. stoobly_agent/app/proxy/handle_record_service.py +15 -3
  20. stoobly_agent/app/proxy/handle_replay_service.py +44 -18
  21. stoobly_agent/app/proxy/handle_test_service.py +75 -16
  22. stoobly_agent/app/proxy/intercept_handler.py +11 -16
  23. stoobly_agent/app/proxy/intercept_settings.py +17 -4
  24. stoobly_agent/app/proxy/mitmproxy/request_facade.py +5 -2
  25. stoobly_agent/app/proxy/mitmproxy/response_facade.py +5 -4
  26. stoobly_agent/app/proxy/mock/eval_fixtures_service.py +78 -14
  27. stoobly_agent/app/proxy/mock/eval_request_service.py +2 -2
  28. stoobly_agent/app/proxy/record/join_request_service.py +7 -8
  29. stoobly_agent/app/proxy/record/upload_request_service.py +2 -2
  30. stoobly_agent/app/proxy/replay/replay_request_service.py +4 -4
  31. stoobly_agent/app/proxy/test/helpers/upload_test_service.py +2 -2
  32. stoobly_agent/app/proxy/utils/allowed_request_service.py +3 -3
  33. stoobly_agent/app/proxy/utils/response_handler.py +0 -2
  34. stoobly_agent/app/proxy/utils/rewrite.py +72 -0
  35. stoobly_agent/app/settings/constants/request_component.py +4 -1
  36. stoobly_agent/cli.py +35 -28
  37. stoobly_agent/config/constants/intercept_policy.py +2 -0
  38. stoobly_agent/config/constants/mock_policy.py +4 -2
  39. stoobly_agent/config/constants/record_policy.py +4 -2
  40. stoobly_agent/config/constants/replay_policy.py +4 -2
  41. stoobly_agent/public/{18-es2015.583f191cc7ad512ee262.js → 18-es2015.503207073756a9c8211a.js} +1 -1
  42. stoobly_agent/public/{18-es5.583f191cc7ad512ee262.js → 18-es5.503207073756a9c8211a.js} +1 -1
  43. stoobly_agent/public/index.html +1 -1
  44. stoobly_agent/public/{main-es2015.2cc16523aa3fcaba51e5.js → main-es2015.d682619f3d6d53d64c6a.js} +1 -1
  45. stoobly_agent/public/{main-es5.2cc16523aa3fcaba51e5.js → main-es5.d682619f3d6d53d64c6a.js} +1 -1
  46. stoobly_agent/public/{runtime-es2015.b914470164e4d6e75d96.js → runtime-es2015.8c1efed946fc02c923fc.js} +1 -1
  47. stoobly_agent/public/{runtime-es5.b914470164e4d6e75d96.js → runtime-es5.8c1efed946fc02c923fc.js} +1 -1
  48. stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_test.py +2 -1
  49. stoobly_agent/test/app/cli/scaffold/e2e_test.py +2 -2
  50. stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
  51. stoobly_agent/test/app/proxy/mock/eval_fixtures_service_test.py +140 -71
  52. stoobly_agent/test/cli/lifecycle_hooks_test.py +66 -0
  53. stoobly_agent/test/cli/mock_test.py +53 -29
  54. stoobly_agent/test/cli/record_test.py +67 -0
  55. stoobly_agent/test/mock_data/lifecycle_hooks.py +35 -0
  56. {stoobly_agent-1.4.2.dist-info → stoobly_agent-1.5.0.dist-info}/LICENSE +1 -1
  57. {stoobly_agent-1.4.2.dist-info → stoobly_agent-1.5.0.dist-info}/METADATA +7 -12
  58. {stoobly_agent-1.4.2.dist-info → stoobly_agent-1.5.0.dist-info}/RECORD +62 -58
  59. /stoobly_agent/app/cli/scaffold/templates/workflow/mock/{fixtures/.keep → public/.gitignore} +0 -0
  60. /stoobly_agent/app/cli/scaffold/templates/workflow/test/{fixtures/.keep → public/.gitignore} +0 -0
  61. {stoobly_agent-1.4.2.dist-info → stoobly_agent-1.5.0.dist-info}/WHEEL +0 -0
  62. {stoobly_agent-1.4.2.dist-info → stoobly_agent-1.5.0.dist-info}/entry_points.txt +0 -0
@@ -1 +1 @@
1
- !function(e){function r(r){for(var a,f,o=r[0],b=r[1],d=r[2],i=0,l=[];i<o.length;i++)f=o[i],Object.prototype.hasOwnProperty.call(c,f)&&c[f]&&l.push(c[f][0]),c[f]=0;for(a in b)Object.prototype.hasOwnProperty.call(b,a)&&(e[a]=b[a]);for(u&&u(r);l.length;)l.shift()();return n.push.apply(n,d||[]),t()}function t(){for(var e,r=0;r<n.length;r++){for(var t=n[r],a=!0,o=1;o<t.length;o++)0!==c[t[o]]&&(a=!1);a&&(n.splice(r--,1),e=f(f.s=t[0]))}return e}var a={},c={11:0},n=[];function f(r){if(a[r])return a[r].exports;var t=a[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var r=[],t=c[e];if(0!==t)if(t)r.push(t[2]);else{var a=new Promise(function(r,a){t=c[e]=[r,a]});r.push(t[2]=a);var n,o=document.createElement("script");o.charset="utf-8",o.timeout=120,f.nc&&o.setAttribute("nonce",f.nc),o.src=function(e){return f.p+""+({3:"common"}[e]||e)+"-es2015."+{0:"c7c5a6d51b98cb85b9fc",1:"bb4492eeabe1fe937ada",2:"51eb8544ea9a21f2874c",3:"388805227aa99c527fba",4:"f8ac5475bf103969b2d2",5:"90ea7bd4439d9749e052",6:"5fb726c0555664300974",7:"19ccb84e62e2ea874f53",8:"b901639e2aeff1358c3d",9:"b7bcad8238f58e214f03",10:"56da22458086513ba0c7",12:"be58ed0ef449008b932e",13:"343b0261a8b3b3f4a1fc",14:"b6619d7742671d2a37fb",15:"d8855701408b0e1d7a3e",16:"98fa59c2c96d2caac3c3",17:"7f60b56d1fd66d4d5544",18:"583f191cc7ad512ee262",19:"78ec0e9fd228b5104712",20:"90544c488f1f0900bab4",21:"63ed4e6b242fbc047bd6",22:"1e96ef651f96d51191e2",23:"6d3052555b4fac38f16d",28:"a2bf42f38e4dd771ccea",29:"18b515f07c88753c7eb6",30:"d4d3dc4101400cadf3f3",31:"e3ea815f75c19c217b7d",32:"57553995bff0ae518501",33:"da5ba1e5baa164921198",34:"87acbb95cfb824650157",35:"8f79ff8748d4ff06ab03",36:"e3a104020eeec02cb8c4",37:"3b472e6cf303201bbf2c",38:"39dbf43d46cdc94f78c6",39:"e5475ea4fb6ec5c60741",40:"47b2873a8439717af6a7",41:"69f2771002745c066976",42:"b590b92ede890155dcd6",43:"ad1d956bffba561ba64c",44:"3ef2c17996ed5be95ced",45:"3d65d27e0a7085e96356",46:"e4f0a5b127eae13c27c0",47:"c7d45334a70131f133b5"}[e]+".js"}(e);var b=new Error;n=function(r){o.onerror=o.onload=null,clearTimeout(d);var t=c[e];if(0!==t){if(t){var a=r&&("load"===r.type?"missing":r.type),n=r&&r.target&&r.target.src;b.message="Loading chunk "+e+" failed.\n("+a+": "+n+")",b.name="ChunkLoadError",b.type=a,b.request=n,t[1](b)}c[e]=void 0}};var d=setTimeout(function(){n({type:"timeout",target:o})},12e4);o.onerror=o.onload=n,document.head.appendChild(o)}return Promise.all(r)},f.m=e,f.c=a,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var a in e)f.d(t,a,(function(r){return e[r]}).bind(null,a));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="",f.oe=function(e){throw console.error(e),e};var o=window.webpackJsonp=window.webpackJsonp||[],b=o.push.bind(o);o.push=r,o=o.slice();for(var d=0;d<o.length;d++)r(o[d]);var u=b;t()}([]);
1
+ !function(e){function r(r){for(var a,f,o=r[0],b=r[1],d=r[2],i=0,l=[];i<o.length;i++)f=o[i],Object.prototype.hasOwnProperty.call(c,f)&&c[f]&&l.push(c[f][0]),c[f]=0;for(a in b)Object.prototype.hasOwnProperty.call(b,a)&&(e[a]=b[a]);for(u&&u(r);l.length;)l.shift()();return n.push.apply(n,d||[]),t()}function t(){for(var e,r=0;r<n.length;r++){for(var t=n[r],a=!0,o=1;o<t.length;o++)0!==c[t[o]]&&(a=!1);a&&(n.splice(r--,1),e=f(f.s=t[0]))}return e}var a={},c={11:0},n=[];function f(r){if(a[r])return a[r].exports;var t=a[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var r=[],t=c[e];if(0!==t)if(t)r.push(t[2]);else{var a=new Promise(function(r,a){t=c[e]=[r,a]});r.push(t[2]=a);var n,o=document.createElement("script");o.charset="utf-8",o.timeout=120,f.nc&&o.setAttribute("nonce",f.nc),o.src=function(e){return f.p+""+({3:"common"}[e]||e)+"-es2015."+{0:"c7c5a6d51b98cb85b9fc",1:"bb4492eeabe1fe937ada",2:"51eb8544ea9a21f2874c",3:"388805227aa99c527fba",4:"f8ac5475bf103969b2d2",5:"90ea7bd4439d9749e052",6:"5fb726c0555664300974",7:"19ccb84e62e2ea874f53",8:"b901639e2aeff1358c3d",9:"b7bcad8238f58e214f03",10:"56da22458086513ba0c7",12:"be58ed0ef449008b932e",13:"343b0261a8b3b3f4a1fc",14:"b6619d7742671d2a37fb",15:"d8855701408b0e1d7a3e",16:"98fa59c2c96d2caac3c3",17:"7f60b56d1fd66d4d5544",18:"503207073756a9c8211a",19:"78ec0e9fd228b5104712",20:"90544c488f1f0900bab4",21:"63ed4e6b242fbc047bd6",22:"1e96ef651f96d51191e2",23:"6d3052555b4fac38f16d",28:"a2bf42f38e4dd771ccea",29:"18b515f07c88753c7eb6",30:"d4d3dc4101400cadf3f3",31:"e3ea815f75c19c217b7d",32:"57553995bff0ae518501",33:"da5ba1e5baa164921198",34:"87acbb95cfb824650157",35:"8f79ff8748d4ff06ab03",36:"e3a104020eeec02cb8c4",37:"3b472e6cf303201bbf2c",38:"39dbf43d46cdc94f78c6",39:"e5475ea4fb6ec5c60741",40:"47b2873a8439717af6a7",41:"69f2771002745c066976",42:"b590b92ede890155dcd6",43:"ad1d956bffba561ba64c",44:"3ef2c17996ed5be95ced",45:"3d65d27e0a7085e96356",46:"e4f0a5b127eae13c27c0",47:"c7d45334a70131f133b5"}[e]+".js"}(e);var b=new Error;n=function(r){o.onerror=o.onload=null,clearTimeout(d);var t=c[e];if(0!==t){if(t){var a=r&&("load"===r.type?"missing":r.type),n=r&&r.target&&r.target.src;b.message="Loading chunk "+e+" failed.\n("+a+": "+n+")",b.name="ChunkLoadError",b.type=a,b.request=n,t[1](b)}c[e]=void 0}};var d=setTimeout(function(){n({type:"timeout",target:o})},12e4);o.onerror=o.onload=n,document.head.appendChild(o)}return Promise.all(r)},f.m=e,f.c=a,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var a in e)f.d(t,a,(function(r){return e[r]}).bind(null,a));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="",f.oe=function(e){throw console.error(e),e};var o=window.webpackJsonp=window.webpackJsonp||[],b=o.push.bind(o);o.push=r,o=o.slice();for(var d=0;d<o.length;d++)r(o[d]);var u=b;t()}([]);
@@ -1 +1 @@
1
- !function(e){function r(r){for(var a,f,o=r[0],b=r[1],d=r[2],i=0,l=[];i<o.length;i++)f=o[i],Object.prototype.hasOwnProperty.call(c,f)&&c[f]&&l.push(c[f][0]),c[f]=0;for(a in b)Object.prototype.hasOwnProperty.call(b,a)&&(e[a]=b[a]);for(u&&u(r);l.length;)l.shift()();return n.push.apply(n,d||[]),t()}function t(){for(var e,r=0;r<n.length;r++){for(var t=n[r],a=!0,o=1;o<t.length;o++)0!==c[t[o]]&&(a=!1);a&&(n.splice(r--,1),e=f(f.s=t[0]))}return e}var a={},c={11:0},n=[];function f(r){if(a[r])return a[r].exports;var t=a[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var r=[],t=c[e];if(0!==t)if(t)r.push(t[2]);else{var a=new Promise(function(r,a){t=c[e]=[r,a]});r.push(t[2]=a);var n,o=document.createElement("script");o.charset="utf-8",o.timeout=120,f.nc&&o.setAttribute("nonce",f.nc),o.src=function(e){return f.p+""+({3:"common"}[e]||e)+"-es5."+{0:"c7c5a6d51b98cb85b9fc",1:"bb4492eeabe1fe937ada",2:"51eb8544ea9a21f2874c",3:"388805227aa99c527fba",4:"f8ac5475bf103969b2d2",5:"90ea7bd4439d9749e052",6:"5fb726c0555664300974",7:"19ccb84e62e2ea874f53",8:"b901639e2aeff1358c3d",9:"b7bcad8238f58e214f03",10:"56da22458086513ba0c7",12:"be58ed0ef449008b932e",13:"343b0261a8b3b3f4a1fc",14:"b6619d7742671d2a37fb",15:"d8855701408b0e1d7a3e",16:"98fa59c2c96d2caac3c3",17:"7f60b56d1fd66d4d5544",18:"583f191cc7ad512ee262",19:"78ec0e9fd228b5104712",20:"90544c488f1f0900bab4",21:"63ed4e6b242fbc047bd6",22:"1e96ef651f96d51191e2",23:"6d3052555b4fac38f16d",28:"a2bf42f38e4dd771ccea",29:"18b515f07c88753c7eb6",30:"d4d3dc4101400cadf3f3",31:"e3ea815f75c19c217b7d",32:"57553995bff0ae518501",33:"da5ba1e5baa164921198",34:"87acbb95cfb824650157",35:"8f79ff8748d4ff06ab03",36:"e3a104020eeec02cb8c4",37:"3b472e6cf303201bbf2c",38:"39dbf43d46cdc94f78c6",39:"e5475ea4fb6ec5c60741",40:"47b2873a8439717af6a7",41:"69f2771002745c066976",42:"b590b92ede890155dcd6",43:"ad1d956bffba561ba64c",44:"3ef2c17996ed5be95ced",45:"3d65d27e0a7085e96356",46:"e4f0a5b127eae13c27c0",47:"c7d45334a70131f133b5"}[e]+".js"}(e);var b=new Error;n=function(r){o.onerror=o.onload=null,clearTimeout(d);var t=c[e];if(0!==t){if(t){var a=r&&("load"===r.type?"missing":r.type),n=r&&r.target&&r.target.src;b.message="Loading chunk "+e+" failed.\n("+a+": "+n+")",b.name="ChunkLoadError",b.type=a,b.request=n,t[1](b)}c[e]=void 0}};var d=setTimeout(function(){n({type:"timeout",target:o})},12e4);o.onerror=o.onload=n,document.head.appendChild(o)}return Promise.all(r)},f.m=e,f.c=a,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var a in e)f.d(t,a,(function(r){return e[r]}).bind(null,a));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="",f.oe=function(e){throw console.error(e),e};var o=window.webpackJsonp=window.webpackJsonp||[],b=o.push.bind(o);o.push=r,o=o.slice();for(var d=0;d<o.length;d++)r(o[d]);var u=b;t()}([]);
1
+ !function(e){function r(r){for(var a,f,o=r[0],b=r[1],d=r[2],i=0,l=[];i<o.length;i++)f=o[i],Object.prototype.hasOwnProperty.call(c,f)&&c[f]&&l.push(c[f][0]),c[f]=0;for(a in b)Object.prototype.hasOwnProperty.call(b,a)&&(e[a]=b[a]);for(u&&u(r);l.length;)l.shift()();return n.push.apply(n,d||[]),t()}function t(){for(var e,r=0;r<n.length;r++){for(var t=n[r],a=!0,o=1;o<t.length;o++)0!==c[t[o]]&&(a=!1);a&&(n.splice(r--,1),e=f(f.s=t[0]))}return e}var a={},c={11:0},n=[];function f(r){if(a[r])return a[r].exports;var t=a[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var r=[],t=c[e];if(0!==t)if(t)r.push(t[2]);else{var a=new Promise(function(r,a){t=c[e]=[r,a]});r.push(t[2]=a);var n,o=document.createElement("script");o.charset="utf-8",o.timeout=120,f.nc&&o.setAttribute("nonce",f.nc),o.src=function(e){return f.p+""+({3:"common"}[e]||e)+"-es5."+{0:"c7c5a6d51b98cb85b9fc",1:"bb4492eeabe1fe937ada",2:"51eb8544ea9a21f2874c",3:"388805227aa99c527fba",4:"f8ac5475bf103969b2d2",5:"90ea7bd4439d9749e052",6:"5fb726c0555664300974",7:"19ccb84e62e2ea874f53",8:"b901639e2aeff1358c3d",9:"b7bcad8238f58e214f03",10:"56da22458086513ba0c7",12:"be58ed0ef449008b932e",13:"343b0261a8b3b3f4a1fc",14:"b6619d7742671d2a37fb",15:"d8855701408b0e1d7a3e",16:"98fa59c2c96d2caac3c3",17:"7f60b56d1fd66d4d5544",18:"503207073756a9c8211a",19:"78ec0e9fd228b5104712",20:"90544c488f1f0900bab4",21:"63ed4e6b242fbc047bd6",22:"1e96ef651f96d51191e2",23:"6d3052555b4fac38f16d",28:"a2bf42f38e4dd771ccea",29:"18b515f07c88753c7eb6",30:"d4d3dc4101400cadf3f3",31:"e3ea815f75c19c217b7d",32:"57553995bff0ae518501",33:"da5ba1e5baa164921198",34:"87acbb95cfb824650157",35:"8f79ff8748d4ff06ab03",36:"e3a104020eeec02cb8c4",37:"3b472e6cf303201bbf2c",38:"39dbf43d46cdc94f78c6",39:"e5475ea4fb6ec5c60741",40:"47b2873a8439717af6a7",41:"69f2771002745c066976",42:"b590b92ede890155dcd6",43:"ad1d956bffba561ba64c",44:"3ef2c17996ed5be95ced",45:"3d65d27e0a7085e96356",46:"e4f0a5b127eae13c27c0",47:"c7d45334a70131f133b5"}[e]+".js"}(e);var b=new Error;n=function(r){o.onerror=o.onload=null,clearTimeout(d);var t=c[e];if(0!==t){if(t){var a=r&&("load"===r.type?"missing":r.type),n=r&&r.target&&r.target.src;b.message="Loading chunk "+e+" failed.\n("+a+": "+n+")",b.name="ChunkLoadError",b.type=a,b.request=n,t[1](b)}c[e]=void 0}};var d=setTimeout(function(){n({type:"timeout",target:o})},12e4);o.onerror=o.onload=n,document.head.appendChild(o)}return Promise.all(r)},f.m=e,f.c=a,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var a in e)f.d(t,a,(function(r){return e[r]}).bind(null,a));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="",f.oe=function(e){throw console.error(e),e};var o=window.webpackJsonp=window.webpackJsonp||[],b=o.push.bind(o);o.push=r,o=o.slice();for(var d=0;d<o.length;d++)r(o[d]);var u=b;t()}([]);
@@ -1,6 +1,7 @@
1
1
  import copy
2
- from pathlib import Path
3
2
  import pdb
3
+
4
+ from pathlib import Path
4
5
  from pprint import pprint
5
6
  from typing import Dict
6
7
 
@@ -124,7 +124,7 @@ class TestScaffoldE2e():
124
124
  # Add user defined Docker Compose file for the local service
125
125
  shutil.copyfile(local_service_mock_docker_compose_path, destination_path)
126
126
 
127
- # Record workflow doesn't have a fixtures folder
127
+ # Record workflow doesn't have a public folder
128
128
 
129
129
  # Generate certs
130
130
  ScaffoldCliInvoker.cli_app_mkcert(runner, app_dir_path)
@@ -249,7 +249,7 @@ class TestScaffoldE2e():
249
249
  'service_name': external_service_docker_compose.service_name
250
250
  }
251
251
  command = ServiceWorkflowValidateCommand(app, **config)
252
- with open(f"{command.fixtures_dir_path}/shared_file.txt", 'w') as file:
252
+ with open(f"{command.public_dir_path}/shared_file.txt", 'w') as file:
253
253
  file.write('this is a shared file')
254
254
 
255
255
  ScaffoldCliInvoker.cli_workflow_up(runner, app_dir_path, target_workflow_name=target_workflow_name)
@@ -1 +1 @@
1
- 1.4.1
1
+ 1.5.0
@@ -25,75 +25,144 @@ def settings():
25
25
  return reset()
26
26
 
27
27
  class TestEvalFixturesService():
28
- @pytest.fixture(scope='class')
29
- def request_method(self):
30
- return 'POST'
31
-
32
- @pytest.fixture(scope='class')
33
- def request_url(self):
34
- return 'https://petstore.swagger.io/index.html'
35
-
36
- @pytest.fixture(scope='class')
37
- def created_request(
38
- self, settings: Settings, request_method: str, request_url: str
39
- ):
40
- status = RequestBuilder(
41
- method=request_method,
42
- response_body='',
43
- status_code=200,
44
- url=request_url,
45
- ).with_settings(settings).build()[1]
46
- assert status == 200
47
-
48
- return Request.last()
49
-
50
- @pytest.fixture(scope='class')
51
- def public_directory(self):
52
- tmp_dir_path = DataDir.instance().tmp_dir_path
53
- public_dir_path = os.path.join(tmp_dir_path, 'public')
54
- if not os.path.exists(public_dir_path):
55
- os.mkdir(public_dir_path)
56
- return public_dir_path
57
-
58
- @pytest.fixture(scope='class')
59
- def index_file_contents(self):
60
- return b'Hello World!'
61
-
62
- @pytest.fixture(autouse=True, scope='class')
63
- def index_file_path(self, public_directory: str, index_file_contents: str):
64
- path = os.path.join(public_directory, 'index.html')
65
- with open(path, 'wb') as fp:
66
- fp.write(index_file_contents)
67
- return path
68
-
69
- @pytest.fixture(scope='class')
70
- def response_fixtures(self, request_method: str, index_file_path: str) -> Fixtures:
71
- fixtures = {}
72
- fixtures[request_method] = {
73
- '/index.html': {
74
- 'headers': {
75
- 'Content-Length': '1',
76
- },
77
- 'path': index_file_path,
28
+ class TestResponseFixtures():
29
+ @pytest.fixture(scope='class')
30
+ def request_method(self):
31
+ return 'POST'
32
+
33
+ @pytest.fixture(scope='class')
34
+ def request_url(self):
35
+ return 'https://petstore.swagger.io/404.html'
36
+
37
+ @pytest.fixture(scope='class')
38
+ def created_request(
39
+ self, settings: Settings, request_method: str, request_url: str
40
+ ):
41
+ status = RequestBuilder(
42
+ method=request_method,
43
+ response_body='',
44
+ status_code=200,
45
+ url=request_url,
46
+ ).with_settings(settings).build()[1]
47
+ assert status == 200
48
+
49
+ return Request.last()
50
+
51
+ @pytest.fixture(scope='class')
52
+ def not_found_file_contents(self):
53
+ return b'Not Found'
54
+
55
+ @pytest.fixture(scope='class')
56
+ def public_directory(self):
57
+ tmp_dir_path = DataDir.instance().tmp_dir_path
58
+ public_dir_path = os.path.join(tmp_dir_path, 'public')
59
+ if not os.path.exists(public_dir_path):
60
+ os.mkdir(public_dir_path)
61
+ return public_dir_path
62
+
63
+ @pytest.fixture(autouse=True, scope='class')
64
+ def not_found_file_path(self, public_directory: str, not_found_file_contents: str):
65
+ path = os.path.join(public_directory, '404.html')
66
+ with open(path, 'wb') as fp:
67
+ fp.write(not_found_file_contents)
68
+ return path
69
+
70
+ @pytest.fixture(scope='class')
71
+ def response_fixtures(self, request_method: str, not_found_file_path: str) -> Fixtures:
72
+ fixtures = {}
73
+ fixtures[request_method] = {
74
+ '/404.html': {
75
+ 'headers': {
76
+ 'test': '1',
77
+ },
78
+ 'path': not_found_file_path,
79
+ 'status_code': 404,
80
+ }
78
81
  }
79
- }
80
- return fixtures
81
-
82
- @pytest.fixture()
83
- def mitmproxy_request(self, created_request: Request) -> MitmproxyRequest:
84
- return MitmproxyRequestAdapter(created_request).adapt()
85
-
86
- def test_it_evaluates_response_fixture(
87
- self, mitmproxy_request: MitmproxyRequest, response_fixtures: Fixtures, index_file_contents: str
88
- ):
89
- res: requests.Response = eval_fixtures(mitmproxy_request, response_fixtures=response_fixtures)
90
- assert res
91
- assert res.raw.read() == index_file_contents
92
- assert res.headers['Content-Length'] == '1'
93
-
94
- def test_it_evaluates_public_directory(
95
- self, mitmproxy_request: MitmproxyRequest, public_directory: str, index_file_contents: str
96
- ):
97
- res: requests.Response = eval_fixtures(mitmproxy_request, public_directory_path=public_directory)
98
- assert res
99
- assert res.raw.read() == index_file_contents
82
+ return fixtures
83
+
84
+ @pytest.fixture()
85
+ def mitmproxy_request(self, created_request: Request) -> MitmproxyRequest:
86
+ return MitmproxyRequestAdapter(created_request).adapt()
87
+
88
+ @pytest.fixture()
89
+ def fixtures_response(self, mitmproxy_request: MitmproxyRequest, response_fixtures: Fixtures):
90
+ res: requests.Response = eval_fixtures(mitmproxy_request, response_fixtures=response_fixtures)
91
+ assert res != None
92
+ return res
93
+
94
+ def test_it_sets_response(
95
+ self, fixtures_response: requests.Response, not_found_file_contents: str
96
+ ):
97
+ assert fixtures_response.raw.read() == not_found_file_contents
98
+
99
+ def test_it_sets_headers(self, fixtures_response: requests.Response):
100
+ assert fixtures_response.headers['test'] == '1'
101
+ assert fixtures_response.headers['Content-Type'] == 'text/html'
102
+
103
+ def test_it_sets_status_code(self, fixtures_response: requests.Response):
104
+ assert fixtures_response.status_code == 404
105
+
106
+ class TestPublicDirectory():
107
+ @pytest.fixture(scope='class')
108
+ def request_method(self):
109
+ return 'GET'
110
+
111
+ @pytest.fixture(scope='class')
112
+ def request_url(self):
113
+ return 'https://petstore.swagger.io'
114
+
115
+ @pytest.fixture(scope='class')
116
+ def created_request(
117
+ self, settings: Settings, request_method: str, request_url: str
118
+ ):
119
+ status = RequestBuilder(
120
+ method=request_method,
121
+ request_headers={'accept': 'text/html;q=0.1,application/json;q=0.9'},
122
+ response_body='',
123
+ status_code=200,
124
+ url=request_url,
125
+ ).with_settings(settings).build()[1]
126
+ assert status == 200
127
+
128
+ return Request.last()
129
+
130
+ @pytest.fixture()
131
+ def mitmproxy_request(self, created_request: Request) -> MitmproxyRequest:
132
+ return MitmproxyRequestAdapter(created_request).adapt()
133
+
134
+ @pytest.fixture(scope='class')
135
+ def public_directory(self):
136
+ tmp_dir_path = DataDir.instance().tmp_dir_path
137
+ public_dir_path = os.path.join(tmp_dir_path, 'public')
138
+ if not os.path.exists(public_dir_path):
139
+ os.mkdir(public_dir_path)
140
+ return public_dir_path
141
+
142
+ @pytest.fixture(scope='class')
143
+ def index_file_contents(self):
144
+ return b'Hello World!'
145
+
146
+ @pytest.fixture(autouse=True, scope='class')
147
+ def index_file_path(self, public_directory: str, index_file_contents: str):
148
+ path = os.path.join(public_directory, 'index.html')
149
+ with open(path, 'wb') as fp:
150
+ fp.write(index_file_contents)
151
+ return path
152
+
153
+ @pytest.fixture()
154
+ def public_directory_response(self, mitmproxy_request: MitmproxyRequest, public_directory: str):
155
+ res: requests.Response = eval_fixtures(mitmproxy_request, public_directory_path=public_directory)
156
+ assert res != None
157
+ return res
158
+
159
+ def test_it_sets_contents(
160
+ self, public_directory_response: requests.Response, index_file_contents: str
161
+ ):
162
+ assert public_directory_response.raw.read() == index_file_contents
163
+
164
+ def test_it_headers(self, public_directory_response: requests.Response):
165
+ assert public_directory_response.headers['Content-Type'] == 'text/html'
166
+
167
+ def test_it_sets_status_code(self, public_directory_response: requests.Response):
168
+ assert public_directory_response.status_code == 200
@@ -0,0 +1,66 @@
1
+ import pdb
2
+ import pytest
3
+
4
+ from click.testing import CliRunner
5
+ from pathlib import Path
6
+
7
+ from stoobly_agent.cli import mock, record, request
8
+ from stoobly_agent.lib.orm.request import Request
9
+ from stoobly_agent.test.test_helper import DETERMINISTIC_GET_REQUEST_URL, reset
10
+
11
+ @pytest.fixture(scope='module')
12
+ def runner():
13
+ return CliRunner()
14
+
15
+ class TestLifecycleHooks():
16
+ @pytest.fixture(scope='class', autouse=True)
17
+ def settings(self):
18
+ return reset()
19
+
20
+ @pytest.fixture(scope='class')
21
+ def lifecycle_hooks_path(self):
22
+ return str(Path(__file__).parent.parent / 'mock_data' / 'lifecycle_hooks.py')
23
+
24
+ @pytest.fixture(scope='class')
25
+ def record_result(self, runner: CliRunner, lifecycle_hooks_path: str):
26
+ record_result = runner.invoke(record, [
27
+ '--lifecycle-hooks-path', lifecycle_hooks_path, '--output', '/dev/null', DETERMINISTIC_GET_REQUEST_URL
28
+ ])
29
+ assert record_result.exit_code == 0
30
+ return record_result
31
+
32
+ @pytest.fixture(scope='class')
33
+ def recorded_request(self):
34
+ return Request.last()
35
+
36
+ @pytest.fixture(scope='class')
37
+ def mock_result(self, runner: CliRunner, lifecycle_hooks_path: str):
38
+ mock_result = runner.invoke(mock, [
39
+ '--lifecycle-hooks-path', lifecycle_hooks_path, '--output', '/dev/null', DETERMINISTIC_GET_REQUEST_URL
40
+ ])
41
+ assert mock_result.exit_code == 0
42
+ return mock_result
43
+
44
+ @pytest.fixture(scope='class')
45
+ def test_result(self, runner: CliRunner, lifecycle_hooks_path: str, recorded_request: Request):
46
+ test_result = runner.invoke(request, [
47
+ 'test', '--format', 'json', '--lifecycle-hooks-path', lifecycle_hooks_path, recorded_request.key()
48
+ ])
49
+ assert test_result.exit_code == 0
50
+ return test_result
51
+
52
+ def test_calls_record_hooks(self, record_result):
53
+ expected_stdout = ['before_request', 'before_record', 'after_record', 'before_response']
54
+ assert record_result.stdout.strip() == "\n".join(expected_stdout)
55
+
56
+ def test_calls_mock_hooks(self, mock_result):
57
+ expected_stdout = ['before_request', 'before_mock', 'after_mock', 'before_response']
58
+ assert mock_result.stdout.strip() == "\n".join(expected_stdout)
59
+
60
+ def test_calls_test_hooks(self, test_result):
61
+ expected_stdout = [
62
+ 'before_request', 'before_replay', 'after_replay', 'before_mock', 'after_mock', 'before_test', 'after_test', 'before_response'
63
+ ]
64
+ stdout = test_result.stdout
65
+ lifecycle_hooks_output = stdout.split('{')[0]
66
+ assert lifecycle_hooks_output.strip() == "\n".join(expected_stdout)
@@ -10,8 +10,9 @@ from stoobly_agent.config.constants import mode
10
10
  from stoobly_agent.app.settings.constants import request_component
11
11
  from stoobly_agent.cli import config, mock, record, scenario
12
12
  from stoobly_agent.lib.api.keys.scenario_key import ScenarioKey
13
+ from stoobly_agent.lib.orm.request import Request
13
14
 
14
- @pytest.fixture()
15
+ @pytest.fixture(scope='module')
15
16
  def runner():
16
17
  return CliRunner()
17
18
 
@@ -23,46 +24,60 @@ class TestMocking():
23
24
  return reset()
24
25
 
25
26
  class TestWhenHeaders():
27
+ header_name = 'foo'
28
+ header_value = 'bar'
29
+ url = DETERMINISTIC_GET_REQUEST_URL
26
30
 
27
- def test_it_rewrites(self, runner: CliRunner):
28
- header_name = 'foo'
29
- header_value = 'bar'
30
-
31
- url = DETERMINISTIC_GET_REQUEST_URL
32
- record_result = runner.invoke(record, [url, '-H', f"{header_name}: {header_value}"])
31
+ @pytest.fixture(autouse=True, scope='class')
32
+ def recorded_request(self, runner: CliRunner):
33
+ record_result = runner.invoke(record, [self.url, '-H', f"{self.header_name}: {self.header_value}"])
33
34
  assert record_result.exit_code == 0
35
+ return Request.last()
34
36
 
37
+ def test_it_ignores_headers_default(self, runner: CliRunner):
38
+ # Expect to fail since we have not set up rewrite rule for mock mode
39
+ mock_result = runner.invoke(mock, [self.url])
40
+ assert mock_result.exit_code == 0
41
+
42
+ def test_it_fails_when_enabled(self, runner: CliRunner):
35
43
  # Enforce matching by headers only
36
44
  match_result = runner.invoke(config, [
37
45
  'match', 'set',
38
46
  '--method', 'GET', '--mode', mode.MOCK, '--pattern', '.*?', '--component', request_component.HEADER
39
47
  ])
40
48
  assert match_result.exit_code == 0
41
-
49
+
42
50
  # Expect to fail since we have not set up rewrite rule for mock mode
43
- mock_result = runner.invoke(mock, [url])
51
+ mock_result = runner.invoke(mock, [self.url])
44
52
  assert mock_result.exit_code == 1
45
53
 
54
+ def test_it_succeeds_after_rewrite(self, runner: CliRunner):
46
55
  rewrite_result = runner.invoke(config, [
47
56
  'rewrite', 'set',
48
- '--method', 'GET', '--mode', mode.MOCK, '--name', header_name, '--value', header_value, '--pattern', '.*?', '--type', request_component.HEADER
57
+ '--method', 'GET', '--mode', mode.MOCK, '--name', self.header_name, '--value', self.header_value, '--pattern', '.*?', '--type', request_component.HEADER
49
58
  ]
50
59
  )
51
60
  assert rewrite_result.exit_code == 0
52
61
 
53
- mock_result = runner.invoke(mock, [url])
62
+ mock_result = runner.invoke(mock, [self.url])
54
63
  assert mock_result.exit_code == 0
55
64
 
56
65
  class TestWhenQueryParams():
66
+ query_param_name = 'foo'
67
+ query_param_value = 'bar'
68
+ url = DETERMINISTIC_GET_REQUEST_URL
57
69
 
58
- def test_it_rewrites(self, runner: CliRunner):
59
- query_param_name = 'foo'
60
- query_param_value = 'bar'
61
-
62
- url = DETERMINISTIC_GET_REQUEST_URL
63
- record_result = runner.invoke(record, [f"{url}?{query_param_name}={query_param_value}"])
70
+ @pytest.fixture(autouse=True, scope='class')
71
+ def recorded_request(self, runner: CliRunner):
72
+ record_result = runner.invoke(record, [f"{self.url}?{self.query_param_name}={self.query_param_value}"])
64
73
  assert record_result.exit_code == 0
74
+ return Request.last()
75
+
76
+ def test_it_ignores_query_params_by_default(self, runner: CliRunner):
77
+ mock_result = runner.invoke(mock, [self.url])
78
+ assert mock_result.exit_code == 0
65
79
 
80
+ def test_it_fails_when_enabled(self, runner: CliRunner):
66
81
  # Enforce matching by query params only
67
82
  match_result = runner.invoke(config, [
68
83
  'match', 'set',
@@ -71,34 +86,42 @@ class TestMocking():
71
86
  assert match_result.exit_code == 0
72
87
 
73
88
  # Expect to fail since we have not set up rewrite rule for mock mode
74
- mock_result = runner.invoke(mock, [url])
89
+ mock_result = runner.invoke(mock, [self.url])
75
90
  assert mock_result.exit_code == 1
76
91
 
92
+ def test_it_succeeds_after_rewrites(self, runner: CliRunner):
77
93
  rewrite_result = runner.invoke(config, [
78
94
  'rewrite', 'set',
79
- '--method', 'GET', '--mode', mode.MOCK, '--name', query_param_name, '--value', query_param_value, '--pattern', '.*?', '--type', request_component.QUERY_PARAM
95
+ '--method', 'GET', '--mode', mode.MOCK, '--name', self.query_param_name, '--value', self.query_param_value, '--pattern', '.*?', '--type', request_component.QUERY_PARAM
80
96
  ]
81
97
  )
82
98
  assert rewrite_result.exit_code == 0
83
99
 
84
- mock_result = runner.invoke(mock, [url])
100
+ mock_result = runner.invoke(mock, [self.url])
85
101
  assert mock_result.exit_code == 0
86
102
 
87
103
  class TestWhenBodyParams():
104
+ body_param_name = 'foo'
105
+ body_param_value = 'bar'
106
+ url = DETERMINISTIC_GET_REQUEST_URL
88
107
 
89
- def test_it_rewrites(self, runner: CliRunner):
90
- body_param_name = 'foo'
91
- body_param_value = 'bar'
92
-
108
+ @pytest.fixture(autouse=True, scope='class')
109
+ def recorded_request(self, runner: CliRunner):
93
110
  content = {}
94
- content[body_param_name] = body_param_value
111
+ content[self.body_param_name] = self.body_param_value
95
112
  body = json.dumps(content)
96
113
 
97
114
  url = DETERMINISTIC_GET_REQUEST_URL
98
115
  record_result = runner.invoke(record, [url, '-d', body, '-H', 'Content-Type: application/json'])
99
116
  assert record_result.exit_code == 0
117
+ return Request.last()
100
118
 
101
- # Enforce matching by query params only
119
+ def test_it_ignores_body_params_by_default(self, runner: CliRunner):
120
+ mock_result = runner.invoke(mock, [self.url])
121
+ assert mock_result.exit_code == 0
122
+
123
+ def test_it_fails_when_enabled(self, runner: CliRunner):
124
+ # Enforce matching by bodyy params only
102
125
  match_result = runner.invoke(config, [
103
126
  'match', 'set',
104
127
  '--method', 'GET', '--mode', mode.MOCK, '--pattern', '.*?', '--component', request_component.BODY_PARAM
@@ -106,17 +129,18 @@ class TestMocking():
106
129
  assert match_result.exit_code == 0
107
130
 
108
131
  # Expect to fail since we have not set up rewrite rule for mock mode
109
- mock_result = runner.invoke(mock, [url])
132
+ mock_result = runner.invoke(mock, [self.url])
110
133
  assert mock_result.exit_code == 1
111
134
 
135
+ def test_it_succeeds_after_rewrites(self, runner: CliRunner):
112
136
  rewrite_result = runner.invoke(config, [
113
137
  'rewrite', 'set',
114
- '--method', 'GET', '--mode', mode.MOCK, '--name', body_param_name, '--value', body_param_value, '--pattern', '.*?', '--type', request_component.BODY_PARAM
138
+ '--method', 'GET', '--mode', mode.MOCK, '--name', self.body_param_name, '--value', self.body_param_value, '--pattern', '.*?', '--type', request_component.BODY_PARAM
115
139
  ]
116
140
  )
117
141
  assert rewrite_result.exit_code == 0
118
142
 
119
- mock_result = runner.invoke(mock, [url])
143
+ mock_result = runner.invoke(mock, [self.url])
120
144
  assert mock_result.exit_code == 0
121
145
 
122
146
  class TestScenario():
@@ -9,11 +9,13 @@ from urllib.parse import parse_qs
9
9
  from stoobly_agent.test.test_helper import DETERMINISTIC_GET_REQUEST_URL, NON_DETERMINISTIC_GET_REQUEST_URL, reset
10
10
 
11
11
  from stoobly_agent.app.models.adapters.raw_http_request_adapter import RawHttpRequestAdapter
12
+ from stoobly_agent.app.models.adapters.raw_http_response_adapter import RawHttpResponseAdapter
12
13
  from stoobly_agent.app.settings.constants import firewall_action, request_component
13
14
  from stoobly_agent.config.constants import custom_headers, mode, record_policy, request_origin
14
15
  from stoobly_agent.cli import config, intercept, mock, record, scenario
15
16
  from stoobly_agent.lib.api.keys.scenario_key import ScenarioKey
16
17
  from stoobly_agent.lib.orm.request import Request
18
+ from stoobly_agent.lib.orm.response import Response
17
19
  from stoobly_agent.lib.orm.scenario import Scenario
18
20
  from stoobly_agent.lib.utils.decode import decode
19
21
 
@@ -130,6 +132,71 @@ class TestRecording():
130
132
  body = decode(python_request.data)
131
133
  assert json.loads(body).get(body_param) == body_param_value
132
134
 
135
+ class TestWhenResponseHeaders():
136
+
137
+ def test_it_rewrites(self, runner: CliRunner):
138
+ header_name = 'foo'
139
+ header_value = 'bar'
140
+
141
+ rewrite_result = runner.invoke(config, [
142
+ 'rewrite', 'set',
143
+ '--method', 'GET', '--mode', mode.RECORD, '--name', header_name, '--value', header_value, '--pattern', '.*?', '--type', request_component.RESPONSE_HEADER
144
+ ]
145
+ )
146
+ assert rewrite_result.exit_code == 0
147
+
148
+ record_result = runner.invoke(record, [DETERMINISTIC_GET_REQUEST_URL])
149
+ assert record_result.exit_code == 0
150
+
151
+ _response = Response.last()
152
+ python_response = RawHttpResponseAdapter(_response.raw).to_response()
153
+
154
+ assert python_response.headers.get(header_name.title()) == header_value
155
+
156
+ class TestWhenResponseParams():
157
+
158
+ def test_it_rewrites(self, runner: CliRunner):
159
+ body_param = 'foo'
160
+ body_param_value = 'bar'
161
+
162
+ rewrite_result = runner.invoke(config, [
163
+ 'rewrite', 'set',
164
+ '--method', 'GET', '--mode', mode.RECORD, '--name', body_param, '--value', body_param_value, '--pattern', '.*?', '--type', request_component.RESPONSE_PARAM
165
+ ]
166
+ )
167
+ assert rewrite_result.exit_code == 0
168
+
169
+ record_result = runner.invoke(record, [DETERMINISTIC_GET_REQUEST_URL])
170
+ assert record_result.exit_code == 0
171
+
172
+ _response = Response.last()
173
+ python_response = RawHttpResponseAdapter(_response.raw).to_response()
174
+
175
+ body = decode(python_response.content)
176
+ assert json.loads(body).get(body_param) == body_param_value
177
+
178
+ def test_it_does_not_rewrite(self, runner: CliRunner):
179
+ body_param = 'foo'
180
+ body_param_value = 'bar'
181
+
182
+ rewrite_result = runner.invoke(config, [
183
+ 'rewrite', 'set',
184
+ '--method', 'GET', '--mode', mode.RECORD, '--name', body_param, '--value', body_param_value, '--pattern', '.*?', '--type', request_component.RESPONSE_PARAM
185
+ ]
186
+ )
187
+ assert rewrite_result.exit_code == 0
188
+
189
+ record_result = runner.invoke(record, [NON_DETERMINISTIC_GET_REQUEST_URL])
190
+ assert record_result.exit_code == 0
191
+
192
+ _response = Response.last()
193
+ python_response = RawHttpResponseAdapter(_response.raw).to_response()
194
+
195
+ body = decode(python_response.content)
196
+ # For non iterable resposne content, do not rewrite
197
+ with pytest.raises(json.decoder.JSONDecodeError):
198
+ json.loads(body)
199
+
133
200
  class TestFirewall():
134
201
  @pytest.fixture(scope='function', autouse=True)
135
202
  def settings(self):
@@ -0,0 +1,35 @@
1
+ from stoobly_agent.app.proxy.context import InterceptContext
2
+ from stoobly_agent.app.proxy.mock.context import MockContext
3
+ from stoobly_agent.app.proxy.record.context import RecordContext
4
+ from stoobly_agent.app.proxy.replay.context import ReplayContext
5
+ from stoobly_agent.app.proxy.test.context import TestContext
6
+
7
+ def handle_before_request(context: InterceptContext):
8
+ print('before_request')
9
+
10
+ def handle_before_record(context: RecordContext):
11
+ print('before_record')
12
+
13
+ def handle_before_mock(context: MockContext):
14
+ print('before_mock')
15
+
16
+ def handle_before_replay(context: ReplayContext):
17
+ print('before_replay')
18
+
19
+ def handle_before_test(context: ReplayContext):
20
+ print('before_test')
21
+
22
+ def handle_after_record(context: RecordContext):
23
+ print('after_record')
24
+
25
+ def handle_after_mock(context: MockContext):
26
+ print('after_mock')
27
+
28
+ def handle_after_replay(context: ReplayContext):
29
+ print('after_replay')
30
+
31
+ def handle_after_test(context: TestContext):
32
+ print('after_test')
33
+
34
+ def handle_before_response(context: InterceptContext):
35
+ print('before_response')
@@ -1,4 +1,4 @@
1
- Copyright 2023 Stoobly
1
+ Copyright 2025 Stoobly
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.