Best Python code snippet using localstack_python
test_job_ops_helper.py
Source:test_job_ops_helper.py  
1import re2import time3from collections import OrderedDict4from io import StringIO5from typing import Dict6from unittest.mock import Mock7import pytest8import vcr9from mock import mock_open, patch10from azure.ai.ml._restclient.runhistory.models import RunDetails, RunDetailsWarning11from azure.ai.ml._scope_dependent_operations import OperationScope12from azure.ai.ml.operations._job_ops_helper import (13    _get_sorted_filtered_logs,14    _incremental_print,15    list_logs,16    stream_logs_until_completion,17)18from azure.ai.ml.operations._run_operations import RunOperations19from .test_vcr_utils import before_record_cb20class DummyJob:21    class InteractionEndpoint:22        def __init__(self, **kwargs):23            self.endpoint = "testurl"24    class Properties:25        def __init__(self, **kwargs):26            super().__init__()27            self.experiment_name = "dummy_exp"28            self.services = {"Studio": DummyJob.InteractionEndpoint()}29            self.job_type = "Command"30    def __init__(self, **kwargs):31        super().__init__()32        self.name = "dummy"33        self.properties = DummyJob.Properties()34def fake_read():35    return mock_open(read_data="{}")36@pytest.fixture37def mock__commands():38    m = Mock(name="_commands")39    mock_run_history_facade = patch.dict("sys.modules", {"azureml._execution": m})40    mock_run_history_facade.start()41    yield m42    mock_run_history_facade.stop()43@pytest.fixture44def mock_time(request):45    p = patch("azure.ai.ml.operations._job_ops_helper.time")46    yield p.start()47    p.stop()48@pytest.fixture49def mock_run_operations(mock_workspace_scope: OperationScope, mock_aml_services_run_history: Mock) -> RunOperations:50    yield RunOperations(mock_workspace_scope, mock_aml_services_run_history)51@pytest.mark.skip("TODO 1907352: Relies on a missing VCR.py recording + test suite needs to be reworked")52@pytest.mark.unittest53class TestJobLogManager:54    def test_wait_for_completion_with_output(self, mock_run_operations):55        dummy_job = DummyJob()56        with patch.object(57            RunOperations,58            "get_run_details",59            side_effect=[60                RunDetails(status="Finalizing", log_files={"log1": "Log", "log2": "log"}),61                RunDetails(status="Completed", log_files={"log1": "Log", "log2": "log"}),62            ],63        ) as get_run_mock:64            stream_logs_until_completion(mock_run_operations, dummy_job)65            get_run_mock.assert_called()66    def test_wait_for_completion_with_error_silent(self, mock_run_operations):67        dummy_job = DummyJob()68        with patch.object(69            RunOperations,70            "get_run_details",71            return_value=RunDetails(status="Failed", warnings=[RunDetailsWarning(message="bad luck")]),72        ) as get_run_mock:73            stream_logs_until_completion(mock_run_operations, dummy_job, None, False)74            get_run_mock.assert_called_once()75    def test_wait_for_completion_with_error_raise(self, mock_run_operations):76        dummy_job = DummyJob()77        with patch.object(RunOperations, "get_run_details", return_value=RunDetails(status="Failed")) as get_run_mock:78            with pytest.raises(Exception):79                stream_logs_until_completion(mock_run_operations, dummy_job)80            get_run_mock.assert_called_once()81    # The list of logs that should be streamed, if you need to recreate,82    # you can just copy and paste the logFiles section from the Raw run JSON on the UI,83    # then keep here only the ones we stream84    _streamable_log_files_urls = OrderedDict(85        {86            "azureml-logs/55_azureml-execution-tvmps_f712ea79c8fca9c3c7f41774b414e867a0854377c8e411b095f30dd68f6d6027_d.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/55_azureml-execution-tvmps_f712ea79c8fca9c3c7f41774b414e867a0854377c8e411b095f30dd68f6d6027_d.txt?sv=2019-02-02&sr=b&sig=2B9oQEbsUwKZzw1eTUiyLJy64DRC%2BVOjv9lRb8Jx%2FLM%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",87            "azureml-logs/65_job_prep-tvmps_f712ea79c8fca9c3c7f41774b414e867a0854377c8e411b095f30dd68f6d6027_d.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/65_job_prep-tvmps_f712ea79c8fca9c3c7f41774b414e867a0854377c8e411b095f30dd68f6d6027_d.txt?sv=2019-02-02&sr=b&sig=2E1x1mUWF5Y8VD1e0yMqEZeWct4vngjES%2FJ3SFzKKxU%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",88            "azureml-logs/70_driver_log-worker-0.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/70_driver_log-worker-0.txt?sv=2019-02-02&sr=b&sig=8lXLfLMqGaQ7VNGLCKkQ%2BbdebJcyEFCJzNStYCRuVZc%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",89            "azureml-logs/75_job_post-tvmps_f712ea79c8fca9c3c7f41774b414e867a0854377c8e411b095f30dd68f6d6027_d.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/75_job_post-tvmps_f712ea79c8fca9c3c7f41774b414e867a0854377c8e411b095f30dd68f6d6027_d.txt?sv=2019-02-02&sr=b&sig=9YR6A64Tuq0E7KsgzPX7atqJ33eGjaJ8QeRaNaQ1%2BL4%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",90        }91    )92    # The list of logs that should NOT be streamed, if you need to recreate,93    # you can just copy and paste the logFiles section from the Raw run JSON on the UI,94    # then keep here only the ones we shouldn't stream95    _additional_log_files_urls = {96        "azureml-logs/process_info.json": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",97        "azureml-logs/process_status.json": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_status.json?sv=2019-02-02&sr=b&sig=FDFzfqtn9iYq2FMb5SOBGBu91k%2B8LQITcRiYYyLtDHs%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",98        "logs/azureml/job_prep_azureml.log": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/logs/azureml/job_prep_azureml.log?sv=2019-02-02&sr=b&sig=td0HUXBar%2FYv%2FhZiSdlPR516OH8bCMiBN3yH6dCSHvk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",99        "logs/azureml/job_release_azureml.log": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/logs/azureml/job_release_azureml.log?sv=2019-02-02&sr=b&sig=BeeRya%2FFZhqCNBk0hCJrks7%2Bejg9qTCFe5FNnf%2BUJyk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",100        "logs/azureml/worker0_373_azureml.log": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/logs/azureml/worker0_373_azureml.log?sv=2019-02-02&sr=b&sig=ySxUJjd1lqi%2FskcMfAYYFQ%2FyUQALbV0WH7jYtf%2FXaKk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",101    }102    _common_runtime_log_urls = {103        "user_logs/std_log.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",104        "azureml-logs/lifecycler/lifecycler.log": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",105    }106    _common_runtime_mpi_urls = {107        "user_logs/std_log_process_00.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",108        "user_logs/std_log_process_01.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",109        "user_logs/std_log_process_02.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",110        "user_logs/std_log_process_03.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",111        "user_logs/std_log_process_04.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",112    }113    _common_runtime_tensorflow_urls = {114        "user_logs/std_log_node_00_ps.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",115        "user_logs/std_log_node_01_ps.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",116        "user_logs/std_log_node_00_worker.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",117        "user_logs/std_log_node_01_worker.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",118        "user_logs/std_log_node_02_worker.txt": "https://rihorn24316837458.blob.core.windows.net/azureml/ExperimentRun/dcid.1a9952e7-f173-45c0-bd61-3cd591498bdf/azureml-logs/process_info.json?sv=2019-02-02&sr=b&sig=wn2pW00%2F86Qlo3NWOokMVGmaeModJNyHlIP5dDI4zqk%3D&skoid=e3f42e2c-d581-4b65-a966-631cfa961328&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2021-05-03T13%3A11%3A21Z&ske=2021-05-04T08%3A32%3A18Z&sks=b&skv=2019-02-02&st=2021-05-03T13%3A45%3A30Z&se=2021-05-03T21%3A55%3A30Z&sp=r",119    }120    # Method to create a RunDetails based on the provided status,121    # the number of streamable files to include, and if whether to add or not122    # non-streamable log files123    def _get_run_details_dto(124        self, status="Finalizing", number_of_streamable_log_files=0, include_additional_log_files=False125    ) -> RunDetails:126        keys = self._streamable_log_files_urls.keys()127        # Check if there are enough streamable log files128        if number_of_streamable_log_files > len(keys):129            raise Exception(f"There are less than {number_of_streamable_log_files}")130        # Keep only the first number_of_streamable_log_files logs131        log_files = {}132        for key in keys:133            log_files[key] = self._streamable_log_files_urls[key]134            number_of_streamable_log_files -= 1135            if not number_of_streamable_log_files:136                break137        # Add the additional logs if specified138        if include_additional_log_files:139            log_files.update(self._additional_log_files_urls)140        return RunDetails(status=status, log_files=log_files)141    # Helper method to test that logs will be streamed comprehensively142    # and in predictable order independently of the sequence of run details.143    # Logs could be delivered at different pace after subsequent calls to get details144    def _test_stream_logs_helper(self, mock_run_operations, run_details_sequence=[]) -> None:145        my_vcr = vcr.VCR(before_record=before_record_cb)146        with patch("sys.stdout", new=StringIO()) as fake_out, patch.object(147            RunOperations, "get_run_details", side_effect=run_details_sequence148        ) as get_run_mock, patch.object(time, "sleep",) as fake_time, my_vcr.use_cassette(149            "cassettes/test_stream_logs.yaml"150        ):151            stream_logs_until_completion(mock_run_operations, DummyJob())152            # get_run_mock was called, and all the sequence of run details was consumed153            get_run_mock.assert_called()154            assert get_run_mock.call_count == len(run_details_sequence)155            # while streamed, we waited in between each call to get run details156            fake_time.assert_called()157            assert fake_time.call_count == len(run_details_sequence) - 1158            # Regext to checking on the 'Streaming <log name>' message159            reg_exp = re.compile(r"Streaming ([\S]*)")160            output = fake_out.getvalue()161            list_of_logs = list(self._streamable_log_files_urls.keys())162            # Check that all the logs were streamed163            assert reg_exp.findall(output) == list_of_logs164            # Check there were no duplicates165            assert len(list_of_logs) == len(set(list_of_logs))166    def test_list_logs(self, mock_run_operations) -> None:167        with patch.object(168            RunOperations,169            "get_run_details",170            side_effect=[self._get_run_details_dto(status="Completed", number_of_streamable_log_files=3)],171        ) as get_run_mock:172            output = list_logs(mock_run_operations, DummyJob())173            get_run_mock.assert_called()174            assert len(output.items()) == 3175    # Method to test the golden path, a new log was added on each call to get run details176    @pytest.mark.vcr()177    def test_stream_logs_golden_path(self, mock_run_operations) -> None:178        run_details_sequence = [179            self._get_run_details_dto(status="Running"),180            self._get_run_details_dto(status="Finalizing", number_of_streamable_log_files=1),181            self._get_run_details_dto(status="Finalizing", number_of_streamable_log_files=2),182            self._get_run_details_dto(status="Finalizing", number_of_streamable_log_files=3),183            self._get_run_details_dto(status="Finalizing", number_of_streamable_log_files=4),184            self._get_run_details_dto(185                status="Completed", number_of_streamable_log_files=4, include_additional_log_files=True186            ),187        ]188        self._test_stream_logs_helper(mock_run_operations, run_details_sequence=run_details_sequence)189    # Method to test when all the logs were available at the same time190    @pytest.mark.vcr()191    def test_stream_logs_arriving_all_together(self, mock_run_operations) -> None:192        run_details_sequence = [193            self._get_run_details_dto(status="Running"),194            self._get_run_details_dto(status="Finalizing", number_of_streamable_log_files=4),195            self._get_run_details_dto(196                status="Completed", number_of_streamable_log_files=4, include_additional_log_files=True197            ),198        ]199        self._test_stream_logs_helper(mock_run_operations, run_details_sequence=run_details_sequence)200    # Method to test when the logs became available in batches of 2201    @pytest.mark.vcr()202    def test_stream_logs_arriving_in_batches(self, mock_run_operations) -> None:203        run_details_sequence = [204            self._get_run_details_dto(status="Running"),205            self._get_run_details_dto(status="Finalizing", number_of_streamable_log_files=2),206            self._get_run_details_dto(status="Finalizing", number_of_streamable_log_files=4),207            self._get_run_details_dto(208                status="Completed", number_of_streamable_log_files=4, include_additional_log_files=True209            ),210        ]211        self._test_stream_logs_helper(mock_run_operations, run_details_sequence=run_details_sequence)212    def test_get_streamable_logs_common_runtime_folder_structure(self) -> None:213        output = _get_sorted_filtered_logs(self._common_runtime_log_urls, "Command")214        assert len(output) == 1215        assert output[0] == "user_logs/std_log.txt"216    def test_get_all_logs_common_runtime_folder_structure(self) -> None:217        output = _get_sorted_filtered_logs(self._common_runtime_log_urls, "Command", {}, False)218        assert len(output) == 1219        assert output[0] == "user_logs/std_log.txt"220    def test_get_streamable_logs_common_runtime_mpi(self) -> None:221        output = _get_sorted_filtered_logs(self._common_runtime_mpi_urls, "Command")222        assert len(output) == 1223        assert output[0] == "user_logs/std_log_process_00.txt"224    def test_get_all_logs_common_runtime_mpi(self) -> None:225        output = _get_sorted_filtered_logs(self._common_runtime_mpi_urls, "Command", {}, False)226        assert len(output) == 5227    def test_get_streamable_logs_common_runtime_tensorflow(self) -> None:228        output = _get_sorted_filtered_logs(self._common_runtime_tensorflow_urls, "Command")229        assert len(output) == 1230        assert output[0] == "user_logs/std_log_node_00_ps.txt"231    def test_get_all_logs_common_runtime_tensorflow(self) -> None:232        output = _get_sorted_filtered_logs(self._common_runtime_tensorflow_urls, "Command", {}, False)233        assert len(output) == 5234    def test_stream_printing(self) -> None:235        log_name = "55_log_test"236        log_content = "line1\nline2\nline3\n"237        stream = StringIO()238        processed_logs: Dict[str, int] = {}239        _incremental_print(log_content, processed_logs, log_name, stream)240        # should contain the length of the log (3) + the header lines (4)241        assert len(stream.getvalue().splitlines()) == 7242        assert processed_logs[log_name] == 3243        # reset the state, to mock out the case where the first two lines have alread been read in244        processed_logs[log_name] = 2245        stream = StringIO()246        _incremental_print(log_content, processed_logs, log_name, stream)247        # should contain the length of the log (3) - skip previous lines (2) +  no header lines (0)248        assert len(stream.getvalue().splitlines()) == 1249        assert processed_logs[log_name] == 3250    def test_empty_log_is_skipped(self) -> None:251        log_name = "55_log_test"252        log_content = ""253        stream = StringIO()254        processed_logs: Dict[str, int] = {}255        _incremental_print(log_content, processed_logs, log_name, stream)256        # should be empty, no header, no log.257        assert len(stream.getvalue().splitlines()) == 0...test_worker.py
Source:test_worker.py  
...309@patch('pika.PlainCredentials')310@patch('pika.ConnectionParameters')311@patch('pika.BlockingConnection')312@patch('ammonite.callback.Sender', MockSender)313def test_stream_logs(a, b, c):314    print("starting stream log")315    container_name = "container"316    container_path = os.path.join(ROOT_DIR, "data")317    filename = os.path.join(container_path,318                            container_name,319                            "%s-json.log" % container_name)320    container = MockDockerContainer()321    config = MockConfig({'DOCKER': {'CONTAINER_PATH': container_path}})322    with LogCapture() as l:323        with open(filename, 'w') as fh:324            thread = Thread(target=stream_log,325                            args=(container_name, "2", container, config))326            thread.daemon = True327            thread.start()...test_agent.py
Source:test_agent.py  
...175    assert response == metrics_response()176# @pytest.mark.skip177# @pytest.mark.asyncio178# @pytest.mark.parametrize("expected", [metrics_response()])179# async def test_stream_logs(agent, expected):180#     response = await agent.stream_logs(stream=True)181#     assert response182@pytest.mark.asyncio183@pytest.mark.parametrize("expected", [200])184async def test_join(agent, expected):185    agent.client.expected = expected186    response = await agent.join("1.2.3.4")187    assert response.status == 200188@pytest.mark.asyncio189@pytest.mark.parametrize("expected", [200])190async def test_leave(agent, expected):191    agent.client.expected = expected192    response = await agent.leave()193    assert response.status == 200...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
