2022-02-16 12:09:44 +08:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
#
|
|
|
|
# Copyright (C) 2022 Collabora Limited
|
|
|
|
# Author: Guilherme Gallo <guilherme.gallo@collabora.com>
|
|
|
|
#
|
2022-07-06 08:34:01 +08:00
|
|
|
# SPDX-License-Identifier: MIT
|
2022-02-16 12:09:44 +08:00
|
|
|
|
2023-04-18 11:18:12 +08:00
|
|
|
import os
|
2022-02-16 12:09:44 +08:00
|
|
|
import xmlrpc.client
|
|
|
|
from contextlib import nullcontext as does_not_raise
|
|
|
|
from datetime import datetime
|
2022-07-26 04:56:51 +08:00
|
|
|
from itertools import chain, repeat
|
2023-04-06 12:31:04 +08:00
|
|
|
from pathlib import Path
|
2023-04-18 11:18:12 +08:00
|
|
|
from unittest.mock import MagicMock, patch
|
2022-02-16 12:09:44 +08:00
|
|
|
|
|
|
|
import pytest
|
2022-06-24 08:43:00 +08:00
|
|
|
from lava.exceptions import MesaCIException, MesaCIRetryError
|
2022-02-16 12:09:44 +08:00
|
|
|
from lava.lava_job_submitter import (
|
|
|
|
DEVICE_HANGING_TIMEOUT_SEC,
|
2022-03-24 09:10:51 +08:00
|
|
|
NUMBER_OF_RETRIES_TIMEOUT_DETECTION,
|
|
|
|
LAVAJob,
|
2023-04-06 12:31:04 +08:00
|
|
|
LAVAJobSubmitter,
|
2023-04-04 18:47:09 +08:00
|
|
|
bootstrap_log_follower,
|
2022-02-16 12:09:44 +08:00
|
|
|
follow_job_execution,
|
|
|
|
retriable_follow_job,
|
|
|
|
)
|
2022-07-07 09:52:23 +08:00
|
|
|
from lava.utils import LogSectionType
|
2022-02-16 12:09:44 +08:00
|
|
|
|
2022-06-24 08:43:00 +08:00
|
|
|
from .lava.helpers import (
|
|
|
|
generate_n_logs,
|
|
|
|
generate_testsuite_result,
|
|
|
|
jobs_logs_response,
|
2022-07-26 04:56:51 +08:00
|
|
|
mock_lava_signal,
|
2022-04-04 22:26:17 +08:00
|
|
|
mock_logs,
|
|
|
|
section_timeout,
|
2022-06-24 08:43:00 +08:00
|
|
|
)
|
2022-02-16 12:09:44 +08:00
|
|
|
|
2022-06-24 08:43:00 +08:00
|
|
|
NUMBER_OF_MAX_ATTEMPTS = NUMBER_OF_RETRIES_TIMEOUT_DETECTION + 1
|
2022-02-16 12:09:44 +08:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def mock_proxy_waiting_time(mock_proxy):
|
|
|
|
def update_mock_proxy(frozen_time, **kwargs):
|
2022-07-26 04:56:51 +08:00
|
|
|
wait_time = kwargs.pop("wait_time", 1)
|
2022-02-16 12:09:44 +08:00
|
|
|
proxy_mock = mock_proxy(**kwargs)
|
|
|
|
proxy_job_state = proxy_mock.scheduler.job_state
|
|
|
|
proxy_job_state.return_value = {"job_state": "Running"}
|
|
|
|
proxy_job_state.side_effect = frozen_time.tick(wait_time)
|
|
|
|
|
|
|
|
return proxy_mock
|
|
|
|
|
|
|
|
return update_mock_proxy
|
|
|
|
|
|
|
|
|
2023-04-18 11:18:12 +08:00
|
|
|
@pytest.fixture(params=[{"CI": "true"}, {"CI": "false"}], ids=["Under CI", "Local run"])
|
|
|
|
def ci_environment(request):
|
|
|
|
with patch.dict(os.environ, request.param):
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def lava_job_submitter(
|
|
|
|
ci_environment,
|
|
|
|
tmp_path,
|
|
|
|
mock_proxy,
|
|
|
|
):
|
|
|
|
os.chdir(tmp_path)
|
|
|
|
tmp_file = Path(tmp_path) / "log.json"
|
|
|
|
|
|
|
|
with patch("lava.lava_job_submitter.setup_lava_proxy") as mock_setup_lava_proxy:
|
|
|
|
mock_setup_lava_proxy.return_value = mock_proxy()
|
|
|
|
yield LAVAJobSubmitter(
|
|
|
|
boot_method="test_boot",
|
|
|
|
ci_project_dir="test_dir",
|
|
|
|
device_type="test_device",
|
|
|
|
job_timeout_min=1,
|
|
|
|
structured_log_file=tmp_file,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-02-16 12:09:44 +08:00
|
|
|
@pytest.mark.parametrize("exception", [RuntimeError, SystemError, KeyError])
|
|
|
|
def test_submit_and_follow_respects_exceptions(mock_sleep, mock_proxy, exception):
|
2022-04-01 02:42:49 +08:00
|
|
|
with pytest.raises(MesaCIException):
|
2022-02-17 02:06:20 +08:00
|
|
|
proxy = mock_proxy(side_effect=exception)
|
|
|
|
job = LAVAJob(proxy, '')
|
2023-04-04 18:47:09 +08:00
|
|
|
log_follower = bootstrap_log_follower()
|
|
|
|
follow_job_execution(job, log_follower)
|
2022-02-17 02:06:20 +08:00
|
|
|
|
2022-02-16 12:09:44 +08:00
|
|
|
|
|
|
|
NETWORK_EXCEPTION = xmlrpc.client.ProtocolError("", 0, "test", {})
|
|
|
|
XMLRPC_FAULT = xmlrpc.client.Fault(0, "test")
|
|
|
|
|
|
|
|
PROXY_SCENARIOS = {
|
2022-07-26 04:56:51 +08:00
|
|
|
"simple pass case": (mock_logs(result="pass"), does_not_raise(), "pass", {}),
|
|
|
|
"simple fail case": (mock_logs(result="fail"), does_not_raise(), "fail", {}),
|
|
|
|
"simple hung case": (
|
|
|
|
mock_logs(
|
|
|
|
messages={
|
|
|
|
LogSectionType.TEST_CASE: [
|
|
|
|
section_timeout(LogSectionType.TEST_CASE) + 1
|
|
|
|
]
|
|
|
|
* 1000
|
|
|
|
},
|
|
|
|
result="fail",
|
|
|
|
),
|
|
|
|
pytest.raises(MesaCIRetryError),
|
|
|
|
"hung",
|
|
|
|
{},
|
|
|
|
),
|
|
|
|
"leftover dump from last job in boot section": (
|
|
|
|
(
|
|
|
|
mock_lava_signal(LogSectionType.LAVA_BOOT),
|
|
|
|
jobs_logs_response(finished=False, msg=None, result="fail"),
|
|
|
|
),
|
|
|
|
pytest.raises(MesaCIRetryError),
|
|
|
|
"hung",
|
|
|
|
{},
|
|
|
|
),
|
2022-04-04 22:26:17 +08:00
|
|
|
"boot works at last retry": (
|
|
|
|
mock_logs(
|
2022-07-26 04:56:51 +08:00
|
|
|
messages={
|
2022-04-04 22:26:17 +08:00
|
|
|
LogSectionType.LAVA_BOOT: [
|
|
|
|
section_timeout(LogSectionType.LAVA_BOOT) + 1
|
|
|
|
]
|
|
|
|
* NUMBER_OF_RETRIES_TIMEOUT_DETECTION
|
|
|
|
+ [1]
|
|
|
|
},
|
2022-07-26 04:56:51 +08:00
|
|
|
result="pass",
|
2022-04-04 22:26:17 +08:00
|
|
|
),
|
2022-02-16 12:09:44 +08:00
|
|
|
does_not_raise(),
|
2022-07-26 04:56:51 +08:00
|
|
|
"pass",
|
2022-03-24 09:10:51 +08:00
|
|
|
{},
|
2022-02-16 12:09:44 +08:00
|
|
|
),
|
2022-07-26 04:56:51 +08:00
|
|
|
"test case took too long": pytest.param(
|
2022-04-04 22:26:17 +08:00
|
|
|
mock_logs(
|
2022-07-26 04:56:51 +08:00
|
|
|
messages={
|
|
|
|
LogSectionType.TEST_CASE: [
|
|
|
|
section_timeout(LogSectionType.TEST_CASE) + 1
|
2022-04-04 22:26:17 +08:00
|
|
|
]
|
|
|
|
* (NUMBER_OF_MAX_ATTEMPTS + 1)
|
|
|
|
},
|
2022-07-26 04:56:51 +08:00
|
|
|
result="pass",
|
2022-04-21 07:55:47 +08:00
|
|
|
),
|
2022-04-01 02:42:49 +08:00
|
|
|
pytest.raises(MesaCIRetryError),
|
2022-07-26 04:56:51 +08:00
|
|
|
"pass",
|
2022-04-04 22:26:17 +08:00
|
|
|
{},
|
|
|
|
),
|
|
|
|
"timed out more times than retry attempts": (
|
|
|
|
generate_n_logs(n=4, tick_fn=9999999),
|
|
|
|
pytest.raises(MesaCIRetryError),
|
2022-07-26 04:56:51 +08:00
|
|
|
"fail",
|
2022-03-24 09:10:51 +08:00
|
|
|
{},
|
2022-02-16 12:09:44 +08:00
|
|
|
),
|
|
|
|
"long log case, no silence": (
|
2022-07-26 04:56:51 +08:00
|
|
|
mock_logs(
|
|
|
|
messages={LogSectionType.TEST_CASE: [1] * (1000)},
|
|
|
|
result="pass",
|
|
|
|
),
|
2022-02-16 12:09:44 +08:00
|
|
|
does_not_raise(),
|
2022-07-26 04:56:51 +08:00
|
|
|
"pass",
|
2022-03-24 09:10:51 +08:00
|
|
|
{},
|
|
|
|
),
|
|
|
|
"no retries, testsuite succeed": (
|
2022-07-26 04:56:51 +08:00
|
|
|
mock_logs(result="pass"),
|
2022-03-24 09:10:51 +08:00
|
|
|
does_not_raise(),
|
2022-07-26 04:56:51 +08:00
|
|
|
"pass",
|
2022-03-24 09:10:51 +08:00
|
|
|
{
|
|
|
|
"testsuite_results": [
|
|
|
|
generate_testsuite_result(result="pass")
|
|
|
|
]
|
|
|
|
},
|
|
|
|
),
|
|
|
|
"no retries, but testsuite fails": (
|
2022-07-26 04:56:51 +08:00
|
|
|
mock_logs(result="fail"),
|
2022-03-24 09:10:51 +08:00
|
|
|
does_not_raise(),
|
2022-07-26 04:56:51 +08:00
|
|
|
"fail",
|
2022-03-24 09:10:51 +08:00
|
|
|
{
|
|
|
|
"testsuite_results": [
|
|
|
|
generate_testsuite_result(result="fail")
|
|
|
|
]
|
|
|
|
},
|
|
|
|
),
|
|
|
|
"no retries, one testsuite fails": (
|
2022-05-10 20:27:01 +08:00
|
|
|
generate_n_logs(n=1, tick_fn=0, result="fail"),
|
2022-03-24 09:10:51 +08:00
|
|
|
does_not_raise(),
|
2022-07-26 04:56:51 +08:00
|
|
|
"fail",
|
2022-03-24 09:10:51 +08:00
|
|
|
{
|
|
|
|
"testsuite_results": [
|
|
|
|
generate_testsuite_result(result="fail"),
|
|
|
|
generate_testsuite_result(result="pass")
|
|
|
|
]
|
|
|
|
},
|
2022-02-16 12:09:44 +08:00
|
|
|
),
|
|
|
|
"very long silence": (
|
2022-02-17 02:06:20 +08:00
|
|
|
generate_n_logs(n=NUMBER_OF_MAX_ATTEMPTS + 1, tick_fn=100000),
|
2022-04-01 02:42:49 +08:00
|
|
|
pytest.raises(MesaCIRetryError),
|
2022-07-26 04:56:51 +08:00
|
|
|
"fail",
|
2022-03-24 09:10:51 +08:00
|
|
|
{},
|
2022-02-16 12:09:44 +08:00
|
|
|
),
|
|
|
|
# If a protocol error happens, _call_proxy will retry without affecting timeouts
|
|
|
|
"unstable connection, ProtocolError followed by final message": (
|
2022-07-26 04:56:51 +08:00
|
|
|
(NETWORK_EXCEPTION, *list(mock_logs(result="pass"))),
|
2022-02-16 12:09:44 +08:00
|
|
|
does_not_raise(),
|
2022-07-26 04:56:51 +08:00
|
|
|
"pass",
|
2022-03-24 09:10:51 +08:00
|
|
|
{},
|
2022-02-16 12:09:44 +08:00
|
|
|
),
|
|
|
|
# After an arbitrary number of retries, _call_proxy should call sys.exit
|
|
|
|
"unreachable case, subsequent ProtocolErrors": (
|
|
|
|
repeat(NETWORK_EXCEPTION),
|
|
|
|
pytest.raises(SystemExit),
|
2022-07-26 04:56:51 +08:00
|
|
|
"fail",
|
2022-03-24 09:10:51 +08:00
|
|
|
{},
|
2022-02-16 12:09:44 +08:00
|
|
|
),
|
2023-04-04 18:47:09 +08:00
|
|
|
"XMLRPC Fault": ([XMLRPC_FAULT], pytest.raises(MesaCIRetryError), False, {}),
|
2022-02-16 12:09:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
2022-04-04 22:26:17 +08:00
|
|
|
"test_log, expectation, job_result, proxy_args",
|
2022-02-16 12:09:44 +08:00
|
|
|
PROXY_SCENARIOS.values(),
|
|
|
|
ids=PROXY_SCENARIOS.keys(),
|
|
|
|
)
|
|
|
|
def test_retriable_follow_job(
|
2022-04-04 22:26:17 +08:00
|
|
|
mock_sleep,
|
|
|
|
test_log,
|
|
|
|
expectation,
|
|
|
|
job_result,
|
|
|
|
proxy_args,
|
|
|
|
mock_proxy,
|
2022-02-16 12:09:44 +08:00
|
|
|
):
|
|
|
|
with expectation:
|
2022-04-04 22:26:17 +08:00
|
|
|
proxy = mock_proxy(side_effect=test_log, **proxy_args)
|
2022-05-10 20:27:01 +08:00
|
|
|
job: LAVAJob = retriable_follow_job(proxy, "")
|
2022-07-26 04:56:51 +08:00
|
|
|
assert job_result == job.status
|
2022-02-16 12:09:44 +08:00
|
|
|
|
|
|
|
|
2022-07-26 04:56:51 +08:00
|
|
|
WAIT_FOR_JOB_SCENARIOS = {"one log run taking (sec):": (mock_logs(result="pass"))}
|
2022-02-16 12:09:44 +08:00
|
|
|
|
|
|
|
|
2022-07-26 04:56:51 +08:00
|
|
|
@pytest.mark.parametrize("wait_time", (DEVICE_HANGING_TIMEOUT_SEC * 2,))
|
2022-02-16 12:09:44 +08:00
|
|
|
@pytest.mark.parametrize(
|
2022-07-26 04:56:51 +08:00
|
|
|
"side_effect",
|
2022-02-16 12:09:44 +08:00
|
|
|
WAIT_FOR_JOB_SCENARIOS.values(),
|
|
|
|
ids=WAIT_FOR_JOB_SCENARIOS.keys(),
|
|
|
|
)
|
|
|
|
def test_simulate_a_long_wait_to_start_a_job(
|
|
|
|
frozen_time,
|
|
|
|
wait_time,
|
|
|
|
side_effect,
|
|
|
|
mock_proxy_waiting_time,
|
|
|
|
):
|
|
|
|
start_time = datetime.now()
|
2022-05-10 20:27:01 +08:00
|
|
|
job: LAVAJob = retriable_follow_job(
|
2022-02-16 12:09:44 +08:00
|
|
|
mock_proxy_waiting_time(
|
|
|
|
frozen_time, side_effect=side_effect, wait_time=wait_time
|
|
|
|
),
|
|
|
|
"",
|
|
|
|
)
|
|
|
|
|
|
|
|
end_time = datetime.now()
|
|
|
|
delta_time = end_time - start_time
|
|
|
|
|
2022-07-26 04:56:51 +08:00
|
|
|
assert job.status == "pass"
|
2022-02-16 12:09:44 +08:00
|
|
|
assert delta_time.total_seconds() >= wait_time
|
|
|
|
|
|
|
|
|
2022-04-04 22:26:17 +08:00
|
|
|
|
2022-04-21 07:55:47 +08:00
|
|
|
CORRUPTED_LOG_SCENARIOS = {
|
|
|
|
"too much subsequent corrupted data": (
|
|
|
|
[(False, "{'msg': 'Incomplete}")] * 100 + [jobs_logs_response(True)],
|
|
|
|
pytest.raises((MesaCIRetryError)),
|
|
|
|
),
|
|
|
|
"one subsequent corrupted data": (
|
|
|
|
[(False, "{'msg': 'Incomplete}")] * 2 + [jobs_logs_response(True)],
|
|
|
|
does_not_raise(),
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"data_sequence, expected_exception",
|
|
|
|
CORRUPTED_LOG_SCENARIOS.values(),
|
|
|
|
ids=CORRUPTED_LOG_SCENARIOS.keys(),
|
|
|
|
)
|
|
|
|
def test_log_corruption(mock_sleep, data_sequence, expected_exception, mock_proxy):
|
|
|
|
proxy_mock = mock_proxy()
|
|
|
|
proxy_logs_mock = proxy_mock.scheduler.jobs.logs
|
|
|
|
proxy_logs_mock.side_effect = data_sequence
|
|
|
|
with expected_exception:
|
|
|
|
retriable_follow_job(proxy_mock, "")
|
2022-05-16 08:35:48 +08:00
|
|
|
|
|
|
|
|
2022-06-22 03:30:34 +08:00
|
|
|
LAVA_RESULT_LOG_SCENARIOS = {
|
|
|
|
# the submitter should accept xtrace logs
|
|
|
|
"Bash xtrace echo with kmsg interleaving": (
|
2022-07-01 06:46:40 +08:00
|
|
|
"echo hwci: mesa: pass[ 737.673352] <LAVA_SIGNAL_ENDTC mesa-ci>",
|
2022-06-22 03:30:34 +08:00
|
|
|
"pass",
|
|
|
|
),
|
|
|
|
# the submitter should accept xtrace logs
|
|
|
|
"kmsg result print": (
|
2022-07-01 06:46:40 +08:00
|
|
|
"[ 737.673352] hwci: mesa: pass",
|
2022-06-22 03:30:34 +08:00
|
|
|
"pass",
|
|
|
|
),
|
|
|
|
# if the job result echo has a very bad luck, it still can be interleaved
|
|
|
|
# with kmsg
|
|
|
|
"echo output with kmsg interleaving": (
|
2022-07-01 06:46:40 +08:00
|
|
|
"hwci: mesa: pass[ 737.673352] <LAVA_SIGNAL_ENDTC mesa-ci>",
|
2022-06-22 03:30:34 +08:00
|
|
|
"pass",
|
|
|
|
),
|
|
|
|
"fail case": (
|
2022-07-01 06:46:40 +08:00
|
|
|
"hwci: mesa: fail",
|
2022-06-22 03:30:34 +08:00
|
|
|
"fail",
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"message, expectation",
|
|
|
|
LAVA_RESULT_LOG_SCENARIOS.values(),
|
|
|
|
ids=LAVA_RESULT_LOG_SCENARIOS.keys(),
|
|
|
|
)
|
2022-07-01 06:46:40 +08:00
|
|
|
def test_parse_job_result_from_log(message, expectation, mock_proxy):
|
2022-06-22 03:30:34 +08:00
|
|
|
job = LAVAJob(mock_proxy(), "")
|
|
|
|
job.parse_job_result_from_log([message])
|
|
|
|
|
|
|
|
assert job.status == expectation
|
2022-07-01 05:16:51 +08:00
|
|
|
|
|
|
|
|
2022-07-07 10:31:27 +08:00
|
|
|
@pytest.mark.slow(
|
|
|
|
reason="Slow and sketchy test. Needs a LAVA log raw file at /tmp/log.yaml"
|
|
|
|
)
|
2023-04-19 22:31:47 +08:00
|
|
|
@pytest.mark.skipif(
|
|
|
|
not Path("/tmp/log.yaml").is_file(), reason="Missing /tmp/log.yaml file."
|
|
|
|
)
|
2023-04-18 11:18:12 +08:00
|
|
|
def test_full_yaml_log(mock_proxy, frozen_time, lava_job_submitter):
|
2022-07-01 05:16:51 +08:00
|
|
|
import random
|
|
|
|
|
2023-01-10 03:46:28 +08:00
|
|
|
from lavacli.utils import flow_yaml as lava_yaml
|
2022-07-01 05:16:51 +08:00
|
|
|
|
|
|
|
def time_travel_from_log_chunk(data_chunk):
|
|
|
|
if not data_chunk:
|
|
|
|
return
|
|
|
|
|
|
|
|
first_log_time = data_chunk[0]["dt"]
|
|
|
|
frozen_time.move_to(first_log_time)
|
|
|
|
yield
|
|
|
|
|
|
|
|
last_log_time = data_chunk[-1]["dt"]
|
|
|
|
frozen_time.move_to(last_log_time)
|
|
|
|
return
|
|
|
|
|
|
|
|
def time_travel_to_test_time():
|
|
|
|
# Suppose that the first message timestamp of the entire LAVA job log is
|
|
|
|
# the same of from the job submitter execution
|
|
|
|
with open("/tmp/log.yaml", "r") as f:
|
|
|
|
first_log = f.readline()
|
2023-01-10 03:46:28 +08:00
|
|
|
first_log_time = lava_yaml.load(first_log)[0]["dt"]
|
2022-07-01 05:16:51 +08:00
|
|
|
frozen_time.move_to(first_log_time)
|
|
|
|
|
|
|
|
def load_lines() -> list:
|
|
|
|
with open("/tmp/log.yaml", "r") as f:
|
2022-11-28 10:38:33 +08:00
|
|
|
# data = yaml.safe_load(f)
|
|
|
|
data = f.readlines()
|
|
|
|
stream = chain(data)
|
2022-07-01 05:16:51 +08:00
|
|
|
try:
|
|
|
|
while True:
|
2022-11-28 10:38:33 +08:00
|
|
|
data_chunk = [next(stream) for _ in range(random.randint(0, 50))]
|
|
|
|
serial_message = "".join(data_chunk)
|
2022-07-01 05:16:51 +08:00
|
|
|
# Suppose that the first message timestamp is the same of
|
|
|
|
# log fetch RPC call
|
|
|
|
time_travel_from_log_chunk(data_chunk)
|
2022-11-28 10:38:33 +08:00
|
|
|
yield False, "[]"
|
2022-07-01 05:16:51 +08:00
|
|
|
# Travel to the same datetime of the last fetched log line
|
|
|
|
# in the chunk
|
|
|
|
time_travel_from_log_chunk(data_chunk)
|
2022-11-28 10:38:33 +08:00
|
|
|
yield False, serial_message
|
2022-07-01 05:16:51 +08:00
|
|
|
except StopIteration:
|
2022-11-28 10:38:33 +08:00
|
|
|
yield True, serial_message
|
2022-07-01 05:16:51 +08:00
|
|
|
return
|
|
|
|
|
|
|
|
proxy = mock_proxy()
|
|
|
|
|
|
|
|
def reset_logs(*args):
|
|
|
|
proxy.scheduler.jobs.logs.side_effect = load_lines()
|
|
|
|
|
|
|
|
proxy.scheduler.jobs.submit = reset_logs
|
|
|
|
with pytest.raises(MesaCIRetryError):
|
|
|
|
time_travel_to_test_time()
|
2023-04-18 11:18:12 +08:00
|
|
|
lava_job_submitter.submit()
|
2022-07-01 05:16:51 +08:00
|
|
|
retriable_follow_job(proxy, "")
|
2023-04-18 11:18:12 +08:00
|
|
|
print(lava_job_submitter.structured_log_file.read_text())
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"validate_only,finished_job_status,expected_combined_status,expected_exit_code",
|
|
|
|
[
|
|
|
|
(True, "pass", None, None),
|
|
|
|
(False, "pass", "pass", 0),
|
|
|
|
(False, "fail", "fail", 1),
|
|
|
|
],
|
|
|
|
ids=[
|
|
|
|
"validate_only_no_job_submission",
|
|
|
|
"successful_job_submission",
|
|
|
|
"failed_job_submission",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_job_combined_status(
|
|
|
|
lava_job_submitter,
|
|
|
|
validate_only,
|
|
|
|
finished_job_status,
|
|
|
|
expected_combined_status,
|
|
|
|
expected_exit_code,
|
|
|
|
):
|
|
|
|
lava_job_submitter.validate_only = validate_only
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"lava.lava_job_submitter.retriable_follow_job"
|
|
|
|
) as mock_retriable_follow_job, patch(
|
|
|
|
"lava.lava_job_submitter.LAVAJobSubmitter._LAVAJobSubmitter__prepare_submission"
|
|
|
|
) as mock_prepare_submission, patch(
|
|
|
|
"sys.exit"
|
|
|
|
):
|
|
|
|
from lava.lava_job_submitter import STRUCTURAL_LOG
|
|
|
|
|
|
|
|
mock_retriable_follow_job.return_value = MagicMock(status=finished_job_status)
|
|
|
|
|
|
|
|
mock_job_definition = MagicMock(spec=str)
|
|
|
|
mock_prepare_submission.return_value = mock_job_definition
|
|
|
|
original_status: str = STRUCTURAL_LOG.get("job_combined_status")
|
|
|
|
|
|
|
|
if validate_only:
|
|
|
|
lava_job_submitter.submit()
|
|
|
|
mock_retriable_follow_job.assert_not_called()
|
|
|
|
assert STRUCTURAL_LOG.get("job_combined_status") == original_status
|
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
lava_job_submitter.submit()
|
|
|
|
|
|
|
|
except SystemExit as e:
|
|
|
|
assert e.code == expected_exit_code
|
|
|
|
|
|
|
|
assert STRUCTURAL_LOG["job_combined_status"] == expected_combined_status
|