Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(4)

Unified Diff: external_tests/ssl_gtest/ssl_internal_unittest.cc

Issue 279190043: Add simple tests for a few libssl internal interfaces.
Patch Set: Add simple tests for a few libssl internal interfaces. [v4] Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « external_tests/ssl_gtest/manifest.mn ('k') | lib/ssl/ssl3con.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: external_tests/ssl_gtest/ssl_internal_unittest.cc
diff --git a/external_tests/ssl_gtest/ssl_internal_unittest.cc b/external_tests/ssl_gtest/ssl_internal_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7e2a32be7cf5f8c33378eaa8e489eee45a89b5ff
--- /dev/null
+++ b/external_tests/ssl_gtest/ssl_internal_unittest.cc
@@ -0,0 +1,233 @@
+// -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vim: set ts=2 et sw=2 tw=80:
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <string.h>
+#ifdef XP_UNIX
+#include <sys/resource.h>
+#endif
+
+#include <memory> // for unique_ptr
+
+#include "prthread.h"
+
+#include "gtest_utils.h"
+#include "keyhi.h"
+#include "scoped_ptrs.h"
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslimpl.h"
+#include "test_io.h"
+
+namespace nss_test {
+
+// This can't be defined in scoped_ptrs.h because that's shared with
+// other tests that aren't set up to include sslimpl.h to get the
+// ssl3* internal declarations.
+struct ScopedMaybeDeleteKeyPair {
+ void operator()(ssl3KeyPair* ptr) {
+ if (ptr) {
+ ssl3_FreeKeyPair(ptr);
+ }
+ }
+};
+typedef std::unique_ptr<ssl3KeyPair, ScopedMaybeDeleteKeyPair> ScopedKeyPair;
+
+// DEBUG_ASSERT_DEATH, for operations that should crash on debug
+// builds and do something expected on non-debug builds.
+// TODO(jld@mozilla.com), bug 1243238: move this into a common location.
+#ifdef DEBUG
+#ifdef XP_UNIX
+// Unix + debug: check that assertion crashes as expected; suppress
+// core dumps, which the test harness would treat as a failure.
+class SuppressCoreDump {
+public:
+ SuppressCoreDump() {
+ if (getrlimit(RLIMIT_CORE, &saved_limit_) != 0) {
+ saved_limit_.rlim_cur = saved_limit_.rlim_max = RLIM_INFINITY;
+ }
+ struct ::rlimit new_limit = saved_limit_;
+ new_limit.rlim_cur = 0;
+ setrlimit(RLIMIT_CORE, &new_limit);
+ }
+
+ ~SuppressCoreDump() {
+ setrlimit(RLIMIT_CORE, &saved_limit_);
+ }
+
+private:
+ struct ::rlimit saved_limit_;
+};
+
+#define DEBUG_ASSERT_DEATH(stmt, regex) ASSERT_DEATH_IF_SUPPORTED({ \
+ SuppressCoreDump _coreDumpGuard; \
+ stmt; \
+ }, regex)
+#else
+// Not-Unix + debug: check that assertion crashes; core dumps not an issue.
+#define DEBUG_ASSERT_DEATH(stmt, regex) ASSERT_DEATH_IF_SUPPORTED(stmt, regex)
+#endif
+#else
+// Non-debug: check that the bad thing *doesn't* crash by doing it.
+#define DEBUG_ASSERT_DEATH(stmt, regex) stmt
+#endif
+
+class InternalSocketTest : public ::testing::Test {
+public:
+ InternalSocketTest() : fd_(nullptr), ss_(nullptr) { }
+ ~InternalSocketTest() { }
+
+ void SetUp() {
+ fd_.reset(DummyPrSocket::CreateFD("fake", STREAM));
+ ASSERT_NE(nullptr, fd_);
+ ASSERT_EQ(fd_.get(), SSL_ImportFD(nullptr, fd_.get()));
+ ss_ = ssl_FindSocket(fd_.get());
+ ASSERT_NE(nullptr, ss_);
+ }
+
+protected:
+ ScopedPRFileDesc fd_;
+ sslSocket *ss_; // The sslSocket is owned by the PRFileDesc.
+};
+
+class InternalKeyPairTest : public ::testing::Test {
+public:
+ InternalKeyPairTest() : keys_(nullptr) { }
+ ~InternalKeyPairTest() { }
+
+ void SetUp() {
+ static const ECName curve = ec_secp256r1;
+ ScopedSECItem ecParams(SECITEM_AllocItem(nullptr, // no arena
+ nullptr, // not reallocating
+ 0)); // length
+ ASSERT_TRUE(ecParams);
+ ASSERT_EQ(SECSuccess,
+ ssl3_ECName2Params(nullptr, // no arena
+ curve, ecParams.get()));
+ EXPECT_NE(nullptr, ecParams->data);
+ EXPECT_NE(0U, ecParams->len);
+
+
+ SECKEYPublicKey *tmpPubKey;
+ ScopedSECKEYPrivateKey
+ privKey(SECKEY_CreateECPrivateKey(ecParams.get(),
+ &tmpPubKey,
+ nullptr)); // no UI context
+ ScopedSECKEYPublicKey pubKey(tmpPubKey);
+
+ ASSERT_TRUE(privKey);
+ ASSERT_TRUE(pubKey);
+
+ keys_.reset(ssl3_NewKeyPair(privKey.release(), pubKey.release()));
+ ASSERT_TRUE(keys_);
+ }
+
+protected:
+ ScopedKeyPair keys_;
+};
+
+template<class F>
+static void
+ThreadFunctionalMain(void *vp) {
+ (*static_cast<const F*>(vp))();
+}
+
+template<class F>
+static void
+RunOnThreads(size_t numThreads, const F& func)
+{
+ void* vp = const_cast<void*>(static_cast<const void*>(&func));
+ std::unique_ptr<PRThread*[]> threads(new PRThread*[numThreads]);
+
+ for (size_t i = 0; i < numThreads; ++i) {
+ threads[i] = PR_CreateThread(PR_SYSTEM_THREAD,
+ ThreadFunctionalMain<F>,
+ vp,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0); // use default stack size
+ ASSERT_NE(nullptr, threads[i]);
+ }
+ for (size_t i = 0; i < numThreads; ++i) {
+ EXPECT_EQ(PR_SUCCESS, PR_JoinThread(threads[i]));
+ }
+}
+
+TEST(SSL3Random, SmokeTest) {
+ // Check that two successive random numbers aren't equal. This is
+ // wrong with probability 2**-256 per test run, which is negligible.
+ SSL3Random r0;
+ ASSERT_EQ(SECSuccess, ssl3_GetNewRandom(&r0));
+ SSL3Random r1;
+ ASSERT_EQ(SECSuccess, ssl3_GetNewRandom(&r1));
+ EXPECT_NE(0, memcmp(&r0, &r1, SSL3_RANDOM_LENGTH));
+
+ // ssl3_GetNewRandom uses the "rand" field, but other code memcpy()s
+ // the first SSL3_RANDOM_LENGTH bytes, so make sure that does what's
+ // expected:
+ ASSERT_LE(static_cast<size_t>(SSL3_RANDOM_LENGTH), sizeof(SSL3Random));
+ ASSERT_EQ(static_cast<void*>(&r0), static_cast<void*>(r0.rand));
+}
+
+typedef InternalSocketTest InternalSocketDeathTest;
+
+TEST_F(InternalSocketDeathTest, DoubleUnlockReader) {
+ // On non-debug builds, an excess unlock is ignored. There isn't a
+ // clean way to verify that directly, but the second loop iteration
+ // will at least show that further lock operations don't crash.
+ for (int i = 0; i < 2; ++i) {
+ SSL_LOCK_READER(ss_);
+ SSL_UNLOCK_READER(ss_);
+ DEBUG_ASSERT_DEATH(SSL_UNLOCK_READER(ss_), "Assertion failure:");
+ }
+}
+
+TEST_F(InternalSocketDeathTest, DoubleUnlock1stHandshake) {
+ // Similarly to the above test, except that this lock supports an
+ // "is this held" operation, so on non-debug builds the second loop
+ // iteration will better verify that the extra unlock is ignored as
+ // expected.
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_FALSE(ssl_Have1stHandshakeLock(ss_));
+ ssl_Get1stHandshakeLock(ss_);
+ EXPECT_TRUE(ssl_Have1stHandshakeLock(ss_));
+ ssl_Release1stHandshakeLock(ss_);
+ EXPECT_FALSE(ssl_Have1stHandshakeLock(ss_));
+ DEBUG_ASSERT_DEATH(ssl_Release1stHandshakeLock(ss_), "Assertion failure:");
+ }
+}
+
+TEST_F(InternalKeyPairTest, RefCountSimple) {
+ EXPECT_EQ(1, keys_->refCount);
+ EXPECT_EQ(keys_.get(), ssl3_GetKeyPairRef(keys_.get()));
+ EXPECT_EQ(2, keys_->refCount);
+ ssl3_FreeKeyPair(keys_.get());
+ EXPECT_EQ(1, keys_->refCount);
+}
+
+TEST_F(InternalKeyPairTest, RefCountThreaded) {
+ static const size_t numThreads = 5;
+ static const size_t iterations = 1000000;
+ ssl3KeyPair *const keys = keys_.get();
+
+ RunOnThreads(numThreads, [=]{
+ for (size_t i = 0; i < iterations; ++i) {
+ ssl3_GetKeyPairRef(keys);
+ }
+ });
+
+ ASSERT_EQ(1 + numThreads * iterations, static_cast<size_t>(keys->refCount));
+
+ RunOnThreads(numThreads, [=]{
+ for (size_t i = 0; i < iterations; ++i) {
+ ssl3_FreeKeyPair(keys);
+ }
+ });
+
+ EXPECT_EQ(1, keys->refCount);
+}
+
+} // namespace nss_test
« no previous file with comments | « external_tests/ssl_gtest/manifest.mn ('k') | lib/ssl/ssl3con.c » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b