def test_enqueue_with_tracer(self, _1, _2, patched_config): """Make sure there is no lock contention when tracer is on. When the tracer is set up, we want maybe_handle_execution_control_request to be executed only once. There was a bug in the past where it was called twice: once from the tracer and once from the enqueue function. This caused a lock contention. """ def get_option(name): if name == "server.runOnSave": # Just to avoid starting the watcher for no reason. return False if name == "client.displayEnabled": return True if name == "runner.installTracer": return True raise RuntimeError("Unexpected argument to get_option: %s" % name) patched_config.get_option.side_effect = get_option rs = ReportSession(False, None, "", "", UploadedFileManager()) mock_script_runner = MagicMock() rs._scriptrunner = mock_script_runner rs.enqueue({"dontcare": 123}) func = mock_script_runner.maybe_handle_execution_control_request # In reality, outside of a testing environment func should be called # once. But in this test we're actually not installing a tracer here, # since Report is mocked. So the correct behavior here is for func to # never be called. If you ever see it being called once here it's # likely because there's a bug in the enqueue function (which should # skip func when installTracer is on). func.assert_not_called()
def __init__(self, ioloop, script_path, command_line): """Create the server. It won't be started yet. Parameters ---------- ioloop : tornado.ioloop.IOLoop script_path : str command_line : str """ if Server._singleton is not None: raise RuntimeError( "Server already initialized. Use .get_current() instead") Server._singleton = self _set_tornado_log_levels() self._ioloop = ioloop self._script_path = script_path self._command_line = command_line # Mapping of ReportSession.id -> SessionInfo. self._session_info_by_id = {} self._must_stop = threading.Event() self._state = None self._set_state(State.INITIAL) self._message_cache = ForwardMsgCache() self._uploaded_file_mgr = UploadedFileManager() self._uploaded_file_mgr.on_files_added.connect(self._on_file_uploaded) self._report = None # type: Optional[Report]
def test_enqueue_without_tracer(self, _1, _2, patched_config): """Make sure we try to handle execution control requests. """ def get_option(name): if name == "server.runOnSave": # Just to avoid starting the watcher for no reason. return False if name == "client.displayEnabled": return True if name == "runner.installTracer": return False raise RuntimeError("Unexpected argument to get_option: %s" % name) patched_config.get_option.side_effect = get_option rs = ReportSession(False, None, "", "", UploadedFileManager()) mock_script_runner = MagicMock() mock_script_runner._install_tracer = ScriptRunner._install_tracer rs._scriptrunner = mock_script_runner rs.enqueue({"dontcare": 123}) func = mock_script_runner.maybe_handle_execution_control_request # Expect func to be called only once, inside enqueue(). func.assert_called_once()
def test_msg_hash(self): """Test that ForwardMsg hash generation works as expected""" widget_idA = "A0123456789" widget_idB = "B0123456789" file_name = "example_file.png" file_bytes = bytearray( "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", "utf-8", ) uploaded_file_mgr = UploadedFileManager() uploaded_file_mgr.create_or_clear_file(widget_idA, file_name, len(file_bytes), date.today(), 1) uploaded_file_mgr.create_or_clear_file(widget_idB, file_name, len(file_bytes), date.today(), 2) progress_a = uploaded_file_mgr.process_chunk(widget_idA, 0, file_bytes) self.assertEqual(progress_a, 1) progress_b = uploaded_file_mgr.process_chunk(widget_idB, 0, file_bytes[0:50]) self.assertEqual(progress_b, 0.5) progress_b = uploaded_file_mgr.process_chunk(widget_idB, 1, file_bytes[50:100]) self.assertEqual(progress_b, 1) progress_a, data_a = uploaded_file_mgr.get_data(widget_idA) progress_b, data_b = uploaded_file_mgr.get_data(widget_idB) self.assertEqual(progress_a, 100) self.assertEqual(progress_b, 100) self.assertEqual(len(data_a), len(file_bytes)) self.assertEqual(data_a, file_bytes) self.assertEqual(data_a, data_b) uploaded_file_mgr.delete_file(widget_idA) progress_a, data_a = uploaded_file_mgr.get_data(widget_idA) self.assertEqual(progress_a, 0) self.assertEqual(data_a, None) uploaded_file_mgr.delete_all_files() progress_b, data_b = uploaded_file_mgr.get_data(widget_idB) self.assertEqual(progress_b, 0) self.assertEqual(data_b, None)
def setUp(self, override_root=True): self.report_queue = ReportQueue() self.override_root = override_root self.orig_report_ctx = None if self.override_root: self.orig_report_ctx = get_report_ctx() add_report_ctx( threading.current_thread(), ReportContext( enqueue=self.report_queue.enqueue, widgets=Widgets(), widget_ids_this_run=_WidgetIDSet(), uploaded_file_mgr=UploadedFileManager(), ), )
def __init__(self, ioloop, script_path, command_line): """Initialize the ReportSession. Parameters ---------- ioloop : tornado.ioloop.IOLoop The Tornado IOLoop that we're running within. script_path : str Path of the Python file from which this report is generated. command_line : str Command line as input by the user. """ # Each ReportSession gets a unique ID self.id = ReportSession._next_id ReportSession._next_id += 1 self._ioloop = ioloop self._report = Report(script_path, command_line) self._state = ReportSessionState.REPORT_NOT_RUNNING self._uploaded_file_mgr = UploadedFileManager() self._main_dg = DeltaGenerator(enqueue=self.enqueue, container=BlockPath.MAIN) self._sidebar_dg = DeltaGenerator( enqueue=self.enqueue, container=BlockPath.SIDEBAR ) self._widget_states = WidgetStates() self._local_sources_watcher = LocalSourcesWatcher( self._report, self._on_source_file_changed ) self._sent_initialize_message = False self._storage = None self._maybe_reuse_previous_run = False self._run_on_save = config.get_option("server.runOnSave") # The ScriptRequestQueue is the means by which we communicate # with the active ScriptRunner. self._script_request_queue = ScriptRequestQueue() self._scriptrunner = None LOGGER.debug("ReportSession initialized (id=%s)", self.id)
def test_handle_save_request(self, _1): """Test that handle_save_request serializes files correctly.""" # Create a ReportSession with some mocked bits rs = ReportSession(False, self.io_loop, "mock_report.py", "", UploadedFileManager()) rs._report.report_id = "TestReportID" orig_ctx = get_report_ctx() ctx = ReportContext("TestSessionID", rs._report.enqueue, None, None, None) add_report_ctx(ctx=ctx) rs._scriptrunner = MagicMock() storage = MockStorage() rs._storage = storage # Send two deltas: empty and markdown st.empty() st.markdown("Text!") yield rs.handle_save_request(_create_mock_websocket()) # Check the order of the received files. Manifest should be last. self.assertEqual(3, len(storage.files)) self.assertEqual("reports/TestReportID/0.pb", storage.get_filename(0)) self.assertEqual("reports/TestReportID/1.pb", storage.get_filename(1)) self.assertEqual("reports/TestReportID/manifest.pb", storage.get_filename(2)) # Check the manifest manifest = storage.get_message(2, StaticManifest) self.assertEqual("mock_report", manifest.name) self.assertEqual(2, manifest.num_messages) self.assertEqual(StaticManifest.DONE, manifest.server_status) # Check that the deltas we sent match messages in storage sent_messages = rs._report._master_queue._queue received_messages = [ storage.get_message(0, ForwardMsg), storage.get_message(1, ForwardMsg), ] self.assertEqual(sent_messages, received_messages) add_report_ctx(ctx=orig_ctx)
def setUp(self, override_root=True): self.report_queue = ReportQueue() if override_root: main_dg = self.new_delta_generator() sidebar_dg = self.new_delta_generator(container=BlockPath.SIDEBAR) setattr( threading.current_thread(), REPORT_CONTEXT_ATTR_NAME, ReportContext( main_dg=main_dg, sidebar_dg=sidebar_dg, widgets=Widgets(), widget_ids_this_run=_WidgetIDSet(), uploaded_file_mgr=UploadedFileManager(), ), )
def setUp(self): self.mgr = UploadedFileManager() self.filemgr_events = [] self.mgr.on_files_added.connect(self._on_files_added)
def get_app(self): self.file_mgr = UploadedFileManager() return tornado.web.Application([("/upload_file", UploadFileRequestHandler, dict(file_mgr=self.file_mgr))])