From bbf78c963640e3fd857d46c3b42cd47cf1e02638 Mon Sep 17 00:00:00 2001 From: Ahmad Samir Date: Thu, 26 Dec 2024 14:11:46 +0200 Subject: [PATCH] tst_QCryptographicHash: split 4GiB tests to a separate unit test With those tests split, tst_QCryptographicHash takes about 4ms. When FEATURE_openssl_hash is enabled those tests take about 15s on their own, but when openssl_hash is disabled they take about 2 minutes. That makes running the tests locally a bit of a hassle when hacking code ... test ... hack ... test. This is with a debug build, GCC, `-O0 -g` flags. Change-Id: I8b8f5d1954feb1f9eb8115e27635610a41b42f47 Reviewed-by: Thiago Macieira (cherry picked from commit fff217824b532da7306af1ac755581e76e098a27) Reviewed-by: Qt Cherry-pick Bot --- .../tools/qcryptographichash/CMakeLists.txt | 6 + .../tst_qcryptographichash.cpp | 113 --------------- .../tst_qcryptographichash_bigdata.cpp | 133 ++++++++++++++++++ 3 files changed, 139 insertions(+), 113 deletions(-) create mode 100644 tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash_bigdata.cpp diff --git a/tests/auto/corelib/tools/qcryptographichash/CMakeLists.txt b/tests/auto/corelib/tools/qcryptographichash/CMakeLists.txt index 8a0c08fcadf..b83afa74d04 100644 --- a/tests/auto/corelib/tools/qcryptographichash/CMakeLists.txt +++ b/tests/auto/corelib/tools/qcryptographichash/CMakeLists.txt @@ -23,6 +23,12 @@ qt_internal_add_test(tst_qcryptographichash TESTDATA ${test_data} ) +qt_internal_add_test(tst_qcryptographichash_bigdata + SOURCES + tst_qcryptographichash_bigdata.cpp + TESTDATA ${test_data} +) + if(QT_FEATURE_sanitize_address) set_property(TEST tst_qcryptographichash APPEND PROPERTY ENVIRONMENT "QTEST_FUNCTION_TIMEOUT=900000") endif() diff --git a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp index 47e0ead2708..60a0d2dcf09 100644 --- a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp +++ b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp @@ -8,8 +8,6 @@ #include #include -#include - Q_DECLARE_METATYPE(QCryptographicHash::Algorithm) class tst_QCryptographicHash : public QObject @@ -37,10 +35,6 @@ private slots: void addDataAcceptsNullByteArrayView(); void move(); void swap(); - // keep last - void moreThan4GiBOfData_data(); - void moreThan4GiBOfData(); - void keccakBufferOverflow(); private: void all_methods(bool includingNumAlgorithms) const; void ensureLargeData(); @@ -577,112 +571,5 @@ void tst_QCryptographicHash::swap() QCOMPARE(hash1.result(), QCryptographicHash::hash("test", QCryptographicHash::Sha256)); } -void tst_QCryptographicHash::ensureLargeData() -{ -#if QT_POINTER_SIZE > 4 - QElapsedTimer timer; - timer.start(); - const size_t GiB = 1024 * 1024 * 1024; - if (large.size() == 4 * GiB + 1) - return; - try { - large.resize(4 * GiB + 1, '\0'); - } catch (const std::bad_alloc &) { - QSKIP("Could not allocate 4GiB plus one byte of RAM."); - } - QCOMPARE(large.size(), 4 * GiB + 1); - large.back() = '\1'; - qDebug("created dataset in %lld ms", timer.elapsed()); -#endif -} - -void tst_QCryptographicHash::moreThan4GiBOfData_data() -{ -#if QT_POINTER_SIZE > 4 - if (ensureLargeData(); large.empty()) - return; - QTest::addColumn("algorithm"); - auto me = QMetaEnum::fromType(); - auto row = [me] (QCryptographicHash::Algorithm algo) { - QTest::addRow("%s", me.valueToKey(int(algo))) << algo; - }; - // these are reasonably fast (O(secs)) - row(QCryptographicHash::Md4); - row(QCryptographicHash::Md5); - row(QCryptographicHash::Sha1); - if (!qgetenv("QTEST_ENVIRONMENT").split(' ').contains("ci")) { - // This is important but so slow (O(minute)) that, on CI, it tends to time out. - // Retain it for manual runs, all the same, as most dev machines will be fast enough. - row(QCryptographicHash::Sha512); - } - // the rest is just too slow -#else - QSKIP("This test is 64-bit only."); -#endif -} - -void tst_QCryptographicHash::moreThan4GiBOfData() -{ - QFETCH(const QCryptographicHash::Algorithm, algorithm); - - using MaybeThread = std::thread; - - QElapsedTimer timer; - timer.start(); - const auto sg = qScopeGuard([&] { - qDebug() << algorithm << "test finished in" << timer.restart() << "ms"; - }); - - const auto view = QByteArrayView{large}; - const auto first = view.first(view.size() / 2); - const auto last = view.sliced(view.size() / 2); - - QByteArray single; - QByteArray chunked; - - auto t = MaybeThread{[&] { - QCryptographicHash h(algorithm); - h.addData(view); - single = h.result(); - }}; - { - QCryptographicHash h(algorithm); - h.addData(first); - h.addData(last); - chunked = h.result(); - } - t.join(); - - QCOMPARE(single, chunked); -} - -void tst_QCryptographicHash::keccakBufferOverflow() -{ -#if QT_POINTER_SIZE == 4 - QSKIP("This is a 64-bit-only test"); -#else - - if (ensureLargeData(); large.empty()) - return; - - QElapsedTimer timer; - timer.start(); - const auto sg = qScopeGuard([&] { - qDebug() << "test finished in" << timer.restart() << "ms"; - }); - - constexpr qsizetype magic = INT_MAX/4; - QCOMPARE_GE(large.size(), size_t(magic + 1)); - - QCryptographicHash hash(QCryptographicHash::Algorithm::Keccak_224); - const auto first = QByteArrayView{large}.first(1); - const auto second = QByteArrayView{large}.sliced(1, magic); - hash.addData(first); - hash.addData(second); - (void)hash.resultView(); - QVERIFY(true); // didn't crash -#endif -} - QTEST_MAIN(tst_QCryptographicHash) #include "tst_qcryptographichash.moc" diff --git a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash_bigdata.cpp b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash_bigdata.cpp new file mode 100644 index 00000000000..a07453a76f9 --- /dev/null +++ b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash_bigdata.cpp @@ -0,0 +1,133 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include +#include +#include +#include + +#include + +Q_DECLARE_METATYPE(QCryptographicHash::Algorithm) + +class tst_QCryptographicHashBigData : public QObject +{ + Q_OBJECT +private slots: + void moreThan4GiBOfData_data(); + void moreThan4GiBOfData(); + void keccakBufferOverflow(); +private: + void ensureLargeData(); + std::vector large; +}; + +void tst_QCryptographicHashBigData::ensureLargeData() +{ +#if QT_POINTER_SIZE > 4 + QElapsedTimer timer; + timer.start(); + const size_t GiB = 1024 * 1024 * 1024; + if (large.size() == 4 * GiB + 1) + return; + try { + large.resize(4 * GiB + 1, '\0'); + } catch (const std::bad_alloc &) { + QSKIP("Could not allocate 4GiB plus one byte of RAM."); + } + QCOMPARE(large.size(), 4 * GiB + 1); + large.back() = '\1'; + qDebug("created dataset in %lld ms", timer.elapsed()); +#endif +} + +void tst_QCryptographicHashBigData::moreThan4GiBOfData_data() +{ +#if QT_POINTER_SIZE > 4 + if (ensureLargeData(); large.empty()) + return; + QTest::addColumn("algorithm"); + auto me = QMetaEnum::fromType(); + auto row = [me] (QCryptographicHash::Algorithm algo) { + QTest::addRow("%s", me.valueToKey(int(algo))) << algo; + }; + // these are reasonably fast (O(secs)) + row(QCryptographicHash::Md4); + row(QCryptographicHash::Md5); + row(QCryptographicHash::Sha1); + if (!qgetenv("QTEST_ENVIRONMENT").split(' ').contains("ci")) { + // This is important but so slow (O(minute)) that, on CI, it tends to time out. + // Retain it for manual runs, all the same, as most dev machines will be fast enough. + row(QCryptographicHash::Sha512); + } + // the rest is just too slow +#else + QSKIP("This test is 64-bit only."); +#endif +} + +void tst_QCryptographicHashBigData::moreThan4GiBOfData() +{ + QFETCH(const QCryptographicHash::Algorithm, algorithm); + + using MaybeThread = std::thread; + + QElapsedTimer timer; + timer.start(); + const auto sg = qScopeGuard([&] { + qDebug() << algorithm << "test finished in" << timer.restart() << "ms"; + }); + + const auto view = QByteArrayView{large}; + const auto first = view.first(view.size() / 2); + const auto last = view.sliced(view.size() / 2); + + QByteArray single; + QByteArray chunked; + + auto t = MaybeThread{[&] { + QCryptographicHash h(algorithm); + h.addData(view); + single = h.result(); + }}; + { + QCryptographicHash h(algorithm); + h.addData(first); + h.addData(last); + chunked = h.result(); + } + t.join(); + + QCOMPARE(single, chunked); +} + +void tst_QCryptographicHashBigData::keccakBufferOverflow() +{ +#if QT_POINTER_SIZE == 4 + QSKIP("This is a 64-bit-only test"); +#else + + if (ensureLargeData(); large.empty()) + return; + + QElapsedTimer timer; + timer.start(); + const auto sg = qScopeGuard([&] { + qDebug() << "test finished in" << timer.restart() << "ms"; + }); + + constexpr qsizetype magic = INT_MAX/4; + QCOMPARE_GE(large.size(), size_t(magic + 1)); + + QCryptographicHash hash(QCryptographicHash::Algorithm::Keccak_224); + const auto first = QByteArrayView{large}.first(1); + const auto second = QByteArrayView{large}.sliced(1, magic); + hash.addData(first); + hash.addData(second); + (void)hash.resultView(); + QVERIFY(true); // didn't crash +#endif +} + +QTEST_MAIN(tst_QCryptographicHashBigData) +#include "tst_qcryptographichash_bigdata.moc"