locust 2.32.4.dev16__tar.gz → 2.32.4.dev18__tar.gz

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 (53) hide show
  1. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/PKG-INFO +1 -1
  2. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/_version.py +2 -2
  3. locust-2.32.4.dev16/locust/webui/dist/assets/index-RwtjIXkg.js → locust-2.32.4.dev18/locust/webui/dist/assets/index-BjM9pW6b.js +1 -1
  4. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/webui/dist/auth.html +1 -1
  5. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/webui/dist/index.html +1 -1
  6. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/pyproject.toml +1 -1
  7. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/LICENSE +0 -0
  8. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/README.md +0 -0
  9. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/__init__.py +0 -0
  10. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/__main__.py +0 -0
  11. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/argument_parser.py +0 -0
  12. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/clients.py +0 -0
  13. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/contrib/__init__.py +0 -0
  14. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/contrib/fasthttp.py +0 -0
  15. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/contrib/mongodb.py +0 -0
  16. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/contrib/postgres.py +0 -0
  17. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/debug.py +0 -0
  18. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/dispatch.py +0 -0
  19. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/env.py +0 -0
  20. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/event.py +0 -0
  21. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/exception.py +0 -0
  22. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/html.py +0 -0
  23. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/input_events.py +0 -0
  24. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/log.py +0 -0
  25. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/main.py +0 -0
  26. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/py.typed +0 -0
  27. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/rpc/__init__.py +0 -0
  28. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/rpc/protocol.py +0 -0
  29. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/rpc/zmqrpc.py +0 -0
  30. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/runners.py +0 -0
  31. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/shape.py +0 -0
  32. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/stats.py +0 -0
  33. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/user/__init__.py +0 -0
  34. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/user/inspectuser.py +0 -0
  35. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/user/sequential_taskset.py +0 -0
  36. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/user/task.py +0 -0
  37. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/user/users.py +0 -0
  38. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/user/wait_time.py +0 -0
  39. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/__init__.py +0 -0
  40. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/cache.py +0 -0
  41. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/date.py +0 -0
  42. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/deprecation.py +0 -0
  43. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/directory.py +0 -0
  44. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/exception_handler.py +0 -0
  45. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/load_locustfile.py +0 -0
  46. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/rounding.py +0 -0
  47. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/timespan.py +0 -0
  48. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/util/url.py +0 -0
  49. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/web.py +0 -0
  50. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/webui/dist/assets/favicon-dark.png +0 -0
  51. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/webui/dist/assets/favicon-light.png +0 -0
  52. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/locust/webui/dist/report.html +0 -0
  53. {locust-2.32.4.dev16 → locust-2.32.4.dev18}/poetry.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: locust
3
- Version: 2.32.4.dev16
3
+ Version: 2.32.4.dev18
4
4
  Summary: Developer-friendly load testing framework
5
5
  Home-page: https://locust.io/
6
6
  License: MIT
@@ -14,7 +14,7 @@ __version_tuple__: VERSION_TUPLE
14
14
  version_tuple: VERSION_TUPLE
15
15
 
16
16
 
17
- __version__ = "2.32.4.dev16"
17
+ __version__ = "2.32.4.dev18"
18
18
  version = __version__
19
- __version_tuple__ = (2, 32, 4, "dev16")
19
+ __version_tuple__ = (2, 32, 4, "dev18")
20
20
  version_tuple = __version_tuple__
@@ -218,4 +218,4 @@ PERFORMANCE OF THIS SOFTWARE.
218
218
  <span style="color:${f};">
219
219
  ${d}:&nbsp${ARe({chartValueFormatter:i,value:h})}
220
220
  </span>
221
- `,""):"No data",borderWidth:0},xAxis:{type:"time",min:(e.time||[new Date().toISOString()])[0],startValue:(e.time||[])[0],axisLabel:{formatter:TRe}},grid:{left:60,right:40},yAxis:CRe({splitAxis:a,yAxisLabels:o}),series:N7({charts:e,lines:r,scatterplot:s}),color:n,toolbox:{right:10,feature:{dataZoom:{title:{zoom:"Zoom Select",back:"Zoom Reset"},yAxisIndex:!1},saveAsImage:{name:t.replace(/\s+/g,"_").toLowerCase()+"_"+new Date().getTime()/1e3,title:"Download as PNG",emphasis:{iconStyle:{textPosition:"left"}}}}}}),kRe=e=>({symbol:"none",label:{formatter:t=>`Run #${t.dataIndex+1}`,padding:[0,0,8,0]},data:(e.markers||[]).map(t=>({xAxis:t}))}),IRe=e=>t=>{const{batch:r}=t;if(!r)return;const[{start:n,startValue:i,end:a}]=r,o=n>0&&a<=100||i>0;e.setOption({dataZoom:[{type:"slider",show:o}]})};function PRe({charts:e,title:t,lines:r,colors:n,chartValueFormatter:i,splitAxis:a,yAxisLabels:o,scatterplot:s,shouldReplaceMergeLines:l=!1}){const[u,c]=$.useState(null),f=Ii(({theme:{isDarkMode:h}})=>h),d=$.useRef(null);return $.useEffect(()=>{if(!d.current)return;const h=p1e(d.current);h.setOption(MRe({charts:e,title:t,lines:r,colors:n,chartValueFormatter:i,splitAxis:a,yAxisLabels:o,scatterplot:s})),h.on("datazoom",IRe(h));const v=()=>h.resize();return window.addEventListener("resize",v),h.group="swarmCharts",v1e("swarmCharts"),c(h),()=>{g1e(h),window.removeEventListener("resize",v)}},[d]),$.useEffect(()=>{const h=r.every(({key:v})=>!!e[v]);u&&h&&u.setOption({series:r.map(({key:v,yAxisIndex:g,...y},x)=>({...y,data:e[v],...a?{yAxisIndex:g||x}:{},...x===0?{markLine:kRe(e)}:{}}))})},[e,u,r]),$.useEffect(()=>{if(u){const{textColor:h,axisColor:v,backgroundColor:g,splitLine:y}=f?KF.DARK:KF.LIGHT;u.setOption({backgroundColor:g,textStyle:{color:h},title:{textStyle:{color:h}},legend:{icon:"circle",inactiveColor:h,textStyle:{color:h}},tooltip:{backgroundColor:g,textStyle:{color:h}},xAxis:{axisLine:{lineStyle:{color:v}}},yAxis:{axisLine:{lineStyle:{color:v}},splitLine:{lineStyle:{color:y}}}})}},[u,f]),$.useEffect(()=>{u&&u.setOption({series:N7({charts:e,lines:r,scatterplot:s})},l?{replaceMerge:["series"]}:void 0)},[r]),z.jsx("div",{ref:d,style:{width:"100%",height:"300px"}})}function DRe(){const{data:e,refetch:t}=kde(),r=qo(nv.setUi),n=Ii(({swarm:a})=>a.state),i=n===bn.SPAWNING||n==bn.RUNNING;$.useEffect(()=>{e&&r({ratios:e})},[e]),Ov(t,5e3,{shouldRunInterval:i,immediate:!0})}const JF=2e3;function RRe(){const e=qo(pk.setSwarm),t=qo(nv.setUi),r=qo(nv.updateCharts),n=qo(nv.updateChartMarkers),i=Ii(({swarm:d})=>d),a=$.useRef(i.state),[o,s]=$.useState(!1),{data:l,refetch:u}=Mde(),c=i.state===bn.SPAWNING||i.state==bn.RUNNING,f=()=>{if(!l)return;const{currentResponseTimePercentiles:d,extendedStats:h,stats:v,errors:g,totalRps:y,totalFailPerSec:x,failRatio:S,workers:b,userCount:w,totalAvgResponseTime:T}=l,C=new Date().toISOString();o&&(s(!1),n(C));const M=Rp(y,2),k=Rp(x,2),I=Rp(S*100),R={...Object.entries(d).reduce((L,[O,N])=>({...L,[O]:[C,N||0]}),{}),currentRps:[C,M],currentFailPerSec:[C,k],totalAvgResponseTime:[C,Rp(T,2)],userCount:[C,w],time:C};t({extendedStats:h,stats:v,errors:g,totalRps:M,failRatio:I,workers:b,userCount:w}),r(R)};$.useEffect(()=>{l&&e({state:l.state})},[l&&l.state]),Ov(f,JF,{shouldRunInterval:!!l&&c}),Ov(u,JF,{shouldRunInterval:c}),$.useEffect(()=>{i.state===bn.RUNNING&&a.current===bn.STOPPED&&s(!0),a.current=i.state},[i.state,a])}function ERe(){const{data:e,refetch:t}=Ide(),r=qo(nv.setUi),n=Ii(({swarm:a})=>a.state),i=n===bn.SPAWNING||n==bn.RUNNING;$.useEffect(()=>{e&&r({exceptions:e.exceptions})},[e]),Ov(t,5e3,{shouldRunInterval:i,immediate:!0})}function LRe(){return ERe(),z.jsx(vhe,{})}const ORe=[{key:"occurrences",title:"# Failures"},{key:"method",title:"Method"},{key:"name",title:"Name"},{key:"error",title:"Message",markdown:!0}];function NRe({errors:e}){return z.jsx(Tg,{rows:e,structure:ORe})}const zRe=({ui:{errors:e}})=>({errors:e}),BRe=ki(zRe)(NRe),FRe=e=>e.includes("CRITICAL")?Ks[900]:e.includes("ERROR")?Ks[700]:e.includes("WARNING")?HX[900]:e.includes("DEBUG")?_u[700]:"text.primary";function z7({log:e}){return z.jsx(zt,{color:FRe(e),fontFamily:"monospace",variant:"body2",children:e})}function VRe({workerId:e,logs:t}){const[r,n]=$.useState(!1);$.useEffect(()=>{t.slice(localStorage[e]).some(Y6)&&n(!0)},[t]);const i=$.useCallback(()=>{n(!1),localStorage[e]=t.length},[]);return z.jsxs(OM,{children:[z.jsxs(zM,{expandIcon:z.jsx(ck,{}),onClick:i,children:[r&&z.jsx(J6,{color:"secondary","data-testid":"worker-notification"}),e]}),z.jsx(NM,{children:z.jsx(Al,{elevation:3,sx:{p:2},children:t.map((a,o)=>z.jsx(z7,{log:a},`worker-${e}-log-${o}`))})})]})}function $Re(){const{master:e,workers:t}=Ii(({logViewer:r})=>r);return z.jsxs(ir,{sx:{display:"flex",flexDirection:"column",rowGap:4},children:[z.jsxs(ir,{children:[z.jsx(zt,{sx:{mb:2},variant:"h5",children:"Master Logs"}),z.jsx(Al,{elevation:3,sx:{p:2,fontFamily:"monospace"},children:e.map((r,n)=>z.jsx(z7,{log:r},`master-log-${n}`))})]}),!z6(t)&&z.jsxs(ir,{children:[z.jsx(zt,{sx:{mb:2},variant:"h5",children:"Worker Logs"}),Object.entries(t).map(([r,n],i)=>z.jsx(VRe,{logs:n,workerId:r},`worker-log-${i}`))]})]})}function GRe({extendedCsvFiles:e,statsHistoryEnabled:t}){const r=Ii(({theme:{isDarkMode:n}})=>n);return z.jsxs(N$,{sx:{display:"flex",flexDirection:"column"},children:[z.jsx(nf,{children:z.jsx(an,{href:"/stats/requests/csv",children:"Download requests CSV"})}),t&&z.jsx(nf,{children:z.jsx(an,{href:"/stats/requests_full_history/csv",children:"Download full request statistics history CSV"})}),z.jsx(nf,{children:z.jsx(an,{href:"/stats/failures/csv",children:"Download failures CSV"})}),z.jsx(nf,{children:z.jsx(an,{href:"/exceptions/csv",children:"Download exceptions CSV"})}),z.jsx(nf,{children:z.jsx(an,{href:`/stats/report?theme=${r?po.DARK:po.LIGHT}`,target:"_blank",children:"Download Report"})}),e&&e.map(({href:n,title:i},a)=>z.jsx(nf,{children:z.jsx(an,{href:n,children:i})},`extended-csv-${a}`))]})}const HRe=({swarm:{extendedCsvFiles:e,statsHistoryEnabled:t}})=>({extendedCsvFiles:e,statsHistoryEnabled:t}),WRe=ki(HRe)(GRe);var Mp={},eV;function jRe(){if(eV)return Mp;eV=1;var e=Sc();Object.defineProperty(Mp,"__esModule",{value:!0}),Mp.default=void 0;var t=e(bc()),r=Tl(),n=(0,t.default)((0,r.jsx)("path",{d:"M14.67 5v14H9.33V5h5.34zm1 14H21V5h-5.33v14zm-7.34 0V5H3v14h5.33z"}),"ViewColumn");return Mp.default=n,Mp}var URe=jRe();const YRe=ia(URe);function qRe({structure:e,selectedColumns:t,addColumn:r,removeColumn:n}){const[i,a]=$.useState(null);return z.jsxs(R$,{direction:"row",justifyContent:"end",my:2,spacing:1,children:[z.jsx(bo,{onClick:o=>a(o.currentTarget),variant:"outlined",children:z.jsx(YRe,{})}),z.jsx(V$,{anchorEl:i,anchorOrigin:{vertical:"bottom",horizontal:"left"},onClose:()=>a(null),open:!!i,children:z.jsx(L$,{sx:{p:2},children:e.map(({key:o,title:s})=>z.jsx(E$,{control:z.jsx(Fae,{checked:t.includes(o),onChange:()=>{t.includes(o)?n(o):r(o)}}),label:s},o))})})]})}function XRe(e){const[t,r]=$.useState(e.map(o=>o.key));return{selectedColumns:t,addColumn:o=>{r([...t,o])},removeColumn:o=>{r(t.filter(s=>s!==o))},filteredStructure:(o=>o.filter(s=>t.includes(s.key)))(e)}}const ZRe=vo.percentilesToStatistics?vo.percentilesToStatistics.map(e=>({title:`${e*100}%ile (ms)`,key:`responseTimePercentile${e}`})):[],KRe=[{key:"method",title:"Type"},{key:"name",title:"Name"},{key:"numRequests",title:"# Requests"},{key:"numFailures",title:"# Fails"},{key:"medianResponseTime",title:"Median (ms)",round:2},...ZRe,{key:"avgResponseTime",title:"Average (ms)",round:2},{key:"minResponseTime",title:"Min (ms)"},{key:"maxResponseTime",title:"Max (ms)"},{key:"avgContentLength",title:"Average size (bytes)",round:2},{key:"currentRps",title:"Current RPS",round:2},{key:"currentFailPerSec",title:"Current Failures/s",round:2}];function QRe({stats:e,tableStructure:t=KRe}){const{selectedColumns:r,addColumn:n,removeColumn:i,filteredStructure:a}=XRe(t);return z.jsxs(z.Fragment,{children:[z.jsx(qRe,{addColumn:n,removeColumn:i,selectedColumns:r,structure:t}),z.jsx(Tg,{hasTotalRow:!0,rows:e,structure:a})]})}const JRe=({ui:{stats:e}})=>({stats:e}),eEe=ki(JRe)(QRe),tEe=vo.percentilesToChart?vo.percentilesToChart.map(e=>({name:`${e*100}th percentile`,key:`responseTimePercentile${e}`})):[],rEe=["#ff9f00","#9966CC","#8A2BE2","#8E4585","#E0B0FF","#C8A2C8","#E6E6FA"],nEe=[{title:"Total Requests per Second",lines:[{name:"RPS",key:"currentRps"},{name:"Failures/s",key:"currentFailPerSec"}],colors:["#00ca5a","#ff6d6d"]},{title:"Response Times (ms)",lines:tEe,colors:rEe},{title:"Number of Users",lines:[{name:"Number of Users",key:"userCount"}],colors:["#0099ff"]}];function iEe({charts:e}){return z.jsx("div",{children:nEe.map((t,r)=>z.jsx(PRe,{...t,charts:e},`swarm-chart-${r}`))})}const aEe=({ui:{charts:e}})=>({charts:e}),oEe=ki(aEe)(iEe);function sEe(e){return(e*100).toFixed(1)+"%"}function rM({classRatio:e}){return z.jsx("ul",{children:Object.entries(e).map(([t,{ratio:r,tasks:n}])=>z.jsxs("li",{children:[`${sEe(r)} ${t}`,n&&z.jsx(rM,{classRatio:n})]},`nested-ratio-${t}`))})}function lEe({ratios:{perClass:e,total:t}}){return!e&&!t?null:z.jsxs("div",{children:[e&&z.jsxs(z.Fragment,{children:[z.jsx("h3",{children:"Ratio Per Class"}),z.jsx(rM,{classRatio:e})]}),t&&z.jsxs(z.Fragment,{children:[z.jsx("h3",{children:"Total Ratio"}),z.jsx(rM,{classRatio:t})]})]})}const uEe=({ui:{ratios:e}})=>({ratios:e}),cEe=ki(uEe)(lEe);function fEe(){return DRe(),z.jsx(cEe,{})}const dEe=[{key:"id",title:"Worker"},{key:"state",title:"State"},{key:"userCount",title:"# users"},{key:"cpuUsage",title:"CPU usage"},{key:"memoryUsage",title:"Memory usage",formatter:GX}];function hEe({workers:e=[]}){return z.jsx(Tg,{defaultSortKey:"id",rows:e,structure:dEe})}const pEe=({ui:{workers:e}})=>({workers:e}),vEe=ki(pEe)(hEe),qs={stats:{component:eEe,key:"stats",title:"Statistics"},charts:{component:oEe,key:"charts",title:"Charts"},failures:{component:BRe,key:"failures",title:"Failures"},exceptions:{component:LRe,key:"exceptions",title:"Exceptions"},ratios:{component:fEe,key:"ratios",title:"Current Ratio"},reports:{component:WRe,key:"reports",title:"Download Data"},logs:{component:$Re,key:q6,title:"Logs"},workers:{component:vEe,key:"workers",title:"Workers",shouldDisplayTab:e=>e.swarm.isDistributed}},gEe=[qs.stats,qs.charts,qs.failures,qs.exceptions,qs.ratios,qs.reports,qs.logs,qs.workers];function mEe({hasNotification:e,title:t}){return z.jsxs(ir,{sx:{display:"flex",alignItems:"center"},children:[e&&z.jsx(J6,{color:"secondary"}),z.jsx("span",{children:t})]})}function yEe({currentTabIndexFromQuery:e,notification:t,setNotification:r,setUrl:n,tabs:i}){const[a,o]=$.useState(e),s=(l,u)=>{const c=i[u].key;t[c]&&r({[c]:!1}),She({tab:c}),n({query:{tab:c}}),o(u)};return $.useEffect(()=>{o(e)},[e]),z.jsxs(bg,{maxWidth:"xl",children:[z.jsx(ir,{sx:{mb:2},children:z.jsx(Woe,{onChange:s,value:a,children:i.map(({key:l,title:u},c)=>z.jsx(Wae,{label:z.jsx(mEe,{hasNotification:t[l],title:u})},`tab-${c}`))})}),i.map(({component:l=fhe},u)=>a===u&&z.jsx(l,{},`tabpabel-${u}`))]})}const xEe=(e,{tabs:t,extendedTabs:r})=>{const{notification:n,swarm:{extendedTabs:i},url:{query:a}}=e,s=(t||[...gEe,...r||i||[]]).filter(({shouldDisplayTab:u})=>!u||u&&u(e)),l=a&&a.tab?s.findIndex(({key:u})=>u===a.tab):0;return{notification:n,tabs:s,currentTabIndexFromQuery:l>-1?l:0}},SEe={setNotification:Z6.setNotification,setUrl:whe.setUrl},bEe=ki(xEe,SEe)(yEe);function _Ee({swarmState:e,tabs:t,extendedTabs:r}){RRe(),nhe();const n=N6();return z.jsxs(c$,{theme:n,children:[z.jsx(P$,{}),z.jsx(Xde,{children:e===bn.READY?z.jsx(vk,{}):z.jsx(bEe,{extendedTabs:r,tabs:t})})]})}const wEe=({swarm:{state:e}})=>({swarmState:e}),CEe=ki(wEe)(_Ee);function TEe(){if(ME){const e=yV({reducer:hx({theme:L6})});return z.jsx(TE,{store:e,children:z.jsx(yfe,{...ME})})}else return z.jsx(TE,{store:Ahe,children:z.jsx(CEe,{})})}function AEe({error:e}){return z.jsxs("div",{role:"alert",children:[z.jsx("p",{children:"Something went wrong"}),e.message&&z.jsx("pre",{style:{color:"red"},children:e.message}),"If the issue persists, please consider opening an"," ",z.jsx("a",{href:"https://github.com/locustio/locust/issues/new?assignees=&labels=bug&projects=&template=bug.yml",children:"issue"})]})}const MEe=zY.createRoot(document.getElementById("root"));MEe.render(z.jsx(FY,{fallbackRender:AEe,children:z.jsx(TEe,{})}));
221
+ `,""):"No data",borderWidth:0},xAxis:{type:"time",min:(e.time||[new Date().toISOString()])[0],startValue:(e.time||[])[0],axisLabel:{formatter:TRe}},grid:{left:60,right:40},yAxis:CRe({splitAxis:a,yAxisLabels:o}),series:N7({charts:e,lines:r,scatterplot:s}),color:n,toolbox:{right:10,feature:{dataZoom:{title:{zoom:"Zoom Select",back:"Zoom Reset"},yAxisIndex:!1},saveAsImage:{name:t.replace(/\s+/g,"_").toLowerCase()+"_"+new Date().getTime()/1e3,title:"Download as PNG",emphasis:{iconStyle:{textPosition:"left"}}}}}}),kRe=e=>({symbol:"none",label:{formatter:t=>`Run #${t.dataIndex+1}`,padding:[0,0,8,0]},data:(e.markers||[]).map(t=>({xAxis:t}))}),IRe=e=>t=>{const{batch:r}=t;if(!r)return;const[{start:n,startValue:i,end:a}]=r,o=n>0&&a<=100||i>0;e.setOption({dataZoom:[{type:"slider",show:o}]})};function PRe({charts:e,title:t,lines:r,colors:n,chartValueFormatter:i,splitAxis:a,yAxisLabels:o,scatterplot:s,shouldReplaceMergeLines:l=!1}){const[u,c]=$.useState(null),f=Ii(({theme:{isDarkMode:h}})=>h),d=$.useRef(null);return $.useEffect(()=>{if(!d.current)return;const h=p1e(d.current);h.setOption(MRe({charts:e,title:t,lines:r,colors:n,chartValueFormatter:i,splitAxis:a,yAxisLabels:o,scatterplot:s})),h.on("datazoom",IRe(h));const v=()=>h.resize();return window.addEventListener("resize",v),h.group="swarmCharts",v1e("swarmCharts"),c(h),()=>{g1e(h),window.removeEventListener("resize",v)}},[d]),$.useEffect(()=>{const h=r.every(({key:v})=>!!e[v]);u&&h&&u.setOption({series:r.map(({key:v,yAxisIndex:g,...y},x)=>({...y,data:e[v],...a?{yAxisIndex:g||x}:{},...x===0?{markLine:kRe(e)}:{}}))})},[e,u,r]),$.useEffect(()=>{if(u){const{textColor:h,axisColor:v,backgroundColor:g,splitLine:y}=f?KF.DARK:KF.LIGHT;u.setOption({backgroundColor:g,textStyle:{color:h},title:{textStyle:{color:h}},legend:{icon:"circle",inactiveColor:h,textStyle:{color:h}},tooltip:{backgroundColor:g,textStyle:{color:h}},xAxis:{axisLine:{lineStyle:{color:v}}},yAxis:{axisLine:{lineStyle:{color:v}},splitLine:{lineStyle:{color:y}}}})}},[u,f]),$.useEffect(()=>{u&&u.setOption({series:N7({charts:e,lines:r,scatterplot:s})},l?{replaceMerge:["series"]}:void 0)},[r]),z.jsx("div",{ref:d,style:{width:"100%",height:"300px"}})}function DRe(){const{data:e,refetch:t}=kde(),r=qo(nv.setUi),n=Ii(({swarm:a})=>a.state),i=n===bn.SPAWNING||n==bn.RUNNING;$.useEffect(()=>{e&&r({ratios:e})},[e]),Ov(t,5e3,{shouldRunInterval:i,immediate:!0})}const JF=2e3;function RRe(){const e=qo(pk.setSwarm),t=qo(nv.setUi),r=qo(nv.updateCharts),n=qo(nv.updateChartMarkers),i=Ii(({swarm:d})=>d),a=$.useRef(i.state),[o,s]=$.useState(!1),{data:l,refetch:u}=Mde(),c=i.state===bn.SPAWNING||i.state==bn.RUNNING,f=()=>{if(!l)return;const{currentResponseTimePercentiles:d,extendedStats:h,stats:v,errors:g,totalRps:y,totalFailPerSec:x,failRatio:S,workers:b,userCount:w,totalAvgResponseTime:T}=l,C=new Date().toISOString();o&&(s(!1),n(C));const M=Rp(y,2),k=Rp(x,2),I=Rp(S*100),R={...Object.entries(d).reduce((L,[O,N])=>({...L,[O]:[C,N||0]}),{}),currentRps:[C,M],currentFailPerSec:[C,k],totalAvgResponseTime:[C,Rp(T,2)],userCount:[C,w],time:C};t({extendedStats:h,stats:v,errors:g,totalRps:M,failRatio:I,workers:b,userCount:w}),r(R)};$.useEffect(()=>{l&&e({state:l.state})},[l&&l.state]),Ov(f,JF,{shouldRunInterval:!!l&&c}),Ov(u,JF,{shouldRunInterval:c}),$.useEffect(()=>{i.state===bn.RUNNING&&a.current===bn.STOPPED&&s(!0),a.current=i.state},[i.state,a])}function ERe(){const{data:e,refetch:t}=Ide(),r=qo(nv.setUi),n=Ii(({swarm:a})=>a.state),i=n===bn.SPAWNING||n==bn.RUNNING;$.useEffect(()=>{e&&r({exceptions:e.exceptions})},[e]),Ov(t,5e3,{shouldRunInterval:i,immediate:!0})}function LRe(){return ERe(),z.jsx(vhe,{})}const ORe=[{key:"occurrences",title:"# Failures"},{key:"method",title:"Method"},{key:"name",title:"Name"},{key:"error",title:"Message",markdown:!0}];function NRe({errors:e}){return z.jsx(Tg,{rows:e,structure:ORe})}const zRe=({ui:{errors:e}})=>({errors:e}),BRe=ki(zRe)(NRe),FRe=e=>e.includes("CRITICAL")?Ks[900]:e.includes("ERROR")?Ks[700]:e.includes("WARNING")?HX[900]:e.includes("DEBUG")?_u[700]:"text.primary";function z7({log:e}){return z.jsx(zt,{color:FRe(e),fontFamily:"monospace",variant:"body2",children:e})}function VRe({workerId:e,logs:t}){const[r,n]=$.useState(!1);$.useEffect(()=>{t.slice(localStorage[e]).some(Y6)&&n(!0)},[t]);const i=$.useCallback(()=>{n(!1),localStorage[e]=t.length},[]);return z.jsxs(OM,{children:[z.jsxs(zM,{expandIcon:z.jsx(ck,{}),onClick:i,children:[r&&z.jsx(J6,{color:"secondary","data-testid":"worker-notification"}),e]}),z.jsx(NM,{children:z.jsx(Al,{elevation:3,sx:{p:2},children:t.map((a,o)=>z.jsx(z7,{log:a},`worker-${e}-log-${o}`))})})]})}function $Re(){const{master:e,workers:t}=Ii(({logViewer:r})=>r);return z.jsxs(ir,{sx:{display:"flex",flexDirection:"column",rowGap:4},children:[z.jsxs(ir,{children:[z.jsx(zt,{sx:{mb:2},variant:"h5",children:"Master Logs"}),z.jsx(Al,{elevation:3,sx:{p:2,fontFamily:"monospace"},children:e.map((r,n)=>z.jsx(z7,{log:r},`master-log-${n}`))})]}),!z6(t)&&z.jsxs(ir,{children:[z.jsx(zt,{sx:{mb:2},variant:"h5",children:"Worker Logs"}),Object.entries(t).map(([r,n],i)=>z.jsx(VRe,{logs:n,workerId:r},`worker-log-${i}`))]})]})}function GRe({extendedCsvFiles:e,statsHistoryEnabled:t}){const r=Ii(({theme:{isDarkMode:n}})=>n);return z.jsxs(N$,{sx:{display:"flex",flexDirection:"column"},children:[z.jsx(nf,{children:z.jsx(an,{href:"./stats/requests/csv",children:"Download requests CSV"})}),t&&z.jsx(nf,{children:z.jsx(an,{href:"./stats/requests_full_history/csv",children:"Download full request statistics history CSV"})}),z.jsx(nf,{children:z.jsx(an,{href:"./stats/failures/csv",children:"Download failures CSV"})}),z.jsx(nf,{children:z.jsx(an,{href:"./exceptions/csv",children:"Download exceptions CSV"})}),z.jsx(nf,{children:z.jsx(an,{href:`./stats/report?theme=${r?po.DARK:po.LIGHT}`,target:"_blank",children:"Download Report"})}),e&&e.map(({href:n,title:i},a)=>z.jsx(nf,{children:z.jsx(an,{href:n,children:i})},`extended-csv-${a}`))]})}const HRe=({swarm:{extendedCsvFiles:e,statsHistoryEnabled:t}})=>({extendedCsvFiles:e,statsHistoryEnabled:t}),WRe=ki(HRe)(GRe);var Mp={},eV;function jRe(){if(eV)return Mp;eV=1;var e=Sc();Object.defineProperty(Mp,"__esModule",{value:!0}),Mp.default=void 0;var t=e(bc()),r=Tl(),n=(0,t.default)((0,r.jsx)("path",{d:"M14.67 5v14H9.33V5h5.34zm1 14H21V5h-5.33v14zm-7.34 0V5H3v14h5.33z"}),"ViewColumn");return Mp.default=n,Mp}var URe=jRe();const YRe=ia(URe);function qRe({structure:e,selectedColumns:t,addColumn:r,removeColumn:n}){const[i,a]=$.useState(null);return z.jsxs(R$,{direction:"row",justifyContent:"end",my:2,spacing:1,children:[z.jsx(bo,{onClick:o=>a(o.currentTarget),variant:"outlined",children:z.jsx(YRe,{})}),z.jsx(V$,{anchorEl:i,anchorOrigin:{vertical:"bottom",horizontal:"left"},onClose:()=>a(null),open:!!i,children:z.jsx(L$,{sx:{p:2},children:e.map(({key:o,title:s})=>z.jsx(E$,{control:z.jsx(Fae,{checked:t.includes(o),onChange:()=>{t.includes(o)?n(o):r(o)}}),label:s},o))})})]})}function XRe(e){const[t,r]=$.useState(e.map(o=>o.key));return{selectedColumns:t,addColumn:o=>{r([...t,o])},removeColumn:o=>{r(t.filter(s=>s!==o))},filteredStructure:(o=>o.filter(s=>t.includes(s.key)))(e)}}const ZRe=vo.percentilesToStatistics?vo.percentilesToStatistics.map(e=>({title:`${e*100}%ile (ms)`,key:`responseTimePercentile${e}`})):[],KRe=[{key:"method",title:"Type"},{key:"name",title:"Name"},{key:"numRequests",title:"# Requests"},{key:"numFailures",title:"# Fails"},{key:"medianResponseTime",title:"Median (ms)",round:2},...ZRe,{key:"avgResponseTime",title:"Average (ms)",round:2},{key:"minResponseTime",title:"Min (ms)"},{key:"maxResponseTime",title:"Max (ms)"},{key:"avgContentLength",title:"Average size (bytes)",round:2},{key:"currentRps",title:"Current RPS",round:2},{key:"currentFailPerSec",title:"Current Failures/s",round:2}];function QRe({stats:e,tableStructure:t=KRe}){const{selectedColumns:r,addColumn:n,removeColumn:i,filteredStructure:a}=XRe(t);return z.jsxs(z.Fragment,{children:[z.jsx(qRe,{addColumn:n,removeColumn:i,selectedColumns:r,structure:t}),z.jsx(Tg,{hasTotalRow:!0,rows:e,structure:a})]})}const JRe=({ui:{stats:e}})=>({stats:e}),eEe=ki(JRe)(QRe),tEe=vo.percentilesToChart?vo.percentilesToChart.map(e=>({name:`${e*100}th percentile`,key:`responseTimePercentile${e}`})):[],rEe=["#ff9f00","#9966CC","#8A2BE2","#8E4585","#E0B0FF","#C8A2C8","#E6E6FA"],nEe=[{title:"Total Requests per Second",lines:[{name:"RPS",key:"currentRps"},{name:"Failures/s",key:"currentFailPerSec"}],colors:["#00ca5a","#ff6d6d"]},{title:"Response Times (ms)",lines:tEe,colors:rEe},{title:"Number of Users",lines:[{name:"Number of Users",key:"userCount"}],colors:["#0099ff"]}];function iEe({charts:e}){return z.jsx("div",{children:nEe.map((t,r)=>z.jsx(PRe,{...t,charts:e},`swarm-chart-${r}`))})}const aEe=({ui:{charts:e}})=>({charts:e}),oEe=ki(aEe)(iEe);function sEe(e){return(e*100).toFixed(1)+"%"}function rM({classRatio:e}){return z.jsx("ul",{children:Object.entries(e).map(([t,{ratio:r,tasks:n}])=>z.jsxs("li",{children:[`${sEe(r)} ${t}`,n&&z.jsx(rM,{classRatio:n})]},`nested-ratio-${t}`))})}function lEe({ratios:{perClass:e,total:t}}){return!e&&!t?null:z.jsxs("div",{children:[e&&z.jsxs(z.Fragment,{children:[z.jsx("h3",{children:"Ratio Per Class"}),z.jsx(rM,{classRatio:e})]}),t&&z.jsxs(z.Fragment,{children:[z.jsx("h3",{children:"Total Ratio"}),z.jsx(rM,{classRatio:t})]})]})}const uEe=({ui:{ratios:e}})=>({ratios:e}),cEe=ki(uEe)(lEe);function fEe(){return DRe(),z.jsx(cEe,{})}const dEe=[{key:"id",title:"Worker"},{key:"state",title:"State"},{key:"userCount",title:"# users"},{key:"cpuUsage",title:"CPU usage"},{key:"memoryUsage",title:"Memory usage",formatter:GX}];function hEe({workers:e=[]}){return z.jsx(Tg,{defaultSortKey:"id",rows:e,structure:dEe})}const pEe=({ui:{workers:e}})=>({workers:e}),vEe=ki(pEe)(hEe),qs={stats:{component:eEe,key:"stats",title:"Statistics"},charts:{component:oEe,key:"charts",title:"Charts"},failures:{component:BRe,key:"failures",title:"Failures"},exceptions:{component:LRe,key:"exceptions",title:"Exceptions"},ratios:{component:fEe,key:"ratios",title:"Current Ratio"},reports:{component:WRe,key:"reports",title:"Download Data"},logs:{component:$Re,key:q6,title:"Logs"},workers:{component:vEe,key:"workers",title:"Workers",shouldDisplayTab:e=>e.swarm.isDistributed}},gEe=[qs.stats,qs.charts,qs.failures,qs.exceptions,qs.ratios,qs.reports,qs.logs,qs.workers];function mEe({hasNotification:e,title:t}){return z.jsxs(ir,{sx:{display:"flex",alignItems:"center"},children:[e&&z.jsx(J6,{color:"secondary"}),z.jsx("span",{children:t})]})}function yEe({currentTabIndexFromQuery:e,notification:t,setNotification:r,setUrl:n,tabs:i}){const[a,o]=$.useState(e),s=(l,u)=>{const c=i[u].key;t[c]&&r({[c]:!1}),She({tab:c}),n({query:{tab:c}}),o(u)};return $.useEffect(()=>{o(e)},[e]),z.jsxs(bg,{maxWidth:"xl",children:[z.jsx(ir,{sx:{mb:2},children:z.jsx(Woe,{onChange:s,value:a,children:i.map(({key:l,title:u},c)=>z.jsx(Wae,{label:z.jsx(mEe,{hasNotification:t[l],title:u})},`tab-${c}`))})}),i.map(({component:l=fhe},u)=>a===u&&z.jsx(l,{},`tabpabel-${u}`))]})}const xEe=(e,{tabs:t,extendedTabs:r})=>{const{notification:n,swarm:{extendedTabs:i},url:{query:a}}=e,s=(t||[...gEe,...r||i||[]]).filter(({shouldDisplayTab:u})=>!u||u&&u(e)),l=a&&a.tab?s.findIndex(({key:u})=>u===a.tab):0;return{notification:n,tabs:s,currentTabIndexFromQuery:l>-1?l:0}},SEe={setNotification:Z6.setNotification,setUrl:whe.setUrl},bEe=ki(xEe,SEe)(yEe);function _Ee({swarmState:e,tabs:t,extendedTabs:r}){RRe(),nhe();const n=N6();return z.jsxs(c$,{theme:n,children:[z.jsx(P$,{}),z.jsx(Xde,{children:e===bn.READY?z.jsx(vk,{}):z.jsx(bEe,{extendedTabs:r,tabs:t})})]})}const wEe=({swarm:{state:e}})=>({swarmState:e}),CEe=ki(wEe)(_Ee);function TEe(){if(ME){const e=yV({reducer:hx({theme:L6})});return z.jsx(TE,{store:e,children:z.jsx(yfe,{...ME})})}else return z.jsx(TE,{store:Ahe,children:z.jsx(CEe,{})})}function AEe({error:e}){return z.jsxs("div",{role:"alert",children:[z.jsx("p",{children:"Something went wrong"}),e.message&&z.jsx("pre",{style:{color:"red"},children:e.message}),"If the issue persists, please consider opening an"," ",z.jsx("a",{href:"https://github.com/locustio/locust/issues/new?assignees=&labels=bug&projects=&template=bug.yml",children:"issue"})]})}const MEe=zY.createRoot(document.getElementById("root"));MEe.render(z.jsx(FY,{fallbackRender:AEe,children:z.jsx(TEe,{})}));
@@ -8,7 +8,7 @@
8
8
  <meta name="theme-color" content="#000000" />
9
9
 
10
10
  <title>Locust</title>
11
- <script type="module" crossorigin src="./assets/index-RwtjIXkg.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-BjM9pW6b.js"></script>
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
@@ -8,7 +8,7 @@
8
8
  <meta name="theme-color" content="#000000" />
9
9
 
10
10
  <title>Locust</title>
11
- <script type="module" crossorigin src="./assets/index-RwtjIXkg.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-BjM9pW6b.js"></script>
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
@@ -5,7 +5,7 @@ build-backend = "poetry_dynamic_versioning.backend"
5
5
  [tool.poetry]
6
6
  name = "locust"
7
7
  description = "Developer-friendly load testing framework"
8
- version = "2.32.4.dev16"
8
+ version = "2.32.4.dev18"
9
9
  license = "MIT"
10
10
  readme = "README.md"
11
11
  authors = ["Jonatan Heyman", "Lars Holmberg"]
File without changes
File without changes
File without changes