def test_slow_flow(): app0 = LightningApp(SleepyFlow(sleep_interval=0.5 * FLOW_DURATION_THRESHOLD)) MultiProcessRuntime(app0).dispatch() app1 = LightningApp(SleepyFlow(sleep_interval=2 * FLOW_DURATION_THRESHOLD)) with pytest.warns(LightningFlowWarning): MultiProcessRuntime(app1).dispatch() app0 = LightningApp( SleepyFlowWithWork( sleep_interval=0.5 * FLOW_DURATION_THRESHOLD, work_sleep_interval=2 * FLOW_DURATION_THRESHOLD, parallel=False, ) ) MultiProcessRuntime(app0).dispatch() app1 = LightningApp( SleepyFlowWithWork( sleep_interval=0.5 * FLOW_DURATION_THRESHOLD, work_sleep_interval=2 * FLOW_DURATION_THRESHOLD, parallel=True ) ) MultiProcessRuntime(app1).dispatch()
def test_flow_state_change_with_path(): """Test that type changes to a Path attribute are properly reflected within the state.""" class Flow(LightningFlow): def __init__(self): super().__init__() self.none_to_path = None self.path_to_none = Path() self.path_to_path = Path() def run(self): self.none_to_path = "lit://none/to/path" self.path_to_none = None self.path_to_path = "lit://path/to/path" self._exit() flow = Flow() MultiProcessRuntime(LightningApp(flow)).dispatch() assert flow.none_to_path == Path("lit://none/to/path") assert flow.path_to_none is None assert flow.path_to_path == Path("lit://path/to/path") assert "path_to_none" not in flow._paths assert "path_to_none" in flow._state assert flow._paths["none_to_path"] == Path("lit://none/to/path").to_dict() assert flow._paths["path_to_path"] == Path("lit://path/to/path").to_dict() assert flow.state["vars"]["none_to_path"] == Path("lit://none/to/path") assert flow.state["vars"]["path_to_none"] is None assert flow.state["vars"]["path_to_path"] == Path("lit://path/to/path")
def test_multiprocess_starts_frontend_servers(*_): """Test that the MultiProcessRuntime starts the servers for the frontends in each LightningFlow.""" root = StartFrontendServersTestFlow() app = LightningApp(root) MultiProcessRuntime(app).dispatch() app.frontends[root.flow0.name].start_server.assert_called_once() app.frontends[root.flow1.name].start_server.assert_called_once() app.frontends[root.flow0.name].stop_server.assert_called_once() app.frontends[root.flow1.name].stop_server.assert_called_once()
def test_layout_leaf_node(find_ports_mock, flow): find_ports_mock.side_effect = lambda: 100 app = LightningApp(flow) assert flow._layout == {} # we copy the dict here because after we dispatch the dict will get update with new instances # as the layout gets updated during the loop. frontends = app.frontends.copy() MultiProcessRuntime(app).dispatch() assert flow.counter == 3 # The target url is available for the frontend after we started the servers in dispatch assert flow._layout == dict(target="http://localhost:100/root") assert app.frontends[flow.name].flow is flow # we start the servers for the frontends that we collected at the time of app instantiation frontends[flow.name].start_server.assert_called_once() # leaf layout nodes can't be changed, they stay the same from when they first got configured assert app.frontends[flow.name] == frontends[flow.name]
def test_lightning_stop(): app = LightningApp(FlowStop()) MultiProcessRuntime(app, start_server=False).dispatch()
def test_lightning_app_exit(): app = LightningApp(FlowExit()) MultiProcessRuntime(app).dispatch() assert app.root.work.status.stage == WorkStageStatus.STOPPED
def test_protected_attributes_not_in_state(): flow = ProtectedAttributesFlow() MultiProcessRuntime(LightningApp(flow)).dispatch()
def test_fault_tolerance_work(): app = FaultToleranceLightningTestApp(FlowCC()) MultiProcessRuntime(app, start_server=False).dispatch() assert app.root.work.counter == 2
def test_pickleable_return_from_work(): """Test that any object that is pickleable can be returned from the run method in LightningWork.""" with pytest.raises(SystemExit, match="1"): app = LightningApp(PickleableReturnFlow()) MultiProcessRuntime(app, start_server=False).dispatch()
def test_scheduling_api(): app = LightningApp(FlowSchedule()) MultiProcessRuntime(app).dispatch()
def test_structures_with_payload(): app = LightningApp(FlowPayload(), debug=True) MultiProcessRuntime(app, start_server=False).dispatch() os.remove("payload")
def test_list_with_queues(): app = LightningApp(FlowList()) MultiProcessRuntime(app, start_server=False).dispatch()
def test_synchronization_drive(tmpdir): if os.path.exists("a.txt"): os.remove("a.txt") app = LightningApp(SyncFlow(tmpdir)) MultiProcessRuntime(app, start_server=False).dispatch() os.remove("a.txt")
def test_drive_transferring_files(): app = LightningApp(Flow()) MultiProcessRuntime(app, start_server=False).dispatch() os.remove("a.txt")
def test_app_starts_with_complete_state_copy(_, __): """Test that the LightningApp captures the initial state in a separate copy when _run() gets called.""" app = AppWithFrontend(FlowWithFrontend(), debug=True) MultiProcessRuntime(app, start_server=False).dispatch() assert app.run_once_call_count == 3
def test_multiprocess_runtime_sets_context(): """Test that the runtime sets the global variable COMPONENT_CONTEXT in Flow and Work.""" MultiProcessRuntime(LightningApp(ContxtFlow())).dispatch()
def test_dynamic_content_layout_update(): """Test that the `configure_layout()` gets called as part of the loop and can return new layouts.""" flow = DynamicContentComponent() app = LightningApp(flow) MultiProcessRuntime(app).dispatch() assert flow.configure_layout_called == 5