1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/ssl/ssl_client_session_cache_openssl.h"
7 #include <openssl/ssl.h>
9 #include "base/strings/string_number_conversions.h"
10 #include "base/test/simple_test_clock.h"
11 #include "net/ssl/scoped_openssl_types.h"
12 #include "testing/gtest/include/gtest/gtest.h"
16 // Test basic insertion and lookup operations.
17 TEST(SSLClientSessionCacheOpenSSLTest
, Basic
) {
18 SSLClientSessionCacheOpenSSL::Config config
;
19 SSLClientSessionCacheOpenSSL
cache(config
);
21 ScopedSSL_SESSION
session1(SSL_SESSION_new());
22 ScopedSSL_SESSION
session2(SSL_SESSION_new());
23 ScopedSSL_SESSION
session3(SSL_SESSION_new());
24 EXPECT_EQ(1u, session1
->references
);
25 EXPECT_EQ(1u, session2
->references
);
26 EXPECT_EQ(1u, session3
->references
);
28 EXPECT_EQ(nullptr, cache
.Lookup("key1"));
29 EXPECT_EQ(nullptr, cache
.Lookup("key2"));
30 EXPECT_EQ(0u, cache
.size());
32 cache
.Insert("key1", session1
.get());
33 EXPECT_EQ(session1
.get(), cache
.Lookup("key1"));
34 EXPECT_EQ(nullptr, cache
.Lookup("key2"));
35 EXPECT_EQ(1u, cache
.size());
37 cache
.Insert("key2", session2
.get());
38 EXPECT_EQ(session1
.get(), cache
.Lookup("key1"));
39 EXPECT_EQ(session2
.get(), cache
.Lookup("key2"));
40 EXPECT_EQ(2u, cache
.size());
42 EXPECT_EQ(2u, session1
->references
);
43 EXPECT_EQ(2u, session2
->references
);
45 cache
.Insert("key1", session3
.get());
46 EXPECT_EQ(session3
.get(), cache
.Lookup("key1"));
47 EXPECT_EQ(session2
.get(), cache
.Lookup("key2"));
48 EXPECT_EQ(2u, cache
.size());
50 EXPECT_EQ(1u, session1
->references
);
51 EXPECT_EQ(2u, session2
->references
);
52 EXPECT_EQ(2u, session3
->references
);
55 EXPECT_EQ(nullptr, cache
.Lookup("key1"));
56 EXPECT_EQ(nullptr, cache
.Lookup("key2"));
57 EXPECT_EQ(nullptr, cache
.Lookup("key3"));
58 EXPECT_EQ(0u, cache
.size());
60 EXPECT_EQ(1u, session1
->references
);
61 EXPECT_EQ(1u, session2
->references
);
62 EXPECT_EQ(1u, session3
->references
);
65 // Test that a session may be inserted at two different keys. This should never
66 // be necessary, but the API doesn't prohibit it.
67 TEST(SSLClientSessionCacheOpenSSLTest
, DoubleInsert
) {
68 SSLClientSessionCacheOpenSSL::Config config
;
69 SSLClientSessionCacheOpenSSL
cache(config
);
71 ScopedSSL_SESSION
session(SSL_SESSION_new());
72 EXPECT_EQ(1u, session
->references
);
74 EXPECT_EQ(nullptr, cache
.Lookup("key1"));
75 EXPECT_EQ(nullptr, cache
.Lookup("key2"));
76 EXPECT_EQ(0u, cache
.size());
78 cache
.Insert("key1", session
.get());
79 EXPECT_EQ(session
.get(), cache
.Lookup("key1"));
80 EXPECT_EQ(nullptr, cache
.Lookup("key2"));
81 EXPECT_EQ(1u, cache
.size());
83 EXPECT_EQ(2u, session
->references
);
85 cache
.Insert("key2", session
.get());
86 EXPECT_EQ(session
.get(), cache
.Lookup("key1"));
87 EXPECT_EQ(session
.get(), cache
.Lookup("key2"));
88 EXPECT_EQ(2u, cache
.size());
90 EXPECT_EQ(3u, session
->references
);
93 EXPECT_EQ(nullptr, cache
.Lookup("key1"));
94 EXPECT_EQ(nullptr, cache
.Lookup("key2"));
95 EXPECT_EQ(0u, cache
.size());
97 EXPECT_EQ(1u, session
->references
);
100 // Tests that the session cache's size is correctly bounded.
101 TEST(SSLClientSessionCacheOpenSSLTest
, MaxEntries
) {
102 SSLClientSessionCacheOpenSSL::Config config
;
103 config
.max_entries
= 3;
104 SSLClientSessionCacheOpenSSL
cache(config
);
106 ScopedSSL_SESSION
session1(SSL_SESSION_new());
107 ScopedSSL_SESSION
session2(SSL_SESSION_new());
108 ScopedSSL_SESSION
session3(SSL_SESSION_new());
109 ScopedSSL_SESSION
session4(SSL_SESSION_new());
111 // Insert three entries.
112 cache
.Insert("key1", session1
.get());
113 cache
.Insert("key2", session2
.get());
114 cache
.Insert("key3", session3
.get());
115 EXPECT_EQ(session1
.get(), cache
.Lookup("key1"));
116 EXPECT_EQ(session2
.get(), cache
.Lookup("key2"));
117 EXPECT_EQ(session3
.get(), cache
.Lookup("key3"));
118 EXPECT_EQ(3u, cache
.size());
120 // On insertion of a fourth, the first is removed.
121 cache
.Insert("key4", session4
.get());
122 EXPECT_EQ(nullptr, cache
.Lookup("key1"));
123 EXPECT_EQ(session4
.get(), cache
.Lookup("key4"));
124 EXPECT_EQ(session3
.get(), cache
.Lookup("key3"));
125 EXPECT_EQ(session2
.get(), cache
.Lookup("key2"));
126 EXPECT_EQ(3u, cache
.size());
128 // Despite being newest, the next to be removed is session4 as it was accessed
130 cache
.Insert("key1", session1
.get());
131 EXPECT_EQ(session1
.get(), cache
.Lookup("key1"));
132 EXPECT_EQ(session2
.get(), cache
.Lookup("key2"));
133 EXPECT_EQ(session3
.get(), cache
.Lookup("key3"));
134 EXPECT_EQ(nullptr, cache
.Lookup("key4"));
135 EXPECT_EQ(3u, cache
.size());
138 // Tests that session expiration works properly.
139 TEST(SSLClientSessionCacheOpenSSLTest
, Expiration
) {
140 const size_t kNumEntries
= 20;
141 const size_t kExpirationCheckCount
= 10;
142 const base::TimeDelta kTimeout
= base::TimeDelta::FromSeconds(1000);
144 SSLClientSessionCacheOpenSSL::Config config
;
145 config
.expiration_check_count
= kExpirationCheckCount
;
146 config
.timeout
= kTimeout
;
147 SSLClientSessionCacheOpenSSL
cache(config
);
148 base::SimpleTestClock
* clock
= new base::SimpleTestClock
;
149 cache
.SetClockForTesting(make_scoped_ptr(clock
));
151 // Add |kNumEntries - 1| entries.
152 for (size_t i
= 0; i
< kNumEntries
- 1; i
++) {
153 ScopedSSL_SESSION
session(SSL_SESSION_new());
154 cache
.Insert(base::SizeTToString(i
), session
.get());
156 EXPECT_EQ(kNumEntries
- 1, cache
.size());
158 // Expire all the previous entries and insert one more entry.
159 clock
->Advance(kTimeout
* 2);
160 ScopedSSL_SESSION
session(SSL_SESSION_new());
161 cache
.Insert("key", session
.get());
163 // All entries are still in the cache.
164 EXPECT_EQ(kNumEntries
, cache
.size());
166 // Perform one fewer lookup than needed to trigger the expiration check. This
167 // shall not expire any session.
168 for (size_t i
= 0; i
< kExpirationCheckCount
- 1; i
++)
171 // All entries are still in the cache.
172 EXPECT_EQ(kNumEntries
, cache
.size());
174 // Perform one more lookup. This will expire all sessions but the last one.
176 EXPECT_EQ(1u, cache
.size());
177 EXPECT_EQ(session
.get(), cache
.Lookup("key"));
178 for (size_t i
= 0; i
< kNumEntries
- 1; i
++) {
180 EXPECT_EQ(nullptr, cache
.Lookup(base::SizeTToString(i
)));
184 // Tests that Lookup performs an expiration check before returning a cached
186 TEST(SSLClientSessionCacheOpenSSLTest
, LookupExpirationCheck
) {
187 // kExpirationCheckCount is set to a suitably large number so the automated
188 // pruning never triggers.
189 const size_t kExpirationCheckCount
= 1000;
190 const base::TimeDelta kTimeout
= base::TimeDelta::FromSeconds(1000);
192 SSLClientSessionCacheOpenSSL::Config config
;
193 config
.expiration_check_count
= kExpirationCheckCount
;
194 config
.timeout
= kTimeout
;
195 SSLClientSessionCacheOpenSSL
cache(config
);
196 base::SimpleTestClock
* clock
= new base::SimpleTestClock
;
197 cache
.SetClockForTesting(make_scoped_ptr(clock
));
199 // Insert an entry into the session cache.
200 ScopedSSL_SESSION
session(SSL_SESSION_new());
201 cache
.Insert("key", session
.get());
202 EXPECT_EQ(session
.get(), cache
.Lookup("key"));
203 EXPECT_EQ(1u, cache
.size());
205 // Expire the session.
206 clock
->Advance(kTimeout
* 2);
208 // The entry has not been removed yet.
209 EXPECT_EQ(1u, cache
.size());
211 // But it will not be returned on lookup and gets pruned at that point.
212 EXPECT_EQ(nullptr, cache
.Lookup("key"));
213 EXPECT_EQ(0u, cache
.size());
215 // Sessions also are treated as expired if the clock rewinds.
216 cache
.Insert("key", session
.get());
217 EXPECT_EQ(session
.get(), cache
.Lookup("key"));
218 EXPECT_EQ(1u, cache
.size());
220 clock
->Advance(-kTimeout
* 2);
222 EXPECT_EQ(nullptr, cache
.Lookup("key"));
223 EXPECT_EQ(0u, cache
.size());