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.
5 #include "net/spdy/hpack_header_table.h"
12 #include "base/basictypes.h"
13 #include "base/macros.h"
14 #include "net/spdy/hpack_entry.h"
15 #include "testing/gtest/include/gtest/gtest.h"
23 typedef std::vector
<HpackEntry
> HpackEntryVector
;
25 // Returns an entry whose Size() is equal to the given one.
26 HpackEntry
MakeEntryOfSize(uint32 size
) {
27 EXPECT_GE(size
, HpackEntry::kSizeOverhead
);
28 string
name((size
- HpackEntry::kSizeOverhead
) / 2, 'n');
29 string
value(size
- HpackEntry::kSizeOverhead
- name
.size(), 'v');
30 HpackEntry
entry(name
, value
);
31 EXPECT_EQ(size
, entry
.Size());
35 // Returns a vector of entries whose total size is equal to the given
37 HpackEntryVector
MakeEntriesOfTotalSize(uint32 total_size
) {
38 EXPECT_GE(total_size
, HpackEntry::kSizeOverhead
);
39 uint32 entry_size
= HpackEntry::kSizeOverhead
;
40 uint32 remaining_size
= total_size
;
41 HpackEntryVector entries
;
42 while (remaining_size
> 0) {
43 EXPECT_LE(entry_size
, remaining_size
);
44 entries
.push_back(MakeEntryOfSize(entry_size
));
45 remaining_size
-= entry_size
;
46 entry_size
= std::min(remaining_size
, entry_size
+ 32);
51 // Adds the given vector of entries to the given header table,
52 // expecting no eviction to happen.
53 void AddEntriesExpectNoEviction(const HpackEntryVector
& entries
,
54 HpackHeaderTable
* header_table
) {
55 unsigned start_entry_count
= header_table
->GetEntryCount();
56 for (HpackEntryVector::const_iterator it
= entries
.begin();
57 it
!= entries
.end(); ++it
) {
59 std::vector
<uint32
> removed_referenced_indices
;
60 header_table
->TryAddEntry(*it
, &index
, &removed_referenced_indices
);
62 EXPECT_TRUE(removed_referenced_indices
.empty());
63 EXPECT_EQ(start_entry_count
+ (it
- entries
.begin()) + 1u,
64 header_table
->GetEntryCount());
67 for (HpackEntryVector::const_iterator it
= entries
.begin();
68 it
!= entries
.end(); ++it
) {
69 uint32 index
= header_table
->GetEntryCount() - (it
- entries
.begin());
70 HpackEntry entry
= header_table
->GetEntry(index
);
71 EXPECT_TRUE(it
->Equals(entry
))
72 << "it = " << it
->GetDebugString() << " != entry = "
73 << entry
.GetDebugString();
77 // Returns the set of all indices in header_table that are in that
78 // table's reference set.
79 std::set
<uint32
> GetReferenceSet(const HpackHeaderTable
& header_table
) {
80 std::set
<uint32
> reference_set
;
81 for (uint32 i
= 1; i
<= header_table
.GetEntryCount(); ++i
) {
82 if (header_table
.GetEntry(i
).IsReferenced()) {
83 reference_set
.insert(i
);
89 // Fill a header table with entries. Make sure the entries are in
90 // reverse order in the header table.
91 TEST(HpackHeaderTableTest
, TryAddEntryBasic
) {
92 HpackHeaderTable header_table
;
93 EXPECT_EQ(0u, header_table
.size());
95 HpackEntryVector entries
= MakeEntriesOfTotalSize(header_table
.max_size());
97 // Most of the checks are in AddEntriesExpectNoEviction().
98 AddEntriesExpectNoEviction(entries
, &header_table
);
99 EXPECT_EQ(header_table
.max_size(), header_table
.size());
102 // Fill a header table with entries, and then ramp the table's max
103 // size down to evict an entry one at a time. Make sure the eviction
104 // happens as expected.
105 TEST(HpackHeaderTableTest
, SetMaxSize
) {
106 HpackHeaderTable header_table
;
108 HpackEntryVector entries
= MakeEntriesOfTotalSize(header_table
.max_size());
109 AddEntriesExpectNoEviction(entries
, &header_table
);
111 for (HpackEntryVector::const_iterator it
= entries
.begin();
112 it
!= entries
.end(); ++it
) {
113 uint32 expected_count
= entries
.end() - it
;
114 EXPECT_EQ(expected_count
, header_table
.GetEntryCount());
116 header_table
.SetMaxSize(header_table
.size() + 1);
117 EXPECT_EQ(expected_count
, header_table
.GetEntryCount());
119 header_table
.SetMaxSize(header_table
.size());
120 EXPECT_EQ(expected_count
, header_table
.GetEntryCount());
123 header_table
.SetMaxSize(header_table
.size() - 1);
124 EXPECT_EQ(expected_count
, header_table
.GetEntryCount());
127 EXPECT_EQ(0u, header_table
.size());
130 // Setting the max size of a header table to zero should clear its
132 TEST(HpackHeaderTableTest
, SetMaxSizeZeroClearsReferenceSet
) {
133 HpackHeaderTable header_table
;
135 HpackEntryVector entries
= MakeEntriesOfTotalSize(header_table
.max_size());
136 AddEntriesExpectNoEviction(entries
, &header_table
);
138 std::set
<uint32
> expected_reference_set
;
139 for (uint32 i
= 1; i
<= header_table
.GetEntryCount(); ++i
) {
140 header_table
.GetMutableEntry(i
)->SetReferenced(true);
141 expected_reference_set
.insert(i
);
143 EXPECT_EQ(expected_reference_set
, GetReferenceSet(header_table
));
145 header_table
.SetMaxSize(0);
146 EXPECT_TRUE(GetReferenceSet(header_table
).empty());
149 // Fill a header table with entries, and then add an entry just big
150 // enough to cause eviction of all but one entry. Make sure the
151 // eviction happens as expected and the long entry is inserted into
153 TEST(HpackHeaderTableTest
, TryAddEntryEviction
) {
154 HpackHeaderTable header_table
;
156 HpackEntryVector entries
= MakeEntriesOfTotalSize(header_table
.max_size());
157 AddEntriesExpectNoEviction(entries
, &header_table
);
159 EXPECT_EQ(entries
.size(), header_table
.GetEntryCount());
160 HpackEntry first_entry
= header_table
.GetEntry(1);
161 HpackEntry long_entry
=
162 MakeEntryOfSize(header_table
.size() - first_entry
.Size());
164 header_table
.SetMaxSize(header_table
.size());
165 EXPECT_EQ(entries
.size(), header_table
.GetEntryCount());
167 std::set
<uint32
> expected_reference_set
;
168 for (uint32 i
= 2; i
<= header_table
.GetEntryCount(); ++i
) {
169 header_table
.GetMutableEntry(i
)->SetReferenced(true);
170 expected_reference_set
.insert(i
);
172 EXPECT_EQ(expected_reference_set
, GetReferenceSet(header_table
));
175 std::vector
<uint32
> removed_referenced_indices
;
176 header_table
.TryAddEntry(long_entry
, &index
, &removed_referenced_indices
);
178 EXPECT_EQ(1u, index
);
179 EXPECT_EQ(expected_reference_set
,
180 std::set
<uint32
>(removed_referenced_indices
.begin(),
181 removed_referenced_indices
.end()));
182 EXPECT_TRUE(GetReferenceSet(header_table
).empty());
183 EXPECT_EQ(2u, header_table
.GetEntryCount());
184 EXPECT_TRUE(header_table
.GetEntry(1).Equals(long_entry
));
185 EXPECT_TRUE(header_table
.GetEntry(2).Equals(first_entry
));
188 // Fill a header table with entries, and then add an entry bigger than
189 // the entire table. Make sure no entry remains in the table.
190 TEST(HpackHeaderTableTest
, TryAddTooLargeEntry
) {
191 HpackHeaderTable header_table
;
193 HpackEntryVector entries
= MakeEntriesOfTotalSize(header_table
.max_size());
194 AddEntriesExpectNoEviction(entries
, &header_table
);
196 header_table
.SetMaxSize(header_table
.size());
197 EXPECT_EQ(entries
.size(), header_table
.GetEntryCount());
199 std::set
<uint32
> expected_removed_referenced_indices
;
200 for (uint32 i
= 1; i
<= header_table
.GetEntryCount(); ++i
) {
201 header_table
.GetMutableEntry(i
)->SetReferenced(true);
202 expected_removed_referenced_indices
.insert(i
);
205 HpackEntry long_entry
= MakeEntryOfSize(header_table
.size() + 1);
207 std::vector
<uint32
> removed_referenced_indices
;
208 header_table
.TryAddEntry(long_entry
, &index
, &removed_referenced_indices
);
210 EXPECT_EQ(0u, index
);
211 EXPECT_EQ(expected_removed_referenced_indices
,
212 std::set
<uint32
>(removed_referenced_indices
.begin(),
213 removed_referenced_indices
.end()));
214 EXPECT_EQ(0u, header_table
.GetEntryCount());