Skip to content

Commit

Permalink
Added session.print (#161)
Browse files Browse the repository at this point in the history
* added print to the console
* fixed task leak
  • Loading branch information
tarekziade authored Nov 15, 2023
1 parent df99fd3 commit b248d69
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 17 deletions.
8 changes: 8 additions & 0 deletions molotov/_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,12 @@ def grpc_session(loop, console, verbose, statsd, trace_config, **kw):
url = kw["grpc_url"]
channel = aio.insecure_channel(url)
channel._trace_configs = [trace_config] # type: ignore

def _print(data):
if console is None:
print(data)
else:
console.print(data)

channel.print = _print # type: ignore
return channel
11 changes: 11 additions & 0 deletions molotov/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,24 @@ def get_session(loop, console, verbose=0, statsd=None, kind="http", **kw):
request_class.verbose = verbose
request_class.response_class = LoggedClientResponse
request_class.tracer = trace_config

# patching the class to avoid aiohttp warning
def _print(self, data):
if self.console is None:
print(data)
else:
self.console.print(data)

ClientSession.print = _print # type: ignore

session = ClientSession(
request_class=request_class,
response_class=LoggedClientResponse,
connector=connector,
trace_configs=[trace_config],
**kw,
)
session.console = console

return session

Expand Down
5 changes: 4 additions & 1 deletion molotov/tests/example10.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@


@scenario(weight=40)
async def grpc_scenario(session, session_factory="grpc", grpc_url="ipv4:///127.0.0.1:50051"):
async def grpc_scenario(
session, session_factory="grpc", grpc_url="ipv4:///127.0.0.1:50051"
):
stub = helloworld_pb2_grpc.GreeterStub(session)
response = await stub.SayHello(helloworld_pb2.HelloRequest(name="Alice"))
session.print("Call done")
assert response.message == "Hello, Alice!", response.message
6 changes: 6 additions & 0 deletions molotov/tests/example11.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import molotov


@molotov.scenario()
async def test_print(session):
session.print("Hello")
8 changes: 6 additions & 2 deletions molotov/tests/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ async def read(self):

def feed_data(self, data):
if body == b"":
err = AttributeError("'EmptyStreamReader' object has no " "attribute 'unread_data'")
err = AttributeError(
"'EmptyStreamReader' object has no " "attribute 'unread_data'"
)
raise err
pass

Expand Down Expand Up @@ -363,7 +365,9 @@ async def _slept(delay, result=None, *, loop=None):
# forces a context switch
await original(0)

with patch("asyncio.sleep", _slept):
with patch("asyncio.sleep", _slept), patch(
"molotov.util.cancellable_sleep", _slept
):
yield calls


Expand Down
28 changes: 26 additions & 2 deletions molotov/tests/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,9 @@ async def sizer(session):
stdout, stderr = stdout.read().strip(), stderr.read().strip()

# stdout, stderr, rc = self._test_molotov()
ratio = float(counters["FAILED"].value) / float(counters["OK"].value) * 100.0
ratio = (
float(counters["FAILED"].value) / float(counters["OK"].value) * 100.0
)
self.assertTrue(ratio >= 4.75, ratio)

@co_catch_output
Expand Down Expand Up @@ -805,7 +807,9 @@ async def scenario_one(session):
}
data = json.dumps({"1": "xxx"})

with aiohttp.MultipartWriter("form-data", boundary=boundary) as mpwriter:
with aiohttp.MultipartWriter(
"form-data", boundary=boundary
) as mpwriter:
mpwriter.append(
data,
{
Expand Down Expand Up @@ -847,4 +851,24 @@ def test_grpc_factory(self):

with grpc_server():
stdout, stderr, rc = self._test_molotov("--max-runs", "1", test)

self.assertTrue("Call done" in stdout, stdout)
self.assertTrue("SUCCESSES: 1" in stdout, stdout)

@co_catch_output
@dedicatedloop
def test_print_ui(self):
test = os.path.join(_HERE, "example11.py")

with coserver():
stdout, stderr, rc = self._test_molotov("--max-runs", "1", test)
self.assertTrue("Hello" in stdout, stdout)

@co_catch_output
@dedicatedloop
def test_print_console(self):
test = os.path.join(_HERE, "example11.py")

with coserver():
stdout, stderr, rc = self._test_molotov("--max-runs", "1", "-c", test)
self.assertTrue("Hello" in stdout, stdout)
34 changes: 22 additions & 12 deletions molotov/ui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
TerminalController,
create_key_bindings,
)
from molotov.util import cancellable_sleep

TITLE = HTML(f"<b>Molotov v{__version__}</b> ~ Happy Breaking 🥛🔨 ~ <i>Ctrl+C to abort</i>")
TITLE = HTML(
f"<b>Molotov v{__version__}</b> ~ Happy Breaking 🥛🔨 ~ <i>Ctrl+C to abort</i>"
)


class MolotovApp:
Expand Down Expand Up @@ -61,19 +64,22 @@ def __init__(
self.refresh_interval = refresh_interval
self._running = False

def _dump_term(self):
for line in self.terminal.dump():
sys.stdout.write(line)
sys.stdout.flush()

def _dump_errors(self):
for line in self.errors.dump():
sys.stdout.write(line)
sys.stdout.flush()

async def refresh_console(self):
while self._running:
for line in self.terminal.dump():
sys.stdout.write(line)
sys.stdout.flush()

self._dump_term()
await asyncio.sleep(0)

for line in self.errors.dump():
sys.stdout.write(line)
sys.stdout.flush()

await asyncio.sleep(self.refresh_interval)
self._dump_errors()
await cancellable_sleep(self.refresh_interval)

async def start(self):
self._running = True
Expand Down Expand Up @@ -126,7 +132,11 @@ def _handle_exception(*args, **kw):

async def stop(self):
self._running = False
await asyncio.sleep(0)
cancellable_sleep.cancel_all()

# dump any remaining data
self._dump_term()
self._dump_errors()

if not self.simple_console:
try:
Expand Down
1 change: 1 addition & 0 deletions molotov/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ async def _run(self):
self.print(f"Ran {self.count} scenarios")
step_start = now()
result = await self.step(self.count, scenario=single, options=options)

if result == 1:
self.results["OK"] += 1
self.results["MINUTE_OK"] += 1
Expand Down

0 comments on commit b248d69

Please sign in to comment.