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 <thiago.macieira@intel.com> (cherry picked from commit fff217824b532da7306af1ac755581e76e098a27) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
6790d8d716
commit
bbf78c9636
@ -23,6 +23,12 @@ qt_internal_add_test(tst_qcryptographichash
|
|||||||
TESTDATA ${test_data}
|
TESTDATA ${test_data}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
qt_internal_add_test(tst_qcryptographichash_bigdata
|
||||||
|
SOURCES
|
||||||
|
tst_qcryptographichash_bigdata.cpp
|
||||||
|
TESTDATA ${test_data}
|
||||||
|
)
|
||||||
|
|
||||||
if(QT_FEATURE_sanitize_address)
|
if(QT_FEATURE_sanitize_address)
|
||||||
set_property(TEST tst_qcryptographichash APPEND PROPERTY ENVIRONMENT "QTEST_FUNCTION_TIMEOUT=900000")
|
set_property(TEST tst_qcryptographichash APPEND PROPERTY ENVIRONMENT "QTEST_FUNCTION_TIMEOUT=900000")
|
||||||
endif()
|
endif()
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QtCore/QMetaEnum>
|
#include <QtCore/QMetaEnum>
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QCryptographicHash::Algorithm)
|
Q_DECLARE_METATYPE(QCryptographicHash::Algorithm)
|
||||||
|
|
||||||
class tst_QCryptographicHash : public QObject
|
class tst_QCryptographicHash : public QObject
|
||||||
@ -37,10 +35,6 @@ private slots:
|
|||||||
void addDataAcceptsNullByteArrayView();
|
void addDataAcceptsNullByteArrayView();
|
||||||
void move();
|
void move();
|
||||||
void swap();
|
void swap();
|
||||||
// keep last
|
|
||||||
void moreThan4GiBOfData_data();
|
|
||||||
void moreThan4GiBOfData();
|
|
||||||
void keccakBufferOverflow();
|
|
||||||
private:
|
private:
|
||||||
void all_methods(bool includingNumAlgorithms) const;
|
void all_methods(bool includingNumAlgorithms) const;
|
||||||
void ensureLargeData();
|
void ensureLargeData();
|
||||||
@ -577,112 +571,5 @@ void tst_QCryptographicHash::swap()
|
|||||||
QCOMPARE(hash1.result(), QCryptographicHash::hash("test", QCryptographicHash::Sha256));
|
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<QCryptographicHash::Algorithm>("algorithm");
|
|
||||||
auto me = QMetaEnum::fromType<QCryptographicHash::Algorithm>();
|
|
||||||
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)
|
QTEST_MAIN(tst_QCryptographicHash)
|
||||||
#include "tst_qcryptographichash.moc"
|
#include "tst_qcryptographichash.moc"
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
// Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
|
#include <QtCore/QCoreApplication>
|
||||||
|
#include <QTest>
|
||||||
|
#include <QScopeGuard>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
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<char> 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<QCryptographicHash::Algorithm>("algorithm");
|
||||||
|
auto me = QMetaEnum::fromType<QCryptographicHash::Algorithm>();
|
||||||
|
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"
|
Loading…
x
Reference in New Issue
Block a user