ci: faster unit_test (#34019)

* multiple

* CACHE

* ...

* cache

* now fast

* maybe

* bp

* vv

* slow

* fast

* fix

* faster

* ruff

* info

* timeout

* info

* more

* clean

* faster

* test

* collection time

* is this real?

* fix

* back

* clean

* just to make sure

* faster!
This commit is contained in:
Maxime Desroches 2024-11-13 21:27:23 -08:00 committed by GitHub
parent 26b928596d
commit 50aac48fba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 21 additions and 78 deletions

View File

@ -173,12 +173,19 @@ jobs:
- name: Build openpilot - name: Build openpilot
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
run: ${{ env.RUN }} "scons -j$(nproc)" run: ${{ env.RUN }} "scons -j$(nproc)"
- name: Setup cache
uses: ./.github/workflows/auto-cache
with:
path: .ci_cache/comma_download_cache
key: unit_tests_${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}
- name: Run unit tests - name: Run unit tests
timeout-minutes: ${{ contains(runner.name, 'nsc') && 1 || 20 }} timeout-minutes: ${{ contains(runner.name, 'nsc') && 1 || 20 }}
run: | run: |
${{ env.RUN }} "MAX_EXAMPLES=1 $PYTEST --timeout 60 -m 'not slow' && \ ${{ env.RUN }} "$PYTEST --collect-only -m 'not slow' &> /dev/null && \
MAX_EXAMPLES=1 $PYTEST -m 'not slow' && \
./selfdrive/ui/tests/create_test_translations.sh && \ ./selfdrive/ui/tests/create_test_translations.sh && \
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations" QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
chmod -R 777 /tmp/comma_download_cache"
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v4
with: with:

View File

@ -168,18 +168,18 @@ class TestMessaging:
# this test doesn't work with ZMQ since multiprocessing interrupts it # this test doesn't work with ZMQ since multiprocessing interrupts it
if "ZMQ" not in os.environ: if "ZMQ" not in os.environ:
# wait 15 socket timeouts and make sure it's still retrying # wait 5 socket timeouts and make sure it's still retrying
p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,)) p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,))
p.start() p.start()
time.sleep(sock_timeout*15) time.sleep(sock_timeout*5)
assert p.is_alive() assert p.is_alive()
p.terminate() p.terminate()
# wait 15 socket timeouts before sending # wait 5 socket timeouts before sending
msg = random_carstate() msg = random_carstate()
delayed_send(sock_timeout*15, pub_sock, msg.to_bytes()) delayed_send(sock_timeout*5, pub_sock, msg.to_bytes())
start_time = time.monotonic() start_time = time.monotonic()
recvd = messaging.recv_one_retry(sub_sock) recvd = messaging.recv_one_retry(sub_sock)
assert (time.monotonic() - start_time) >= sock_timeout*15 assert (time.monotonic() - start_time) >= sock_timeout*5
assert isinstance(recvd, capnp._DynamicStructReader) assert isinstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState) assert_carstate(msg.carState, recvd.carState)

View File

@ -1,4 +1,5 @@
import copy import copy
import os
from hypothesis import given, HealthCheck, Phase, settings from hypothesis import given, HealthCheck, Phase, settings
import hypothesis.strategies as st import hypothesis.strategies as st
from parameterized import parameterized from parameterized import parameterized
@ -14,13 +15,15 @@ import openpilot.selfdrive.test.process_replay.process_replay as pr
NOT_TESTED = ['selfdrived', 'controlsd', 'card', 'plannerd', 'calibrationd', 'dmonitoringd', 'paramsd', 'dmonitoringmodeld', 'modeld'] NOT_TESTED = ['selfdrived', 'controlsd', 'card', 'plannerd', 'calibrationd', 'dmonitoringd', 'paramsd', 'dmonitoringmodeld', 'modeld']
TEST_CASES = [(cfg.proc_name, copy.deepcopy(cfg)) for cfg in pr.CONFIGS if cfg.proc_name not in NOT_TESTED] TEST_CASES = [(cfg.proc_name, copy.deepcopy(cfg)) for cfg in pr.CONFIGS if cfg.proc_name not in NOT_TESTED]
MAX_EXAMPLES = int(os.environ.get("MAX_EXAMPLES", "10"))
class TestFuzzProcesses: class TestFuzzProcesses:
# TODO: make this faster and increase examples # TODO: make this faster and increase examples
@parameterized.expand(TEST_CASES) @parameterized.expand(TEST_CASES)
@given(st.data()) @given(st.data())
@settings(phases=[Phase.generate, Phase.target], max_examples=10, deadline=1000, suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large]) @settings(phases=[Phase.generate, Phase.target], max_examples=MAX_EXAMPLES, deadline=1000,
suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
def test_fuzz_process(self, proc_name, cfg, data): def test_fuzz_process(self, proc_name, cfg, data):
msgs = FuzzyGenerator.get_random_event_msg(data.draw, events=cfg.pubs, real_floats=True) msgs = FuzzyGenerator.get_random_event_msg(data.draw, events=cfg.pubs, real_floats=True)
lr = [log.Event.new_message(**m).as_reader() for m in msgs] lr = [log.Event.new_message(**m).as_reader() for m in msgs]

View File

@ -19,7 +19,7 @@ class TestLogmessaged:
self.error_sock = messaging.sub_sock("logMessage", timeout=1000, conflate=False) self.error_sock = messaging.sub_sock("logMessage", timeout=1000, conflate=False)
# ensure sockets are connected # ensure sockets are connected
time.sleep(1) time.sleep(0.5)
messaging.drain_sock(self.sock) messaging.drain_sock(self.sock)
messaging.drain_sock(self.error_sock) messaging.drain_sock(self.error_sock)
@ -35,7 +35,7 @@ class TestLogmessaged:
msgs = [f"abc {i}" for i in range(10)] msgs = [f"abc {i}" for i in range(10)]
for m in msgs: for m in msgs:
cloudlog.error(m) cloudlog.error(m)
time.sleep(1) time.sleep(0.5)
m = messaging.drain_sock(self.sock) m = messaging.drain_sock(self.sock)
assert len(m) == len(msgs) assert len(m) == len(msgs)
assert len(self._get_log_files()) >= 1 assert len(self._get_log_files()) >= 1
@ -45,7 +45,7 @@ class TestLogmessaged:
msg = "a"*3*1024*1024 msg = "a"*3*1024*1024
for _ in range(n): for _ in range(n):
cloudlog.info(msg) cloudlog.info(msg)
time.sleep(1) time.sleep(0.5)
msgs = messaging.drain_sock(self.sock) msgs = messaging.drain_sock(self.sock)
assert len(msgs) == 0 assert len(msgs) == 0

View File

@ -23,42 +23,6 @@ bool download_to_file(const std::string &url, const std::string &local_file, int
return false; return false;
} }
TEST_CASE("httpMultiPartDownload") {
char filename[] = "/tmp/XXXXXX";
close(mkstemp(filename));
const size_t chunk_size = 5 * 1024 * 1024;
std::string content;
SECTION("download to file") {
REQUIRE(download_to_file(TEST_RLOG_URL, filename, chunk_size));
content = util::read_file(filename);
}
SECTION("download to buffer") {
for (int i = 0; i < 3 && content.empty(); ++i) {
content = httpGet(TEST_RLOG_URL, chunk_size);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
REQUIRE(!content.empty());
}
REQUIRE(content.size() == 9112651);
REQUIRE(sha256(content) == TEST_RLOG_CHECKSUM);
}
TEST_CASE("FileReader") {
auto enable_local_cache = GENERATE(true, false);
std::string cache_file = cacheFilePath(TEST_RLOG_URL);
system(("rm " + cache_file + " -f").c_str());
FileReader reader(enable_local_cache);
std::string content = reader.read(TEST_RLOG_URL);
REQUIRE(sha256(content) == TEST_RLOG_CHECKSUM);
if (enable_local_cache) {
REQUIRE(sha256(util::read_file(cache_file)) == TEST_RLOG_CHECKSUM);
} else {
REQUIRE(util::file_exists(cache_file) == false);
}
}
TEST_CASE("LogReader") { TEST_CASE("LogReader") {
SECTION("corrupt log") { SECTION("corrupt log") {
FileReader reader(true); FileReader reader(true);
@ -134,34 +98,3 @@ std::string download_demo_route() {
return data_dir; return data_dir;
} }
TEST_CASE("Getting route") {
std::string data_dir = download_demo_route();
auto flags = GENERATE(0, REPLAY_FLAG_QCAMERA);
Route route(DEMO_ROUTE, data_dir);
REQUIRE(route.load());
REQUIRE(route.segments().size() == 2);
for (int i = 0; i < TEST_REPLAY_SEGMENTS; ++i) {
read_segment(i, route.at(i), flags);
}
}
TEST_CASE("seek_to") {
QEventLoop loop;
int seek_to = util::random_int(0, 2 * 59);
Replay replay(DEMO_ROUTE, {}, {}, nullptr, REPLAY_FLAG_NO_VIPC);
QObject::connect(&replay, &Replay::seekedTo, [&](double sec) {
INFO("seek to " << seek_to << "s sought to" << sec);
REQUIRE(sec >= seek_to);
loop.quit();
});
REQUIRE(replay.load());
replay.start();
replay.seekTo(seek_to, false);
loop.exec();
}