Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: net/spdy/hpack/hpack_header_table_test.cc

Issue 2832973003: Split net/spdy into core and chromium subdirectories. (Closed)
Patch Set: Fix some more build rules. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/spdy/hpack/hpack_header_table.cc ('k') | net/spdy/hpack/hpack_huffman_decoder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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.
4
5 #include "net/spdy/hpack/hpack_header_table.h"
6
7 #include <algorithm>
8 #include <set>
9 #include <vector>
10
11 #include "base/macros.h"
12 #include "net/spdy/hpack/hpack_constants.h"
13 #include "net/spdy/hpack/hpack_entry.h"
14 #include "net/spdy/platform/api/spdy_string.h"
15 #include "net/spdy/spdy_flags.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace net {
19
20 using std::distance;
21
22 namespace test {
23
24 class HpackHeaderTablePeer {
25 public:
26 explicit HpackHeaderTablePeer(HpackHeaderTable* table) : table_(table) {}
27
28 const HpackHeaderTable::EntryTable& dynamic_entries() {
29 return table_->dynamic_entries_;
30 }
31 const HpackHeaderTable::EntryTable& static_entries() {
32 return table_->static_entries_;
33 }
34 size_t index_size() {
35 return table_->static_index_.size() + table_->dynamic_index_.size();
36 }
37 std::vector<HpackEntry*> EvictionSet(SpdyStringPiece name,
38 SpdyStringPiece value) {
39 HpackHeaderTable::EntryTable::iterator begin, end;
40 table_->EvictionSet(name, value, &begin, &end);
41 std::vector<HpackEntry*> result;
42 for (; begin != end; ++begin) {
43 result.push_back(&(*begin));
44 }
45 return result;
46 }
47 size_t total_insertions() { return table_->total_insertions_; }
48 size_t dynamic_entries_count() { return table_->dynamic_entries_.size(); }
49 size_t EvictionCountForEntry(SpdyStringPiece name, SpdyStringPiece value) {
50 return table_->EvictionCountForEntry(name, value);
51 }
52 size_t EvictionCountToReclaim(size_t reclaim_size) {
53 return table_->EvictionCountToReclaim(reclaim_size);
54 }
55 void Evict(size_t count) { return table_->Evict(count); }
56
57 void AddDynamicEntry(SpdyStringPiece name, SpdyStringPiece value) {
58 table_->dynamic_entries_.push_back(
59 HpackEntry(name, value, false, table_->total_insertions_++));
60 }
61
62 private:
63 HpackHeaderTable* table_;
64 };
65
66 } // namespace test
67
68 namespace {
69
70 class HpackHeaderTableTest : public ::testing::Test {
71 protected:
72 typedef std::vector<HpackEntry> HpackEntryVector;
73
74 HpackHeaderTableTest() : table_(), peer_(&table_) {}
75
76 // Returns an entry whose Size() is equal to the given one.
77 static HpackEntry MakeEntryOfSize(uint32_t size) {
78 EXPECT_GE(size, HpackEntry::kSizeOverhead);
79 SpdyString name((size - HpackEntry::kSizeOverhead) / 2, 'n');
80 SpdyString value(size - HpackEntry::kSizeOverhead - name.size(), 'v');
81 HpackEntry entry(name, value, false, 0);
82 EXPECT_EQ(size, entry.Size());
83 return entry;
84 }
85
86 // Returns a vector of entries whose total size is equal to the given
87 // one.
88 static HpackEntryVector MakeEntriesOfTotalSize(uint32_t total_size) {
89 EXPECT_GE(total_size, HpackEntry::kSizeOverhead);
90 uint32_t entry_size = HpackEntry::kSizeOverhead;
91 uint32_t remaining_size = total_size;
92 HpackEntryVector entries;
93 while (remaining_size > 0) {
94 EXPECT_LE(entry_size, remaining_size);
95 entries.push_back(MakeEntryOfSize(entry_size));
96 remaining_size -= entry_size;
97 entry_size = std::min(remaining_size, entry_size + 32);
98 }
99 return entries;
100 }
101
102 // Adds the given vector of entries to the given header table,
103 // expecting no eviction to happen.
104 void AddEntriesExpectNoEviction(const HpackEntryVector& entries) {
105 for (HpackEntryVector::const_iterator it = entries.begin();
106 it != entries.end(); ++it) {
107 HpackHeaderTable::EntryTable::iterator begin, end;
108
109 table_.EvictionSet(it->name(), it->value(), &begin, &end);
110 EXPECT_EQ(0, distance(begin, end));
111
112 const HpackEntry* entry = table_.TryAddEntry(it->name(), it->value());
113 EXPECT_NE(entry, static_cast<HpackEntry*>(NULL));
114 }
115
116 for (size_t i = 0; i != entries.size(); ++i) {
117 // Static table has 61 entries, dynamic entries follow those.
118 size_t index = 61 + entries.size() - i;
119 const HpackEntry* entry = table_.GetByIndex(index);
120 EXPECT_EQ(entries[i].name(), entry->name());
121 EXPECT_EQ(entries[i].value(), entry->value());
122 EXPECT_EQ(index, table_.IndexOf(entry));
123 }
124 }
125
126 HpackEntry DynamicEntry(const SpdyString& name, const SpdyString& value) {
127 peer_.AddDynamicEntry(name, value);
128 return peer_.dynamic_entries().back();
129 }
130
131 HpackHeaderTable table_;
132 test::HpackHeaderTablePeer peer_;
133 };
134
135 TEST_F(HpackHeaderTableTest, StaticTableInitialization) {
136 EXPECT_EQ(0u, table_.size());
137 EXPECT_EQ(kDefaultHeaderTableSizeSetting, table_.max_size());
138 EXPECT_EQ(kDefaultHeaderTableSizeSetting, table_.settings_size_bound());
139
140 EXPECT_EQ(0u, peer_.dynamic_entries_count());
141 EXPECT_EQ(peer_.static_entries().size(), peer_.total_insertions());
142
143 // Static entries have been populated and inserted into the table & index.
144 EXPECT_NE(0u, peer_.static_entries().size());
145 EXPECT_EQ(peer_.index_size(), peer_.static_entries().size());
146 for (size_t i = 0; i != peer_.static_entries().size(); ++i) {
147 const HpackEntry* entry = &peer_.static_entries()[i];
148
149 EXPECT_TRUE(entry->IsStatic());
150 EXPECT_EQ(entry, table_.GetByIndex(i + 1));
151 EXPECT_EQ(entry, table_.GetByNameAndValue(entry->name(), entry->value()));
152 }
153 }
154
155 TEST_F(HpackHeaderTableTest, BasicDynamicEntryInsertionAndEviction) {
156 size_t static_count = peer_.total_insertions();
157 const HpackEntry* first_static_entry = table_.GetByIndex(1);
158
159 EXPECT_EQ(1u, table_.IndexOf(first_static_entry));
160
161 const HpackEntry* entry = table_.TryAddEntry("header-key", "Header Value");
162 EXPECT_EQ("header-key", entry->name());
163 EXPECT_EQ("Header Value", entry->value());
164 EXPECT_FALSE(entry->IsStatic());
165
166 // Table counts were updated appropriately.
167 EXPECT_EQ(entry->Size(), table_.size());
168 EXPECT_EQ(1u, peer_.dynamic_entries_count());
169 EXPECT_EQ(peer_.dynamic_entries().size(), peer_.dynamic_entries_count());
170 EXPECT_EQ(static_count + 1, peer_.total_insertions());
171 EXPECT_EQ(static_count + 1, peer_.index_size());
172
173 // Index() of entries reflects the insertion.
174 EXPECT_EQ(1u, table_.IndexOf(first_static_entry));
175 // Static table has 61 entries.
176 EXPECT_EQ(62u, table_.IndexOf(entry));
177 EXPECT_EQ(first_static_entry, table_.GetByIndex(1));
178 EXPECT_EQ(entry, table_.GetByIndex(62));
179
180 // Evict |entry|. Table counts are again updated appropriately.
181 peer_.Evict(1);
182 EXPECT_EQ(0u, table_.size());
183 EXPECT_EQ(0u, peer_.dynamic_entries_count());
184 EXPECT_EQ(peer_.dynamic_entries().size(), peer_.dynamic_entries_count());
185 EXPECT_EQ(static_count + 1, peer_.total_insertions());
186 EXPECT_EQ(static_count, peer_.index_size());
187
188 // Index() of |first_static_entry| reflects the eviction.
189 EXPECT_EQ(1u, table_.IndexOf(first_static_entry));
190 EXPECT_EQ(first_static_entry, table_.GetByIndex(1));
191 }
192
193 TEST_F(HpackHeaderTableTest, EntryIndexing) {
194 const HpackEntry* first_static_entry = table_.GetByIndex(1);
195
196 // Static entries are queryable by name & value.
197 EXPECT_EQ(first_static_entry, table_.GetByName(first_static_entry->name()));
198 EXPECT_EQ(first_static_entry,
199 table_.GetByNameAndValue(first_static_entry->name(),
200 first_static_entry->value()));
201
202 // Create a mix of entries which duplicate names, and names & values of both
203 // dynamic and static entries.
204 const HpackEntry* entry1 = table_.TryAddEntry(first_static_entry->name(),
205 first_static_entry->value());
206 const HpackEntry* entry2 =
207 table_.TryAddEntry(first_static_entry->name(), "Value Four");
208 const HpackEntry* entry3 = table_.TryAddEntry("key-1", "Value One");
209 const HpackEntry* entry4 = table_.TryAddEntry("key-2", "Value Three");
210 const HpackEntry* entry5 = table_.TryAddEntry("key-1", "Value Two");
211 const HpackEntry* entry6 = table_.TryAddEntry("key-2", "Value Three");
212 const HpackEntry* entry7 = table_.TryAddEntry("key-2", "Value Four");
213
214 // Entries are queryable under their current index.
215 EXPECT_EQ(entry7, table_.GetByIndex(62));
216 EXPECT_EQ(entry6, table_.GetByIndex(63));
217 EXPECT_EQ(entry5, table_.GetByIndex(64));
218 EXPECT_EQ(entry4, table_.GetByIndex(65));
219 EXPECT_EQ(entry3, table_.GetByIndex(66));
220 EXPECT_EQ(entry2, table_.GetByIndex(67));
221 EXPECT_EQ(entry1, table_.GetByIndex(68));
222 EXPECT_EQ(first_static_entry, table_.GetByIndex(1));
223
224 // Querying by name returns the most recently added matching entry.
225 EXPECT_EQ(entry5, table_.GetByName("key-1"));
226 EXPECT_EQ(entry7, table_.GetByName("key-2"));
227 EXPECT_EQ(entry2->name(),
228 table_.GetByName(first_static_entry->name())->name());
229 EXPECT_EQ(NULL, table_.GetByName("not-present"));
230
231 // Querying by name & value returns the lowest-index matching entry among
232 // static entries, and the highest-index one among dynamic entries.
233 EXPECT_EQ(entry3, table_.GetByNameAndValue("key-1", "Value One"));
234 EXPECT_EQ(entry5, table_.GetByNameAndValue("key-1", "Value Two"));
235 EXPECT_EQ(entry6, table_.GetByNameAndValue("key-2", "Value Three"));
236 EXPECT_EQ(entry7, table_.GetByNameAndValue("key-2", "Value Four"));
237 EXPECT_EQ(first_static_entry,
238 table_.GetByNameAndValue(first_static_entry->name(),
239 first_static_entry->value()));
240 EXPECT_EQ(entry2,
241 table_.GetByNameAndValue(first_static_entry->name(), "Value Four"));
242 EXPECT_EQ(NULL, table_.GetByNameAndValue("key-1", "Not Present"));
243 EXPECT_EQ(NULL, table_.GetByNameAndValue("not-present", "Value One"));
244
245 // Evict |entry1|. Queries for its name & value now return the static entry.
246 // |entry2| remains queryable.
247 peer_.Evict(1);
248 EXPECT_EQ(first_static_entry,
249 table_.GetByNameAndValue(first_static_entry->name(),
250 first_static_entry->value()));
251 EXPECT_EQ(entry2,
252 table_.GetByNameAndValue(first_static_entry->name(), "Value Four"));
253
254 // Evict |entry2|. Queries by its name & value are not found.
255 peer_.Evict(1);
256 EXPECT_EQ(NULL,
257 table_.GetByNameAndValue(first_static_entry->name(), "Value Four"));
258 }
259
260 TEST_F(HpackHeaderTableTest, SetSizes) {
261 SpdyString key = "key", value = "value";
262 const HpackEntry* entry1 = table_.TryAddEntry(key, value);
263 const HpackEntry* entry2 = table_.TryAddEntry(key, value);
264 const HpackEntry* entry3 = table_.TryAddEntry(key, value);
265
266 // Set exactly large enough. No Evictions.
267 size_t max_size = entry1->Size() + entry2->Size() + entry3->Size();
268 table_.SetMaxSize(max_size);
269 EXPECT_EQ(3u, peer_.dynamic_entries().size());
270
271 // Set just too small. One eviction.
272 max_size = entry1->Size() + entry2->Size() + entry3->Size() - 1;
273 table_.SetMaxSize(max_size);
274 EXPECT_EQ(2u, peer_.dynamic_entries().size());
275
276 // Changing SETTINGS_HEADER_TABLE_SIZE.
277 EXPECT_EQ(kDefaultHeaderTableSizeSetting, table_.settings_size_bound());
278 // In production, the size passed to SetSettingsHeaderTableSize is never
279 // larger than table_.settings_size_bound().
280 table_.SetSettingsHeaderTableSize(kDefaultHeaderTableSizeSetting * 3 + 1);
281 EXPECT_EQ(kDefaultHeaderTableSizeSetting * 3 + 1, table_.max_size());
282
283 // SETTINGS_HEADER_TABLE_SIZE upper-bounds |table_.max_size()|,
284 // and will force evictions.
285 max_size = entry3->Size() - 1;
286 table_.SetSettingsHeaderTableSize(max_size);
287 EXPECT_EQ(max_size, table_.max_size());
288 EXPECT_EQ(max_size, table_.settings_size_bound());
289 EXPECT_EQ(0u, peer_.dynamic_entries().size());
290 }
291
292 TEST_F(HpackHeaderTableTest, EvictionCountForEntry) {
293 SpdyString key = "key", value = "value";
294 const HpackEntry* entry1 = table_.TryAddEntry(key, value);
295 const HpackEntry* entry2 = table_.TryAddEntry(key, value);
296 size_t entry3_size = HpackEntry::Size(key, value);
297
298 // Just enough capacity for third entry.
299 table_.SetMaxSize(entry1->Size() + entry2->Size() + entry3_size);
300 EXPECT_EQ(0u, peer_.EvictionCountForEntry(key, value));
301 EXPECT_EQ(1u, peer_.EvictionCountForEntry(key, value + "x"));
302
303 // No extra capacity. Third entry would force evictions.
304 table_.SetMaxSize(entry1->Size() + entry2->Size());
305 EXPECT_EQ(1u, peer_.EvictionCountForEntry(key, value));
306 EXPECT_EQ(2u, peer_.EvictionCountForEntry(key, value + "x"));
307 }
308
309 TEST_F(HpackHeaderTableTest, EvictionCountToReclaim) {
310 SpdyString key = "key", value = "value";
311 const HpackEntry* entry1 = table_.TryAddEntry(key, value);
312 const HpackEntry* entry2 = table_.TryAddEntry(key, value);
313
314 EXPECT_EQ(1u, peer_.EvictionCountToReclaim(1));
315 EXPECT_EQ(1u, peer_.EvictionCountToReclaim(entry1->Size()));
316 EXPECT_EQ(2u, peer_.EvictionCountToReclaim(entry1->Size() + 1));
317 EXPECT_EQ(2u, peer_.EvictionCountToReclaim(entry1->Size() + entry2->Size()));
318 }
319
320 // Fill a header table with entries. Make sure the entries are in
321 // reverse order in the header table.
322 TEST_F(HpackHeaderTableTest, TryAddEntryBasic) {
323 EXPECT_EQ(0u, table_.size());
324 EXPECT_EQ(table_.settings_size_bound(), table_.max_size());
325
326 HpackEntryVector entries = MakeEntriesOfTotalSize(table_.max_size());
327
328 // Most of the checks are in AddEntriesExpectNoEviction().
329 AddEntriesExpectNoEviction(entries);
330 EXPECT_EQ(table_.max_size(), table_.size());
331 EXPECT_EQ(table_.settings_size_bound(), table_.size());
332 }
333
334 // Fill a header table with entries, and then ramp the table's max
335 // size down to evict an entry one at a time. Make sure the eviction
336 // happens as expected.
337 TEST_F(HpackHeaderTableTest, SetMaxSize) {
338 HpackEntryVector entries =
339 MakeEntriesOfTotalSize(kDefaultHeaderTableSizeSetting / 2);
340 AddEntriesExpectNoEviction(entries);
341
342 for (HpackEntryVector::iterator it = entries.begin(); it != entries.end();
343 ++it) {
344 size_t expected_count = distance(it, entries.end());
345 EXPECT_EQ(expected_count, peer_.dynamic_entries().size());
346
347 table_.SetMaxSize(table_.size() + 1);
348 EXPECT_EQ(expected_count, peer_.dynamic_entries().size());
349
350 table_.SetMaxSize(table_.size());
351 EXPECT_EQ(expected_count, peer_.dynamic_entries().size());
352
353 --expected_count;
354 table_.SetMaxSize(table_.size() - 1);
355 EXPECT_EQ(expected_count, peer_.dynamic_entries().size());
356 }
357 EXPECT_EQ(0u, table_.size());
358 }
359
360 // Fill a header table with entries, and then add an entry just big
361 // enough to cause eviction of all but one entry. Make sure the
362 // eviction happens as expected and the long entry is inserted into
363 // the table.
364 TEST_F(HpackHeaderTableTest, TryAddEntryEviction) {
365 HpackEntryVector entries = MakeEntriesOfTotalSize(table_.max_size());
366 AddEntriesExpectNoEviction(entries);
367
368 const HpackEntry* survivor_entry = table_.GetByIndex(61 + 1);
369 HpackEntry long_entry =
370 MakeEntryOfSize(table_.max_size() - survivor_entry->Size());
371
372 // All dynamic entries but the first are to be evicted.
373 EXPECT_EQ(peer_.dynamic_entries().size() - 1,
374 peer_.EvictionSet(long_entry.name(), long_entry.value()).size());
375
376 const HpackEntry* new_entry =
377 table_.TryAddEntry(long_entry.name(), long_entry.value());
378 EXPECT_EQ(62u, table_.IndexOf(new_entry));
379 EXPECT_EQ(2u, peer_.dynamic_entries().size());
380 EXPECT_EQ(table_.GetByIndex(63), survivor_entry);
381 EXPECT_EQ(table_.GetByIndex(62), new_entry);
382 }
383
384 // Fill a header table with entries, and then add an entry bigger than
385 // the entire table. Make sure no entry remains in the table.
386 TEST_F(HpackHeaderTableTest, TryAddTooLargeEntry) {
387 HpackEntryVector entries = MakeEntriesOfTotalSize(table_.max_size());
388 AddEntriesExpectNoEviction(entries);
389
390 const HpackEntry long_entry = MakeEntryOfSize(table_.max_size() + 1);
391
392 // All entries are to be evicted.
393 EXPECT_EQ(peer_.dynamic_entries().size(),
394 peer_.EvictionSet(long_entry.name(), long_entry.value()).size());
395
396 const HpackEntry* new_entry =
397 table_.TryAddEntry(long_entry.name(), long_entry.value());
398 EXPECT_EQ(new_entry, static_cast<HpackEntry*>(NULL));
399 EXPECT_EQ(0u, peer_.dynamic_entries().size());
400 }
401
402 TEST_F(HpackHeaderTableTest, EntryNamesDiffer) {
403 HpackEntry entry1("header", "value");
404 HpackEntry entry2("HEADER", "value");
405
406 HpackHeaderTable::EntryHasher hasher;
407 EXPECT_NE(hasher(&entry1), hasher(&entry2));
408
409 HpackHeaderTable::EntriesEq eq;
410 EXPECT_FALSE(eq(&entry1, &entry2));
411 }
412
413 TEST_F(HpackHeaderTableTest, EntryValuesDiffer) {
414 HpackEntry entry1("header", "value");
415 HpackEntry entry2("header", "VALUE");
416
417 HpackHeaderTable::EntryHasher hasher;
418 EXPECT_NE(hasher(&entry1), hasher(&entry2));
419
420 HpackHeaderTable::EntriesEq eq;
421 EXPECT_FALSE(eq(&entry1, &entry2));
422 }
423
424 TEST_F(HpackHeaderTableTest, EntriesEqual) {
425 HpackEntry entry1(DynamicEntry("name", "value"));
426 HpackEntry entry2(DynamicEntry("name", "value"));
427
428 HpackHeaderTable::EntryHasher hasher;
429 EXPECT_EQ(hasher(&entry1), hasher(&entry2));
430
431 HpackHeaderTable::EntriesEq eq;
432 EXPECT_TRUE(eq(&entry1, &entry2));
433 }
434
435 TEST_F(HpackHeaderTableTest, StaticAndDynamicEntriesEqual) {
436 HpackEntry entry1("name", "value");
437 HpackEntry entry2(DynamicEntry("name", "value"));
438
439 HpackHeaderTable::EntryHasher hasher;
440 EXPECT_EQ(hasher(&entry1), hasher(&entry2));
441
442 HpackHeaderTable::EntriesEq eq;
443 EXPECT_TRUE(eq(&entry1, &entry2));
444 }
445
446 } // namespace
447
448 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/hpack/hpack_header_table.cc ('k') | net/spdy/hpack/hpack_huffman_decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698