Skip to content

Commit aee5c02

Browse files
tchatonlexierule
authored andcommitted
(hot fix) Resolve Boring App (#14684)
* resolve_boring_app * update * update * update * update * update * update * update * update * update * update * update * update * update
1 parent e2a639f commit aee5c02

File tree

5 files changed

+30
-66
lines changed

5 files changed

+30
-66
lines changed

src/lightning_app/cli/lightning_cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from lightning_app.utilities.cluster_logs import _cluster_logs_reader
3333
from lightning_app.utilities.exceptions import LogLinesLimitExceeded
3434
from lightning_app.utilities.login import Auth
35-
from lightning_app.utilities.logs_socket_api import _ClusterLogsSocketAPI
35+
from lightning_app.utilities.logs_socket_api import _ClusterLogsSocketAPI, _LightningLogsSocketAPI
3636
from lightning_app.utilities.network import LightningClient
3737

3838
logger = Logger(__name__)
@@ -153,7 +153,7 @@ def logs(app_name: str, components: List[str], follow: bool) -> None:
153153
raise click.ClickException(f"Component '{component}' does not exist in app {app_name}.")
154154

155155
log_reader = _app_logs_reader(
156-
logs_api_client=client,
156+
logs_api_client=_LightningLogsSocketAPI(client.api_client),
157157
project_id=project.project_id,
158158
app_id=apps[app_name].id,
159159
component_names=components,

src/lightning_app/testing/testing.py

Lines changed: 14 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import sys
77
import tempfile
88
import time
9-
import traceback
109
from contextlib import contextmanager
1110
from multiprocessing import Process
1211
from subprocess import Popen
@@ -38,7 +37,6 @@
3837

3938

4039
def _on_error_callback(ws_app, *_):
41-
print(traceback.format_exc())
4240
ws_app.close()
4341

4442

@@ -210,7 +208,9 @@ def run_cli(args) -> Generator:
210208

211209
@requires("playwright")
212210
@contextmanager
213-
def run_app_in_cloud(app_folder: str, app_name: str = "app.py", extra_args: [str] = []) -> Generator:
211+
def run_app_in_cloud(
212+
app_folder: str, app_name: str = "app.py", extra_args: List[str] = [], debug: bool = True
213+
) -> Generator:
214214
"""This utility is used to automate testing e2e application with lightning_app.ai."""
215215
# 1. Validate the provide app_folder is correct.
216216
if not os.path.exists(os.path.join(app_folder, "app.py")):
@@ -239,7 +239,8 @@ def run_app_in_cloud(app_folder: str, app_name: str = "app.py", extra_args: [str
239239
with tempfile.TemporaryDirectory() as tmpdir:
240240
env_copy = os.environ.copy()
241241
env_copy["PACKAGE_LIGHTNING"] = "1"
242-
env_copy["LIGHTNING_DEBUG"] = "1"
242+
if debug:
243+
env_copy["LIGHTNING_DEBUG"] = "1"
243244
shutil.copytree(app_folder, tmpdir, dirs_exist_ok=True)
244245
# TODO - add -no-cache to the command line.
245246
process = Popen(
@@ -308,7 +309,7 @@ def run_app_in_cloud(app_folder: str, app_name: str = "app.py", extra_args: [str
308309
""",
309310
[LIGHTNING_CLOUD_PROJECT_ID],
310311
)
311-
admin_page.goto(f"{Config.url}/{Config.username}/apps")
312+
admin_page.goto(f"{Config.url}/{Config.username}/apps", timeout=60 * 1000)
312313

313314
# Closing the Complete your profile dialog
314315
try:
@@ -339,15 +340,6 @@ def run_app_in_cloud(app_folder: str, app_name: str = "app.py", extra_args: [str
339340
print("'Create Project' dialog not visible, skipping.")
340341

341342
admin_page.locator(f"text={name}").click()
342-
admin_page.evaluate(
343-
"""data => {
344-
window.localStorage.setItem('gridUserId', data[0]);
345-
window.localStorage.setItem('gridUserKey', data[1]);
346-
window.localStorage.setItem('gridUserToken', data[2]);
347-
}
348-
""",
349-
[Config.id, Config.key, token],
350-
)
351343
sleep(5)
352344
# Scroll to the bottom of the page. Used to capture all logs.
353345
admin_page.evaluate(
@@ -376,8 +368,9 @@ def run_app_in_cloud(app_folder: str, app_name: str = "app.py", extra_args: [str
376368
assert len(lightning_apps) == 1
377369
app_id = lightning_apps[0].id
378370

379-
process = Process(target=print_logs, kwargs={"app_id": app_id})
380-
process.start()
371+
if debug:
372+
process = Process(target=print_logs, kwargs={"app_id": app_id})
373+
process.start()
381374

382375
while True:
383376
try:
@@ -418,40 +411,11 @@ def fetch_logs(component_names: Optional[List[str]] = None) -> Generator:
418411
except KeyboardInterrupt:
419412
pass
420413
finally:
421-
has_finished = False
422-
while not has_finished:
423-
try:
424-
button = admin_page.locator('[data-cy="stop"]')
425-
try:
426-
button.wait_for(timeout=3 * 1000)
427-
button.click()
428-
except (playwright._impl._api_types.Error, playwright._impl._api_types.TimeoutError):
429-
pass
430-
context.close()
431-
browser.close()
432-
433-
list_lightningapps = client.lightningapp_instance_service_list_lightningapp_instances(
434-
project.project_id
435-
)
436-
437-
for lightningapp in list_lightningapps.lightningapps:
438-
if lightningapp.name != name:
439-
continue
440-
try:
441-
res = client.lightningapp_instance_service_delete_lightningapp_instance(
442-
project_id=project.project_id,
443-
id=lightningapp.id,
444-
)
445-
assert res == {}
446-
except ApiException as e:
447-
print(f"Failed to delete {lightningapp.name}. Exception {e}")
448-
449-
process.kill()
450-
has_finished = True
451-
except Exception:
452-
pass
453-
454-
Popen("lightning disconnect", shell=True).wait()
414+
if debug:
415+
process.kill()
416+
417+
context.close()
418+
browser.close()
455419

456420

457421
def wait_for(page, callback: Callable, *args, **kwargs) -> Any:

src/lightning_app/utilities/app_logs.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import json
22
import queue
33
from dataclasses import dataclass
4-
from datetime import timedelta
54
from threading import Thread
65
from typing import Callable, Iterator, List, Optional
76

@@ -87,18 +86,22 @@ def _app_logs_reader(
8786
th.start()
8887

8988
# Print logs from queue when log event is available
90-
user_log_start = "<<< BEGIN USER_RUN_FLOW SECTION >>>"
91-
start_timestamp = None
89+
flow = "Your app has started. View it in your browser"
90+
work = "USER_RUN_WORK"
91+
start_timestamps = {}
9292

9393
# Print logs from queue when log event is available
9494
try:
9595
while True:
96-
log_event = read_queue.get(timeout=None if follow else 1.0)
97-
if user_log_start in log_event.message:
98-
start_timestamp = log_event.timestamp + timedelta(seconds=0.5)
99-
100-
if start_timestamp and log_event.timestamp > start_timestamp:
101-
yield log_event
96+
log_event: _LogEvent = read_queue.get(timeout=None if follow else 1.0)
97+
token = flow if log_event.component_name == "flow" else work
98+
if token in log_event.message:
99+
start_timestamps[log_event.component_name] = log_event.timestamp
100+
101+
timestamp = start_timestamps.get(log_event.component_name, None)
102+
if timestamp and log_event.timestamp >= timestamp:
103+
if "launcher" not in log_event.message:
104+
yield log_event
102105

103106
except queue.Empty:
104107
# Empty is raised by queue.get if timeout is reached. Follow = False case.

tests/tests_app_examples/conftest.py

Whitespace-only changes.

tests/tests_app_examples/test_boring_app.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_boring_app_example_cloud() -> None:
1313
with run_app_in_cloud(
1414
os.path.join(_PROJECT_ROOT, "examples/app_boring/"),
1515
app_name="app_dynamic.py",
16-
debug=True,
16+
debug=False,
1717
) as (
1818
_,
1919
view_page,
@@ -23,19 +23,16 @@ def test_boring_app_example_cloud() -> None:
2323

2424
def check_hello_there(*_, **__):
2525
locator = view_page.frame_locator("iframe").locator('ul:has-text("Hello there!")')
26-
locator.wait_for(timeout=3 * 1000)
2726
if len(locator.all_text_contents()):
2827
return True
2928

3029
wait_for(view_page, check_hello_there)
3130

32-
for _ in fetch_logs():
33-
pass
34-
3531
runner = CliRunner()
3632
result = runner.invoke(logs, [name])
3733
lines = result.output.splitlines()
3834

3935
assert result.exit_code == 0
4036
assert result.exception is None
4137
assert any("http://0.0.0.0:8080" in line for line in lines)
38+
print("Succeeded App!")

0 commit comments

Comments
 (0)