locust 2.29.2.dev32__py3-none-any.whl → 2.29.2.dev42__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.
- locust/_version.py +6 -2
- locust/contrib/fasthttp.py +1 -1
- locust/dispatch.py +7 -6
- locust/stats.py +4 -17
- {locust-2.29.2.dev32.dist-info → locust-2.29.2.dev42.dist-info}/METADATA +31 -26
- locust-2.29.2.dev42.dist-info/RECORD +49 -0
- locust-2.29.2.dev42.dist-info/WHEEL +4 -0
- locust-2.29.2.dev42.dist-info/entry_points.txt +3 -0
- locust/test/__init__.py +0 -15
- locust/test/fake_module1_for_env_test.py +0 -7
- locust/test/fake_module2_for_env_test.py +0 -7
- locust/test/mock_locustfile.py +0 -56
- locust/test/mock_logging.py +0 -28
- locust/test/test_debugging.py +0 -39
- locust/test/test_dispatch.py +0 -4170
- locust/test/test_env.py +0 -283
- locust/test/test_fasthttp.py +0 -785
- locust/test/test_http.py +0 -325
- locust/test/test_interruptable_task.py +0 -48
- locust/test/test_load_locustfile.py +0 -228
- locust/test/test_locust_class.py +0 -831
- locust/test/test_log.py +0 -237
- locust/test/test_main.py +0 -2264
- locust/test/test_old_wait_api.py +0 -0
- locust/test/test_parser.py +0 -450
- locust/test/test_runners.py +0 -4476
- locust/test/test_sequential_taskset.py +0 -157
- locust/test/test_stats.py +0 -866
- locust/test/test_tags.py +0 -440
- locust/test/test_taskratio.py +0 -94
- locust/test/test_users.py +0 -69
- locust/test/test_util.py +0 -33
- locust/test/test_wait_time.py +0 -79
- locust/test/test_web.py +0 -1257
- locust/test/test_zmqrpc.py +0 -58
- locust/test/testcases.py +0 -248
- locust/test/util.py +0 -88
- locust-2.29.2.dev32.dist-info/RECORD +0 -79
- locust-2.29.2.dev32.dist-info/WHEEL +0 -5
- locust-2.29.2.dev32.dist-info/entry_points.txt +0 -2
- locust-2.29.2.dev32.dist-info/top_level.txt +0 -1
- {locust-2.29.2.dev32.dist-info → locust-2.29.2.dev42.dist-info}/LICENSE +0 -0
locust/test/test_stats.py
DELETED
@@ -1,866 +0,0 @@
|
|
1
|
-
import locust
|
2
|
-
from locust import HttpUser, TaskSet, User, __version__, constant, task
|
3
|
-
from locust.env import Environment
|
4
|
-
from locust.rpc.protocol import Message
|
5
|
-
from locust.stats import (
|
6
|
-
PERCENTILES_TO_REPORT,
|
7
|
-
STATS_NAME_WIDTH,
|
8
|
-
STATS_TYPE_WIDTH,
|
9
|
-
CachedResponseTimes,
|
10
|
-
RequestStats,
|
11
|
-
StatsCSVFileWriter,
|
12
|
-
StatsEntry,
|
13
|
-
diff_response_time_dicts,
|
14
|
-
stats_history,
|
15
|
-
)
|
16
|
-
from locust.test.test_runners import mocked_rpc
|
17
|
-
from locust.test.testcases import LocustTestCase, WebserverTestCase
|
18
|
-
from locust.user.inspectuser import _get_task_ratio
|
19
|
-
|
20
|
-
import csv
|
21
|
-
import json
|
22
|
-
import os
|
23
|
-
import re
|
24
|
-
import time
|
25
|
-
import unittest
|
26
|
-
from unittest import mock
|
27
|
-
|
28
|
-
import gevent
|
29
|
-
|
30
|
-
_TEST_CSV_STATS_INTERVAL_SEC = 0.2
|
31
|
-
_TEST_CSV_STATS_INTERVAL_WAIT_SEC = _TEST_CSV_STATS_INTERVAL_SEC + 0.1
|
32
|
-
|
33
|
-
|
34
|
-
def _write_csv_files(environment, stats_base_name, full_history=False):
|
35
|
-
"""Spawn CVS writer and exit loop after first iteration."""
|
36
|
-
stats_writer = StatsCSVFileWriter(environment, PERCENTILES_TO_REPORT, stats_base_name, full_history=full_history)
|
37
|
-
greenlet = gevent.spawn(stats_writer)
|
38
|
-
gevent.sleep(_TEST_CSV_STATS_INTERVAL_WAIT_SEC)
|
39
|
-
gevent.kill(greenlet)
|
40
|
-
stats_writer.close_files()
|
41
|
-
|
42
|
-
|
43
|
-
class TestRequestStats(unittest.TestCase):
|
44
|
-
def setUp(self):
|
45
|
-
locust.stats.PERCENTILES_TO_REPORT = PERCENTILES_TO_REPORT
|
46
|
-
self.stats = RequestStats()
|
47
|
-
|
48
|
-
def log(response_time, size):
|
49
|
-
self.stats.log_request("GET", "test_entry", response_time, size)
|
50
|
-
|
51
|
-
def log_error(exc):
|
52
|
-
self.stats.log_error("GET", "test_entry", exc)
|
53
|
-
|
54
|
-
log(45, 1)
|
55
|
-
log(135, 1)
|
56
|
-
log(44, 1)
|
57
|
-
log(None, 1)
|
58
|
-
log_error(Exception("dummy fail"))
|
59
|
-
log_error(Exception("dummy fail"))
|
60
|
-
log(375, 1)
|
61
|
-
log(601, 1)
|
62
|
-
log(35, 1)
|
63
|
-
log(79, 1)
|
64
|
-
log(None, 1)
|
65
|
-
log_error(Exception("dummy fail"))
|
66
|
-
self.s = self.stats.entries[("test_entry", "GET")]
|
67
|
-
|
68
|
-
def test_percentile(self):
|
69
|
-
s = StatsEntry(self.stats, "percentile_test", "GET")
|
70
|
-
for x in range(100):
|
71
|
-
s.log(x, 0)
|
72
|
-
|
73
|
-
self.assertEqual(s.get_response_time_percentile(0.5), 50)
|
74
|
-
self.assertEqual(s.get_response_time_percentile(0.6), 60)
|
75
|
-
self.assertEqual(s.get_response_time_percentile(0.95), 95)
|
76
|
-
|
77
|
-
def test_median(self):
|
78
|
-
self.assertEqual(self.s.median_response_time, 79)
|
79
|
-
|
80
|
-
def test_median_out_of_min_max_bounds(self):
|
81
|
-
s = StatsEntry(self.stats, "median_test", "GET")
|
82
|
-
s.log(6034, 0)
|
83
|
-
self.assertEqual(s.median_response_time, 6034)
|
84
|
-
s.reset()
|
85
|
-
s.log(6099, 0)
|
86
|
-
self.assertEqual(s.median_response_time, 6099)
|
87
|
-
|
88
|
-
def test_total_rps(self):
|
89
|
-
self.stats.log_request("GET", "other_endpoint", 1337, 1337)
|
90
|
-
s2 = self.stats.entries[("other_endpoint", "GET")]
|
91
|
-
s2.start_time = 2.0
|
92
|
-
s2.last_request_timestamp = 6.0
|
93
|
-
self.s.start_time = 1.0
|
94
|
-
self.s.last_request_timestamp = 4.0
|
95
|
-
self.stats.total.start_time = 1.0
|
96
|
-
self.stats.total.last_request_timestamp = 6.0
|
97
|
-
self.assertEqual(self.s.total_rps, 9 / 5.0)
|
98
|
-
self.assertAlmostEqual(s2.total_rps, 1 / 5.0)
|
99
|
-
self.assertEqual(self.stats.total.total_rps, 10 / 5.0)
|
100
|
-
|
101
|
-
def test_rps_less_than_one_second(self):
|
102
|
-
s = StatsEntry(self.stats, "percentile_test", "GET")
|
103
|
-
for i in range(10):
|
104
|
-
s.log(i, 0)
|
105
|
-
self.assertGreater(s.total_rps, 10)
|
106
|
-
|
107
|
-
def test_current_rps(self):
|
108
|
-
self.stats.total.last_request_timestamp = int(time.time()) + 4
|
109
|
-
self.assertEqual(self.s.current_rps, 4.5)
|
110
|
-
|
111
|
-
self.stats.total.last_request_timestamp = int(time.time()) + 25
|
112
|
-
self.assertEqual(self.s.current_rps, 0)
|
113
|
-
|
114
|
-
def test_current_fail_per_sec(self):
|
115
|
-
self.stats.total.last_request_timestamp = int(time.time()) + 4
|
116
|
-
self.assertEqual(self.s.current_fail_per_sec, 1.5)
|
117
|
-
|
118
|
-
self.stats.total.last_request_timestamp = int(time.time()) + 12
|
119
|
-
self.assertEqual(self.s.current_fail_per_sec, 0.3)
|
120
|
-
|
121
|
-
self.stats.total.last_request_timestamp = int(time.time()) + 25
|
122
|
-
self.assertEqual(self.s.current_fail_per_sec, 0)
|
123
|
-
|
124
|
-
def test_num_reqs_fails(self):
|
125
|
-
self.assertEqual(self.s.num_requests, 9)
|
126
|
-
self.assertEqual(self.s.num_failures, 3)
|
127
|
-
|
128
|
-
def test_avg(self):
|
129
|
-
self.assertEqual(self.s.avg_response_time, 187.71428571428572)
|
130
|
-
|
131
|
-
def test_total_content_length(self):
|
132
|
-
self.assertEqual(self.s.total_content_length, 9)
|
133
|
-
|
134
|
-
def test_reset(self):
|
135
|
-
self.s.reset()
|
136
|
-
self.s.log(756, 0)
|
137
|
-
self.s.log_error(Exception("dummy fail after reset"))
|
138
|
-
self.s.log(85, 0)
|
139
|
-
|
140
|
-
self.assertGreater(self.s.total_rps, 2)
|
141
|
-
self.assertEqual(self.s.num_requests, 2)
|
142
|
-
self.assertEqual(self.s.num_failures, 1)
|
143
|
-
self.assertEqual(self.s.avg_response_time, 420.5)
|
144
|
-
self.assertEqual(self.s.median_response_time, 85)
|
145
|
-
self.assertNotEqual(None, self.s.last_request_timestamp)
|
146
|
-
self.s.reset()
|
147
|
-
self.assertEqual(None, self.s.last_request_timestamp)
|
148
|
-
|
149
|
-
def test_avg_only_none(self):
|
150
|
-
self.s.reset()
|
151
|
-
self.s.log(None, 123)
|
152
|
-
self.assertEqual(self.s.avg_response_time, 0)
|
153
|
-
self.assertEqual(self.s.median_response_time, 0)
|
154
|
-
self.assertEqual(self.s.get_response_time_percentile(0.5), 0)
|
155
|
-
|
156
|
-
def test_reset_min_response_time(self):
|
157
|
-
self.s.reset()
|
158
|
-
self.s.log(756, 0)
|
159
|
-
self.assertEqual(756, self.s.min_response_time)
|
160
|
-
|
161
|
-
def test_aggregation(self):
|
162
|
-
s1 = StatsEntry(self.stats, "aggregate me!", "GET")
|
163
|
-
s1.log(12, 0)
|
164
|
-
s1.log(12, 0)
|
165
|
-
s1.log(38, 0)
|
166
|
-
s1.log_error("Dummy exception")
|
167
|
-
|
168
|
-
s2 = StatsEntry(self.stats, "aggregate me!", "GET")
|
169
|
-
s2.log_error("Dummy exception")
|
170
|
-
s2.log_error("Dummy exception")
|
171
|
-
s2.log(12, 0)
|
172
|
-
s2.log(99, 0)
|
173
|
-
s2.log(14, 0)
|
174
|
-
s2.log(55, 0)
|
175
|
-
s2.log(38, 0)
|
176
|
-
s2.log(55, 0)
|
177
|
-
s2.log(97, 0)
|
178
|
-
|
179
|
-
s = StatsEntry(self.stats, "GET", "")
|
180
|
-
s.extend(s1)
|
181
|
-
s.extend(s2)
|
182
|
-
|
183
|
-
self.assertEqual(s.num_requests, 10)
|
184
|
-
self.assertEqual(s.num_failures, 3)
|
185
|
-
self.assertEqual(s.median_response_time, 38)
|
186
|
-
self.assertEqual(s.avg_response_time, 43.2)
|
187
|
-
|
188
|
-
def test_aggregation_with_rounding(self):
|
189
|
-
s1 = StatsEntry(self.stats, "round me!", "GET")
|
190
|
-
s1.log(122, 0) # (rounded 120) min
|
191
|
-
s1.log(992, 0) # (rounded 990) max
|
192
|
-
s1.log(142, 0) # (rounded 140)
|
193
|
-
s1.log(552, 0) # (rounded 550)
|
194
|
-
s1.log(557, 0) # (rounded 560)
|
195
|
-
s1.log(387, 0) # (rounded 390)
|
196
|
-
s1.log(557, 0) # (rounded 560)
|
197
|
-
s1.log(977, 0) # (rounded 980)
|
198
|
-
|
199
|
-
self.assertEqual(s1.num_requests, 8)
|
200
|
-
self.assertEqual(s1.median_response_time, 550)
|
201
|
-
self.assertEqual(s1.avg_response_time, 535.75)
|
202
|
-
self.assertEqual(s1.min_response_time, 122)
|
203
|
-
self.assertEqual(s1.max_response_time, 992)
|
204
|
-
|
205
|
-
def test_aggregation_with_decimal_rounding(self):
|
206
|
-
s1 = StatsEntry(self.stats, "round me!", "GET")
|
207
|
-
s1.log(1.1, 0)
|
208
|
-
s1.log(1.99, 0)
|
209
|
-
s1.log(3.1, 0)
|
210
|
-
self.assertEqual(s1.num_requests, 3)
|
211
|
-
self.assertEqual(s1.median_response_time, 2)
|
212
|
-
self.assertEqual(s1.avg_response_time, (1.1 + 1.99 + 3.1) / 3)
|
213
|
-
self.assertEqual(s1.min_response_time, 1.1)
|
214
|
-
self.assertEqual(s1.max_response_time, 3.1)
|
215
|
-
|
216
|
-
def test_aggregation_min_response_time(self):
|
217
|
-
s1 = StatsEntry(self.stats, "min", "GET")
|
218
|
-
s1.log(10, 0)
|
219
|
-
self.assertEqual(10, s1.min_response_time)
|
220
|
-
s2 = StatsEntry(self.stats, "min", "GET")
|
221
|
-
s1.extend(s2)
|
222
|
-
self.assertEqual(10, s1.min_response_time)
|
223
|
-
|
224
|
-
def test_aggregation_last_request_timestamp(self):
|
225
|
-
s1 = StatsEntry(self.stats, "r", "GET")
|
226
|
-
s2 = StatsEntry(self.stats, "r", "GET")
|
227
|
-
s1.extend(s2)
|
228
|
-
self.assertEqual(None, s1.last_request_timestamp)
|
229
|
-
s1 = StatsEntry(self.stats, "r", "GET")
|
230
|
-
s2 = StatsEntry(self.stats, "r", "GET")
|
231
|
-
s1.last_request_timestamp = 666
|
232
|
-
s1.extend(s2)
|
233
|
-
self.assertEqual(666, s1.last_request_timestamp)
|
234
|
-
s1 = StatsEntry(self.stats, "r", "GET")
|
235
|
-
s2 = StatsEntry(self.stats, "r", "GET")
|
236
|
-
s2.last_request_timestamp = 666
|
237
|
-
s1.extend(s2)
|
238
|
-
self.assertEqual(666, s1.last_request_timestamp)
|
239
|
-
s1 = StatsEntry(self.stats, "r", "GET")
|
240
|
-
s2 = StatsEntry(self.stats, "r", "GET")
|
241
|
-
s1.last_request_timestamp = 666
|
242
|
-
s1.last_request_timestamp = 700
|
243
|
-
s1.extend(s2)
|
244
|
-
self.assertEqual(700, s1.last_request_timestamp)
|
245
|
-
|
246
|
-
def test_percentile_rounded_down(self):
|
247
|
-
s1 = StatsEntry(self.stats, "rounding down!", "GET")
|
248
|
-
s1.log(122, 0) # (rounded 120) min
|
249
|
-
actual_percentile = s1.percentile().split()
|
250
|
-
|
251
|
-
self.assertEqual(actual_percentile, ["GET", "rounding", "down!"] + ["120"] * len(PERCENTILES_TO_REPORT) + ["1"])
|
252
|
-
|
253
|
-
def test_percentile_rounded_up(self):
|
254
|
-
s2 = StatsEntry(self.stats, "rounding up!", "GET")
|
255
|
-
s2.log(127, 0) # (rounded 130) min
|
256
|
-
actual_percentile = s2.percentile().split()
|
257
|
-
self.assertEqual(actual_percentile, ["GET", "rounding", "up!"] + ["130"] * len(PERCENTILES_TO_REPORT) + ["1"])
|
258
|
-
|
259
|
-
def test_custom_percentile_list(self):
|
260
|
-
s = StatsEntry(self.stats, "custom_percentiles", "GET")
|
261
|
-
custom_percentile_list = [0.50, 0.90, 0.95, 0.99]
|
262
|
-
locust.stats.PERCENTILES_TO_REPORT = custom_percentile_list
|
263
|
-
s.log(150, 0)
|
264
|
-
actual_percentile = s.percentile().split()
|
265
|
-
self.assertEqual(
|
266
|
-
actual_percentile, ["GET", "custom_percentiles"] + ["150"] * len(custom_percentile_list) + ["1"]
|
267
|
-
)
|
268
|
-
|
269
|
-
def test_error_grouping(self):
|
270
|
-
# reset stats
|
271
|
-
self.stats = RequestStats()
|
272
|
-
|
273
|
-
self.stats.log_error("GET", "/some-path", Exception("Exception!"))
|
274
|
-
self.stats.log_error("GET", "/some-path", Exception("Exception!"))
|
275
|
-
|
276
|
-
self.assertEqual(1, len(self.stats.errors))
|
277
|
-
self.assertEqual(2, list(self.stats.errors.values())[0].occurrences)
|
278
|
-
|
279
|
-
self.stats.log_error("GET", "/some-path", Exception("Another exception!"))
|
280
|
-
self.stats.log_error("GET", "/some-path", Exception("Another exception!"))
|
281
|
-
self.stats.log_error("GET", "/some-path", Exception("Third exception!"))
|
282
|
-
self.assertEqual(3, len(self.stats.errors))
|
283
|
-
|
284
|
-
def test_error_grouping_errors_with_memory_addresses(self):
|
285
|
-
# reset stats
|
286
|
-
self.stats = RequestStats()
|
287
|
-
|
288
|
-
class Dummy:
|
289
|
-
pass
|
290
|
-
|
291
|
-
self.stats.log_error("GET", "/", Exception(f"Error caused by {Dummy()!r}"))
|
292
|
-
self.assertEqual(1, len(self.stats.errors))
|
293
|
-
|
294
|
-
def test_serialize_through_message(self):
|
295
|
-
"""
|
296
|
-
Serialize a RequestStats instance, then serialize it through a Message,
|
297
|
-
and unserialize the whole thing again. This is done "IRL" when stats are sent
|
298
|
-
from workers to master.
|
299
|
-
"""
|
300
|
-
s1 = StatsEntry(self.stats, "test", "GET")
|
301
|
-
s1.log(10, 0)
|
302
|
-
s1.log(20, 0)
|
303
|
-
s1.log(40, 0)
|
304
|
-
u1 = StatsEntry.unserialize(s1.serialize())
|
305
|
-
|
306
|
-
data = Message.unserialize(Message("dummy", s1.serialize(), "none").serialize()).data
|
307
|
-
u1 = StatsEntry.unserialize(data)
|
308
|
-
|
309
|
-
self.assertEqual(20, u1.median_response_time)
|
310
|
-
|
311
|
-
|
312
|
-
class TestStatsPrinting(LocustTestCase):
|
313
|
-
def setUp(self):
|
314
|
-
super().setUp()
|
315
|
-
|
316
|
-
self.stats = RequestStats()
|
317
|
-
for i in range(100):
|
318
|
-
for method, name, freq in [
|
319
|
-
(
|
320
|
-
"GET",
|
321
|
-
"test_entry",
|
322
|
-
5,
|
323
|
-
),
|
324
|
-
(
|
325
|
-
"DELETE",
|
326
|
-
"test" * int((STATS_NAME_WIDTH - STATS_TYPE_WIDTH + 4) / len("test")),
|
327
|
-
3,
|
328
|
-
),
|
329
|
-
]:
|
330
|
-
self.stats.log_request(method, name, i, 2000 + i)
|
331
|
-
if i % freq == 0:
|
332
|
-
self.stats.log_error(method, name, RuntimeError(f"{method} error"))
|
333
|
-
|
334
|
-
def test_print_percentile_stats(self):
|
335
|
-
locust.stats.print_percentile_stats(self.stats)
|
336
|
-
info = self.mocked_log.info
|
337
|
-
self.assertEqual(8, len(info))
|
338
|
-
self.assertEqual("Response time percentiles (approximated)", info[0])
|
339
|
-
# check that headline contains same number of column as the value rows
|
340
|
-
headlines = info[1].replace("# reqs", "#reqs").split()
|
341
|
-
self.assertEqual(len(headlines), len(info[3].split()))
|
342
|
-
self.assertEqual(len(headlines) - 1, len(info[-2].split())) # Aggregated, no "Type"
|
343
|
-
self.assertEqual(info[2], info[-3]) # table ascii separators
|
344
|
-
|
345
|
-
def test_print_stats(self):
|
346
|
-
locust.stats.print_stats(self.stats)
|
347
|
-
info = self.mocked_log.info
|
348
|
-
self.assertEqual(7, len(info))
|
349
|
-
|
350
|
-
headlines = info[0].replace("# ", "#").split()
|
351
|
-
|
352
|
-
# check number of columns in separator
|
353
|
-
self.assertEqual(len(headlines), len(info[1].split("|")) + 2)
|
354
|
-
# check entry row
|
355
|
-
self.assertEqual(len(headlines), len(info[2].split()))
|
356
|
-
# check aggregated row, which is missing value in "type"-column
|
357
|
-
self.assertEqual(len(headlines) - 1, len(info[-2].split()))
|
358
|
-
# table ascii separators
|
359
|
-
self.assertEqual(info[1], info[-3])
|
360
|
-
|
361
|
-
def test_print_error_report(self):
|
362
|
-
locust.stats.print_error_report(self.stats)
|
363
|
-
info = self.mocked_log.info
|
364
|
-
self.assertEqual(7, len(info))
|
365
|
-
self.assertEqual("Error report", info[0])
|
366
|
-
|
367
|
-
headlines = info[1].replace("# ", "#").split()
|
368
|
-
# check number of columns in headlines vs table ascii separator
|
369
|
-
self.assertEqual(len(headlines), len(info[2].split("|")))
|
370
|
-
# table ascii separators
|
371
|
-
self.assertEqual(info[2], info[-2])
|
372
|
-
|
373
|
-
|
374
|
-
class TestCsvStats(LocustTestCase):
|
375
|
-
STATS_BASE_NAME = "test"
|
376
|
-
STATS_FILENAME = f"{STATS_BASE_NAME}_stats.csv"
|
377
|
-
STATS_HISTORY_FILENAME = f"{STATS_BASE_NAME}_stats_history.csv"
|
378
|
-
STATS_FAILURES_FILENAME = f"{STATS_BASE_NAME}_failures.csv"
|
379
|
-
STATS_EXCEPTIONS_FILENAME = f"{STATS_BASE_NAME}_exceptions.csv"
|
380
|
-
|
381
|
-
def setUp(self):
|
382
|
-
super().setUp()
|
383
|
-
self.remove_file_if_exists(self.STATS_FILENAME)
|
384
|
-
self.remove_file_if_exists(self.STATS_HISTORY_FILENAME)
|
385
|
-
self.remove_file_if_exists(self.STATS_FAILURES_FILENAME)
|
386
|
-
self.remove_file_if_exists(self.STATS_EXCEPTIONS_FILENAME)
|
387
|
-
|
388
|
-
def tearDown(self):
|
389
|
-
self.remove_file_if_exists(self.STATS_FILENAME)
|
390
|
-
self.remove_file_if_exists(self.STATS_HISTORY_FILENAME)
|
391
|
-
self.remove_file_if_exists(self.STATS_FAILURES_FILENAME)
|
392
|
-
self.remove_file_if_exists(self.STATS_EXCEPTIONS_FILENAME)
|
393
|
-
|
394
|
-
def remove_file_if_exists(self, filename):
|
395
|
-
if os.path.exists(filename):
|
396
|
-
os.remove(filename)
|
397
|
-
|
398
|
-
def test_write_csv_files(self):
|
399
|
-
_write_csv_files(self.environment, self.STATS_BASE_NAME)
|
400
|
-
self.assertTrue(os.path.exists(self.STATS_FILENAME))
|
401
|
-
self.assertTrue(os.path.exists(self.STATS_HISTORY_FILENAME))
|
402
|
-
self.assertTrue(os.path.exists(self.STATS_FAILURES_FILENAME))
|
403
|
-
self.assertTrue(os.path.exists(self.STATS_EXCEPTIONS_FILENAME))
|
404
|
-
|
405
|
-
def test_write_csv_files_full_history(self):
|
406
|
-
_write_csv_files(self.environment, self.STATS_BASE_NAME, full_history=True)
|
407
|
-
self.assertTrue(os.path.exists(self.STATS_FILENAME))
|
408
|
-
self.assertTrue(os.path.exists(self.STATS_HISTORY_FILENAME))
|
409
|
-
self.assertTrue(os.path.exists(self.STATS_FAILURES_FILENAME))
|
410
|
-
self.assertTrue(os.path.exists(self.STATS_EXCEPTIONS_FILENAME))
|
411
|
-
|
412
|
-
@mock.patch("locust.stats.CSV_STATS_INTERVAL_SEC", new=_TEST_CSV_STATS_INTERVAL_SEC)
|
413
|
-
def test_csv_stats_writer(self):
|
414
|
-
_write_csv_files(self.environment, self.STATS_BASE_NAME)
|
415
|
-
|
416
|
-
self.assertTrue(os.path.exists(self.STATS_FILENAME))
|
417
|
-
self.assertTrue(os.path.exists(self.STATS_HISTORY_FILENAME))
|
418
|
-
self.assertTrue(os.path.exists(self.STATS_FAILURES_FILENAME))
|
419
|
-
self.assertTrue(os.path.exists(self.STATS_EXCEPTIONS_FILENAME))
|
420
|
-
|
421
|
-
with open(self.STATS_HISTORY_FILENAME) as f:
|
422
|
-
reader = csv.DictReader(f)
|
423
|
-
rows = [r for r in reader]
|
424
|
-
|
425
|
-
self.assertEqual(2, len(rows))
|
426
|
-
self.assertEqual("Aggregated", rows[0]["Name"])
|
427
|
-
self.assertEqual("Aggregated", rows[1]["Name"])
|
428
|
-
|
429
|
-
@mock.patch("locust.stats.CSV_STATS_INTERVAL_SEC", new=_TEST_CSV_STATS_INTERVAL_SEC)
|
430
|
-
def test_csv_stats_writer_full_history(self):
|
431
|
-
stats_writer = StatsCSVFileWriter(
|
432
|
-
self.environment, PERCENTILES_TO_REPORT, self.STATS_BASE_NAME, full_history=True
|
433
|
-
)
|
434
|
-
|
435
|
-
for i in range(10):
|
436
|
-
self.runner.stats.log_request("GET", "/", 100, content_length=666)
|
437
|
-
|
438
|
-
greenlet = gevent.spawn(stats_writer)
|
439
|
-
gevent.sleep(10)
|
440
|
-
|
441
|
-
for i in range(10):
|
442
|
-
self.runner.stats.log_request("GET", "/", 10, content_length=666)
|
443
|
-
|
444
|
-
gevent.sleep(5)
|
445
|
-
|
446
|
-
gevent.sleep(_TEST_CSV_STATS_INTERVAL_WAIT_SEC)
|
447
|
-
gevent.kill(greenlet)
|
448
|
-
stats_writer.close_files()
|
449
|
-
|
450
|
-
self.assertTrue(os.path.exists(self.STATS_FILENAME))
|
451
|
-
self.assertTrue(os.path.exists(self.STATS_HISTORY_FILENAME))
|
452
|
-
self.assertTrue(os.path.exists(self.STATS_FAILURES_FILENAME))
|
453
|
-
self.assertTrue(os.path.exists(self.STATS_EXCEPTIONS_FILENAME))
|
454
|
-
|
455
|
-
with open(self.STATS_HISTORY_FILENAME) as f:
|
456
|
-
reader = csv.DictReader(f)
|
457
|
-
rows = [r for r in reader]
|
458
|
-
|
459
|
-
self.assertGreaterEqual(len(rows), 130)
|
460
|
-
|
461
|
-
self.assertEqual("/", rows[0]["Name"])
|
462
|
-
self.assertEqual("Aggregated", rows[1]["Name"])
|
463
|
-
self.assertEqual("/", rows[2]["Name"])
|
464
|
-
self.assertEqual("Aggregated", rows[3]["Name"])
|
465
|
-
self.assertEqual("20", rows[-1]["Total Request Count"])
|
466
|
-
|
467
|
-
saw100 = False
|
468
|
-
saw10 = False
|
469
|
-
|
470
|
-
for row in rows:
|
471
|
-
if not saw100 and row["95%"] == "100":
|
472
|
-
saw100 = True
|
473
|
-
elif saw100 and row["95%"] == "10":
|
474
|
-
saw10 = True
|
475
|
-
break
|
476
|
-
|
477
|
-
self.assertTrue(saw100, "Never saw 95th percentile increase to 100")
|
478
|
-
self.assertTrue(saw10, "Never saw 95th percentile decrease to 10")
|
479
|
-
|
480
|
-
def test_csv_stats_on_master_from_aggregated_stats(self):
|
481
|
-
# Failing test for: https://github.com/locustio/locust/issues/1315
|
482
|
-
with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server:
|
483
|
-
environment = Environment()
|
484
|
-
stats_writer = StatsCSVFileWriter(
|
485
|
-
environment, PERCENTILES_TO_REPORT, self.STATS_BASE_NAME, full_history=True
|
486
|
-
)
|
487
|
-
master = environment.create_master_runner(master_bind_host="*", master_bind_port=0)
|
488
|
-
greenlet = gevent.spawn(stats_writer)
|
489
|
-
gevent.sleep(_TEST_CSV_STATS_INTERVAL_WAIT_SEC)
|
490
|
-
|
491
|
-
server.mocked_send(Message("client_ready", __version__, "fake_client"))
|
492
|
-
|
493
|
-
master.stats.entries[("/", "GET")].log(100, 23455)
|
494
|
-
master.stats.entries[("/", "GET")].log(800, 23455)
|
495
|
-
master.stats.entries[("/", "GET")].log(700, 23455)
|
496
|
-
|
497
|
-
data = {"user_count": 1}
|
498
|
-
environment.events.report_to_master.fire(client_id="fake_client", data=data)
|
499
|
-
master.stats.clear_all()
|
500
|
-
|
501
|
-
server.mocked_send(Message("stats", data, "fake_client"))
|
502
|
-
s = master.stats.entries[("/", "GET")]
|
503
|
-
self.assertEqual(700, s.median_response_time)
|
504
|
-
|
505
|
-
gevent.kill(greenlet)
|
506
|
-
stats_writer.close_files()
|
507
|
-
|
508
|
-
self.assertTrue(os.path.exists(self.STATS_FILENAME))
|
509
|
-
self.assertTrue(os.path.exists(self.STATS_HISTORY_FILENAME))
|
510
|
-
self.assertTrue(os.path.exists(self.STATS_FAILURES_FILENAME))
|
511
|
-
self.assertTrue(os.path.exists(self.STATS_EXCEPTIONS_FILENAME))
|
512
|
-
|
513
|
-
@mock.patch("locust.stats.CSV_STATS_INTERVAL_SEC", new=_TEST_CSV_STATS_INTERVAL_SEC)
|
514
|
-
def test_user_count_in_csv_history_stats(self):
|
515
|
-
start_time = int(time.time())
|
516
|
-
|
517
|
-
class TestUser(User):
|
518
|
-
wait_time = constant(10)
|
519
|
-
|
520
|
-
@task
|
521
|
-
def t(self):
|
522
|
-
self.environment.runner.stats.log_request("GET", "/", 10, 10)
|
523
|
-
|
524
|
-
environment = Environment(user_classes=[TestUser])
|
525
|
-
stats_writer = StatsCSVFileWriter(environment, PERCENTILES_TO_REPORT, self.STATS_BASE_NAME, full_history=True)
|
526
|
-
runner = environment.create_local_runner()
|
527
|
-
# spawn a user every _TEST_CSV_STATS_INTERVAL_SEC second
|
528
|
-
user_count = 15
|
529
|
-
spawn_rate = 5
|
530
|
-
assert 1 / 5 == _TEST_CSV_STATS_INTERVAL_SEC
|
531
|
-
runner_greenlet = gevent.spawn(runner.start, user_count, spawn_rate)
|
532
|
-
gevent.sleep(0.1)
|
533
|
-
|
534
|
-
greenlet = gevent.spawn(stats_writer)
|
535
|
-
gevent.sleep(user_count / spawn_rate)
|
536
|
-
gevent.kill(greenlet)
|
537
|
-
stats_writer.close_files()
|
538
|
-
runner.stop()
|
539
|
-
gevent.kill(runner_greenlet)
|
540
|
-
|
541
|
-
with open(self.STATS_HISTORY_FILENAME) as f:
|
542
|
-
reader = csv.DictReader(f)
|
543
|
-
rows = [r for r in reader]
|
544
|
-
|
545
|
-
self.assertEqual(2 * user_count, len(rows))
|
546
|
-
for i in range(int(user_count / spawn_rate)):
|
547
|
-
for _ in range(spawn_rate):
|
548
|
-
row = rows.pop(0)
|
549
|
-
self.assertEqual("%i" % ((i + 1) * spawn_rate), row["User Count"])
|
550
|
-
self.assertEqual("/", row["Name"])
|
551
|
-
self.assertEqual("%i" % ((i + 1) * spawn_rate), row["Total Request Count"])
|
552
|
-
self.assertGreaterEqual(int(row["Timestamp"]), start_time)
|
553
|
-
row = rows.pop(0)
|
554
|
-
self.assertEqual("%i" % ((i + 1) * spawn_rate), row["User Count"])
|
555
|
-
self.assertEqual("Aggregated", row["Name"])
|
556
|
-
self.assertEqual("%i" % ((i + 1) * spawn_rate), row["Total Request Count"])
|
557
|
-
self.assertGreaterEqual(int(row["Timestamp"]), start_time)
|
558
|
-
|
559
|
-
def test_requests_csv_quote_escaping(self):
|
560
|
-
with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server:
|
561
|
-
environment = Environment()
|
562
|
-
master = environment.create_master_runner(master_bind_host="*", master_bind_port=0)
|
563
|
-
server.mocked_send(Message("client_ready", __version__, "fake_client"))
|
564
|
-
|
565
|
-
request_name_dict = {
|
566
|
-
"scenario": "get cashes",
|
567
|
-
"path": "/cash/[amount]",
|
568
|
-
"arguments": [{"size": 1}],
|
569
|
-
}
|
570
|
-
request_name_str = json.dumps(request_name_dict)
|
571
|
-
|
572
|
-
master.stats.entries[(request_name_str, "GET")].log(100, 23455)
|
573
|
-
data = {"user_count": 1}
|
574
|
-
environment.events.report_to_master.fire(client_id="fake_client", data=data)
|
575
|
-
master.stats.clear_all()
|
576
|
-
server.mocked_send(Message("stats", data, "fake_client"))
|
577
|
-
|
578
|
-
_write_csv_files(environment, self.STATS_BASE_NAME, full_history=True)
|
579
|
-
with open(self.STATS_FILENAME) as f:
|
580
|
-
reader = csv.DictReader(f)
|
581
|
-
rows = [r for r in reader]
|
582
|
-
csv_request_name = rows[0].get("Name")
|
583
|
-
self.assertEqual(request_name_str, csv_request_name)
|
584
|
-
|
585
|
-
def test_stats_history(self):
|
586
|
-
env1 = Environment(events=locust.events, catch_exceptions=False)
|
587
|
-
runner1 = env1.create_master_runner("127.0.0.1", 5558)
|
588
|
-
env2 = Environment(events=locust.events, catch_exceptions=False)
|
589
|
-
runner2 = env2.create_worker_runner("127.0.0.1", 5558)
|
590
|
-
greenlet1 = gevent.spawn(stats_history, runner1)
|
591
|
-
greenlet2 = gevent.spawn(stats_history, runner2)
|
592
|
-
gevent.sleep(1)
|
593
|
-
hs1 = runner1.stats.history
|
594
|
-
hs2 = runner2.stats.history
|
595
|
-
gevent.kill(greenlet1)
|
596
|
-
gevent.kill(greenlet2)
|
597
|
-
self.assertEqual(1, len(hs1))
|
598
|
-
self.assertEqual(0, len(hs2))
|
599
|
-
|
600
|
-
|
601
|
-
class TestStatsEntryResponseTimesCache(unittest.TestCase):
|
602
|
-
def setUp(self, *args, **kwargs):
|
603
|
-
super().setUp(*args, **kwargs)
|
604
|
-
self.stats = RequestStats()
|
605
|
-
|
606
|
-
def test_response_times_cached(self):
|
607
|
-
s = StatsEntry(self.stats, "/", "GET", use_response_times_cache=True)
|
608
|
-
self.assertEqual(1, len(s.response_times_cache))
|
609
|
-
s.log(11, 1337)
|
610
|
-
self.assertEqual(1, len(s.response_times_cache))
|
611
|
-
s.last_request_timestamp -= 1
|
612
|
-
s.log(666, 1337)
|
613
|
-
self.assertEqual(2, len(s.response_times_cache))
|
614
|
-
self.assertEqual(
|
615
|
-
CachedResponseTimes(
|
616
|
-
response_times={11: 1},
|
617
|
-
num_requests=1,
|
618
|
-
),
|
619
|
-
s.response_times_cache[int(s.last_request_timestamp) - 1],
|
620
|
-
)
|
621
|
-
|
622
|
-
def test_response_times_not_cached_if_not_enabled(self):
|
623
|
-
s = StatsEntry(self.stats, "/", "GET")
|
624
|
-
s.log(11, 1337)
|
625
|
-
self.assertEqual(None, s.response_times_cache)
|
626
|
-
s.last_request_timestamp -= 1
|
627
|
-
s.log(666, 1337)
|
628
|
-
self.assertEqual(None, s.response_times_cache)
|
629
|
-
|
630
|
-
def test_latest_total_response_times_pruned(self):
|
631
|
-
"""
|
632
|
-
Check that RequestStats.latest_total_response_times are pruned when exceeding 20 entries
|
633
|
-
"""
|
634
|
-
s = StatsEntry(self.stats, "/", "GET", use_response_times_cache=True)
|
635
|
-
t = int(time.time())
|
636
|
-
for i in reversed(range(2, 30)):
|
637
|
-
s.response_times_cache[t - i] = CachedResponseTimes(response_times={}, num_requests=0)
|
638
|
-
self.assertEqual(29, len(s.response_times_cache))
|
639
|
-
s.log(17, 1337)
|
640
|
-
s.last_request_timestamp -= 1
|
641
|
-
s.log(1, 1)
|
642
|
-
self.assertEqual(20, len(s.response_times_cache))
|
643
|
-
self.assertEqual(
|
644
|
-
CachedResponseTimes(response_times={17: 1}, num_requests=1),
|
645
|
-
s.response_times_cache.popitem(last=True)[1],
|
646
|
-
)
|
647
|
-
|
648
|
-
def test_get_current_response_time_percentile(self):
|
649
|
-
s = StatsEntry(self.stats, "/", "GET", use_response_times_cache=True)
|
650
|
-
t = int(time.time())
|
651
|
-
s.response_times_cache[t - 10] = CachedResponseTimes(
|
652
|
-
response_times={i: 1 for i in range(100)}, num_requests=200
|
653
|
-
)
|
654
|
-
s.response_times_cache[t - 10].response_times[1] = 201
|
655
|
-
|
656
|
-
s.response_times = {i: 2 for i in range(100)}
|
657
|
-
s.response_times[1] = 202
|
658
|
-
s.num_requests = 300
|
659
|
-
|
660
|
-
self.assertEqual(95, s.get_current_response_time_percentile(0.95))
|
661
|
-
|
662
|
-
def test_get_current_response_time_percentile_outside_cache_window(self):
|
663
|
-
s = StatsEntry(self.stats, "/", "GET", use_response_times_cache=True)
|
664
|
-
# an empty response times cache, current time will not be in this cache
|
665
|
-
s.response_times_cache = {}
|
666
|
-
self.assertEqual(None, s.get_current_response_time_percentile(0.95))
|
667
|
-
|
668
|
-
def test_diff_response_times_dicts(self):
|
669
|
-
self.assertEqual(
|
670
|
-
{1: 5, 6: 8},
|
671
|
-
diff_response_time_dicts(
|
672
|
-
{1: 6, 6: 16, 2: 2},
|
673
|
-
{1: 1, 6: 8, 2: 2},
|
674
|
-
),
|
675
|
-
)
|
676
|
-
self.assertEqual(
|
677
|
-
{},
|
678
|
-
diff_response_time_dicts(
|
679
|
-
{},
|
680
|
-
{},
|
681
|
-
),
|
682
|
-
)
|
683
|
-
self.assertEqual(
|
684
|
-
{10: 15},
|
685
|
-
diff_response_time_dicts(
|
686
|
-
{10: 15},
|
687
|
-
{},
|
688
|
-
),
|
689
|
-
)
|
690
|
-
self.assertEqual(
|
691
|
-
{10: 10},
|
692
|
-
diff_response_time_dicts(
|
693
|
-
{10: 10},
|
694
|
-
{},
|
695
|
-
),
|
696
|
-
)
|
697
|
-
self.assertEqual(
|
698
|
-
{},
|
699
|
-
diff_response_time_dicts(
|
700
|
-
{1: 1},
|
701
|
-
{1: 1},
|
702
|
-
),
|
703
|
-
)
|
704
|
-
|
705
|
-
|
706
|
-
class TestStatsEntry(unittest.TestCase):
|
707
|
-
def parse_string_output(self, text):
|
708
|
-
tokenlist = re.split(r"[\s\(\)%|]+", text.strip())
|
709
|
-
tokens = {
|
710
|
-
"method": tokenlist[0],
|
711
|
-
"name": tokenlist[1],
|
712
|
-
"request_count": int(tokenlist[2]),
|
713
|
-
"failure_count": int(tokenlist[3]),
|
714
|
-
"failure_percentage": float(tokenlist[4]),
|
715
|
-
}
|
716
|
-
return tokens
|
717
|
-
|
718
|
-
def setUp(self, *args, **kwargs):
|
719
|
-
super().setUp(*args, **kwargs)
|
720
|
-
self.stats = RequestStats()
|
721
|
-
|
722
|
-
def test_fail_ratio_with_no_failures(self):
|
723
|
-
REQUEST_COUNT = 10
|
724
|
-
FAILURE_COUNT = 0
|
725
|
-
EXPECTED_FAIL_RATIO = 0.0
|
726
|
-
|
727
|
-
s = StatsEntry(self.stats, "/", "GET")
|
728
|
-
s.num_requests = REQUEST_COUNT
|
729
|
-
s.num_failures = FAILURE_COUNT
|
730
|
-
|
731
|
-
self.assertAlmostEqual(s.fail_ratio, EXPECTED_FAIL_RATIO)
|
732
|
-
output_fields = self.parse_string_output(str(s))
|
733
|
-
self.assertEqual(output_fields["request_count"], REQUEST_COUNT)
|
734
|
-
self.assertEqual(output_fields["failure_count"], FAILURE_COUNT)
|
735
|
-
self.assertAlmostEqual(output_fields["failure_percentage"], EXPECTED_FAIL_RATIO * 100)
|
736
|
-
|
737
|
-
def test_fail_ratio_with_all_failures(self):
|
738
|
-
REQUEST_COUNT = 10
|
739
|
-
FAILURE_COUNT = 10
|
740
|
-
EXPECTED_FAIL_RATIO = 1.0
|
741
|
-
|
742
|
-
s = StatsEntry(self.stats, "/", "GET")
|
743
|
-
s.num_requests = REQUEST_COUNT
|
744
|
-
s.num_failures = FAILURE_COUNT
|
745
|
-
|
746
|
-
self.assertAlmostEqual(s.fail_ratio, EXPECTED_FAIL_RATIO)
|
747
|
-
output_fields = self.parse_string_output(str(s))
|
748
|
-
self.assertEqual(output_fields["request_count"], REQUEST_COUNT)
|
749
|
-
self.assertEqual(output_fields["failure_count"], FAILURE_COUNT)
|
750
|
-
self.assertAlmostEqual(output_fields["failure_percentage"], EXPECTED_FAIL_RATIO * 100)
|
751
|
-
|
752
|
-
def test_fail_ratio_with_half_failures(self):
|
753
|
-
REQUEST_COUNT = 10
|
754
|
-
FAILURE_COUNT = 5
|
755
|
-
EXPECTED_FAIL_RATIO = 0.5
|
756
|
-
|
757
|
-
s = StatsEntry(self.stats, "/", "GET")
|
758
|
-
s.num_requests = REQUEST_COUNT
|
759
|
-
s.num_failures = FAILURE_COUNT
|
760
|
-
|
761
|
-
self.assertAlmostEqual(s.fail_ratio, EXPECTED_FAIL_RATIO)
|
762
|
-
output_fields = self.parse_string_output(str(s))
|
763
|
-
self.assertEqual(output_fields["request_count"], REQUEST_COUNT)
|
764
|
-
self.assertEqual(output_fields["failure_count"], FAILURE_COUNT)
|
765
|
-
self.assertAlmostEqual(output_fields["failure_percentage"], EXPECTED_FAIL_RATIO * 100)
|
766
|
-
|
767
|
-
|
768
|
-
class TestRequestStatsWithWebserver(WebserverTestCase):
|
769
|
-
def setUp(self):
|
770
|
-
super().setUp()
|
771
|
-
|
772
|
-
class MyUser(HttpUser):
|
773
|
-
host = "http://127.0.0.1:%i" % self.port
|
774
|
-
|
775
|
-
self.locust = MyUser(self.environment)
|
776
|
-
|
777
|
-
def test_request_stats_content_length(self):
|
778
|
-
self.locust.client.get("/ultra_fast")
|
779
|
-
self.assertEqual(
|
780
|
-
self.runner.stats.entries[("/ultra_fast", "GET")].avg_content_length, len("This is an ultra fast response")
|
781
|
-
)
|
782
|
-
self.locust.client.get("/ultra_fast")
|
783
|
-
# test legacy stats.get() function sometimes too
|
784
|
-
self.assertEqual(
|
785
|
-
self.runner.stats.get("/ultra_fast", "GET").avg_content_length, len("This is an ultra fast response")
|
786
|
-
)
|
787
|
-
|
788
|
-
def test_request_stats_no_content_length(self):
|
789
|
-
path = "/no_content_length"
|
790
|
-
self.locust.client.get(path)
|
791
|
-
self.assertEqual(
|
792
|
-
self.runner.stats.entries[(path, "GET")].avg_content_length,
|
793
|
-
len("This response does not have content-length in the header"),
|
794
|
-
)
|
795
|
-
|
796
|
-
def test_request_stats_no_content_length_streaming(self):
|
797
|
-
path = "/no_content_length"
|
798
|
-
self.locust.client.get(path, stream=True)
|
799
|
-
self.assertEqual(0, self.runner.stats.entries[(path, "GET")].avg_content_length)
|
800
|
-
|
801
|
-
def test_request_stats_named_endpoint(self):
|
802
|
-
self.locust.client.get("/ultra_fast", name="my_custom_name")
|
803
|
-
self.assertEqual(1, self.runner.stats.entries[("my_custom_name", "GET")].num_requests)
|
804
|
-
|
805
|
-
def test_request_stats_named_endpoint_request_name(self):
|
806
|
-
self.locust.client.request_name = "my_custom_name_1"
|
807
|
-
self.locust.client.get("/ultra_fast")
|
808
|
-
self.assertEqual(1, self.runner.stats.entries[("my_custom_name_1", "GET")].num_requests)
|
809
|
-
self.locust.client.request_name = None
|
810
|
-
|
811
|
-
def test_request_stats_named_endpoint_rename_request(self):
|
812
|
-
with self.locust.client.rename_request("my_custom_name_3"):
|
813
|
-
self.locust.client.get("/ultra_fast")
|
814
|
-
self.assertEqual(1, self.runner.stats.entries[("my_custom_name_3", "GET")].num_requests)
|
815
|
-
|
816
|
-
def test_request_stats_query_variables(self):
|
817
|
-
self.locust.client.get("/ultra_fast?query=1")
|
818
|
-
self.assertEqual(1, self.runner.stats.entries[("/ultra_fast?query=1", "GET")].num_requests)
|
819
|
-
|
820
|
-
def test_request_stats_put(self):
|
821
|
-
self.locust.client.put("/put")
|
822
|
-
self.assertEqual(1, self.runner.stats.entries[("/put", "PUT")].num_requests)
|
823
|
-
|
824
|
-
def test_request_connection_error(self):
|
825
|
-
class MyUser(HttpUser):
|
826
|
-
host = "http://localhost:1"
|
827
|
-
|
828
|
-
locust = MyUser(self.environment)
|
829
|
-
response = locust.client.get("/", timeout=0.1)
|
830
|
-
self.assertEqual(response.status_code, 0)
|
831
|
-
self.assertEqual(1, self.runner.stats.entries[("/", "GET")].num_failures)
|
832
|
-
self.assertEqual(1, self.runner.stats.entries[("/", "GET")].num_requests)
|
833
|
-
|
834
|
-
|
835
|
-
class MyTaskSet(TaskSet):
|
836
|
-
@task(75)
|
837
|
-
def root_task(self):
|
838
|
-
pass
|
839
|
-
|
840
|
-
@task(25)
|
841
|
-
class MySubTaskSet(TaskSet):
|
842
|
-
@task
|
843
|
-
def task1(self):
|
844
|
-
pass
|
845
|
-
|
846
|
-
@task
|
847
|
-
def task2(self):
|
848
|
-
pass
|
849
|
-
|
850
|
-
|
851
|
-
class TestInspectUser(unittest.TestCase):
|
852
|
-
def test_get_task_ratio_relative(self):
|
853
|
-
ratio = _get_task_ratio([MyTaskSet], False, 1.0)
|
854
|
-
self.assertEqual(1.0, ratio["MyTaskSet"]["ratio"])
|
855
|
-
self.assertEqual(0.75, ratio["MyTaskSet"]["tasks"]["root_task"]["ratio"])
|
856
|
-
self.assertEqual(0.25, ratio["MyTaskSet"]["tasks"]["MySubTaskSet"]["ratio"])
|
857
|
-
self.assertEqual(0.5, ratio["MyTaskSet"]["tasks"]["MySubTaskSet"]["tasks"]["task1"]["ratio"])
|
858
|
-
self.assertEqual(0.5, ratio["MyTaskSet"]["tasks"]["MySubTaskSet"]["tasks"]["task2"]["ratio"])
|
859
|
-
|
860
|
-
def test_get_task_ratio_total(self):
|
861
|
-
ratio = _get_task_ratio([MyTaskSet], True, 1.0)
|
862
|
-
self.assertEqual(1.0, ratio["MyTaskSet"]["ratio"])
|
863
|
-
self.assertEqual(0.75, ratio["MyTaskSet"]["tasks"]["root_task"]["ratio"])
|
864
|
-
self.assertEqual(0.25, ratio["MyTaskSet"]["tasks"]["MySubTaskSet"]["ratio"])
|
865
|
-
self.assertEqual(0.125, ratio["MyTaskSet"]["tasks"]["MySubTaskSet"]["tasks"]["task1"]["ratio"])
|
866
|
-
self.assertEqual(0.125, ratio["MyTaskSet"]["tasks"]["MySubTaskSet"]["tasks"]["task2"]["ratio"])
|