Skip to content

Commit 504d207

Browse files
committed
tests for the fountain_sink fixes
+ a change -- the `(size%_chunkSize) > 0` clause is (practically speaking) a superset of the `size < FountainMetadata::md_size` check, so we'll treat them as the same thing. We could probably remove the latter, but it's not doing more harm and is technically more correct.
1 parent a863f1e commit 504d207

3 files changed

Lines changed: 106 additions & 6 deletions

File tree

src/lib/fountain/fountain_decoder_sink.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,16 @@ class fountain_decoder_sink
132132

133133
int64_t decode_frame(const char* data, unsigned size)
134134
{
135-
if ((size%_chunkSize) > 0)
135+
// 2nd clause is implicitly true iff 1st is... but leave it for clarity
136+
if ((size%_chunkSize) > 0 or size < FountainMetadata::md_size)
136137
return -10;
137138

138-
if (size < FountainMetadata::md_size)
139-
return -11;
140-
141139
FountainMetadata md(data, size);
142140
if (!md.file_size())
143141
{
144142
/*std::cout << fmt::format("decode frame {} ... {},{},{},{}",
145143
md.file_size(), (unsigned)data[0], (unsigned)data[1], (unsigned)data[2], (unsigned)data[3]) << std::endl;*/
146-
return -12;
144+
return -11;
147145
}
148146

149147
// check if already done
@@ -154,7 +152,7 @@ class fountain_decoder_sink
154152
auto p = _streams.try_emplace(stream_slot(md), md.file_size(), _chunkSize);
155153
fountain_decoder_stream& s = p.first->second;
156154
if (s.data_size() != md.file_size())
157-
return -13;
155+
return -12;
158156

159157
bool finished = s.write(data, size);
160158
if (!finished)

src/lib/fountain/test/fountain_sinkTest.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,62 @@ TEST_CASE( "FountainSinkTest/testSameFrameManyTimes", "[unit]" )
139139
assertEquals( "0.333333", turbo::str::join(sink.get_progress()) ); // 33% done
140140
assertEquals( "", turbo::str::join(sink.get_done()) );
141141
}
142+
143+
TEST_CASE( "FountainSinkTest/testRejection", "[unit]" )
144+
{
145+
MakeTempDirectory tempdir;
146+
fountain_decoder_sink sink(625, write_on_store<std::ofstream>(tempdir.path()));
147+
148+
stringstream input1 = dummyContents(2000);
149+
fountain_encoder_stream::ptr fes1 = fountain_encoder_stream::create(input1, 625, 1);
150+
151+
// a non-rejection, first
152+
{
153+
std::array<char, 625> buff;
154+
unsigned res = fes1->readsome(buff.data(), buff.size());
155+
assertEquals( res, buff.size() );
156+
157+
// incomplete
158+
assertEquals( 0, sink.decode_frame(buff.data(), buff.size()) );
159+
}
160+
161+
// bad buffer sizes
162+
{
163+
std::array<char, 625> buff;
164+
unsigned res = fes1->readsome(buff.data(), buff.size());
165+
assertEquals( res, buff.size() );
166+
167+
// smaller than fountain header
168+
assertEquals( -10, sink.decode_frame(buff.data(), 5) );
169+
170+
// not the right chunk size
171+
assertEquals( -10, sink.decode_frame(buff.data(), 620) );
172+
}
173+
174+
// bad FountainMetadata
175+
{
176+
std::array<char, 625> buff;
177+
unsigned res = fes1->readsome(buff.data(), buff.size());
178+
assertEquals( res, buff.size() );
179+
180+
// extract and clobber
181+
FountainMetadata md(buff.data(), FountainMetadata::md_size);
182+
md = FountainMetadata(md.encode_id(), 0, md.block_id());
183+
std::memcpy(buff.data(), md.data(), FountainMetadata::md_size);
184+
185+
assertEquals( -11, sink.decode_frame(buff.data(), buff.size()) );
186+
}
187+
188+
// different size, same encode_id
189+
{
190+
stringstream input2 = dummyContents(1000);
191+
fountain_encoder_stream::ptr fes2 = fountain_encoder_stream::create(input2, 625, 1);
192+
193+
std::array<char, 625> buff;
194+
unsigned res = fes2->readsome(buff.data(), buff.size());
195+
assertEquals( res, buff.size() );
196+
197+
// slot taken
198+
assertEquals( -12, sink.decode_frame(buff.data(), buff.size()) );
199+
}
200+
}

src/lib/fountain/test/fountain_streamTest.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,49 @@ TEST_CASE( "FountainStreamTest/testDecode_BigPackets", "[unit]" )
268268
assertEquals( 14, fes->block_count() );
269269
assertEquals( 13, fes->blocks_required() );
270270
assertTrue( fes->good() );
271+
}
272+
273+
TEST_CASE( "FountainStreamTest/testDecode_RejectSizeMismatch", "[unit]" )
274+
{
275+
stringstream input;
276+
for (int i = 0; i < 100; ++i)
277+
input << "0123456789";
278+
279+
fountain_encoder_stream::ptr fes = fountain_encoder_stream::create(input, 625);
271280

281+
assertEquals( 0, fes->block_count() );
282+
assertEquals( 2, fes->blocks_required() );
283+
assertTrue( fes->good() );
284+
285+
fountain_decoder_stream fdsgood(input.str().size(), 625);
286+
fountain_decoder_stream fdsbad(input.str().size() + 7, 625); // size mismatch
287+
288+
std::array<char, 625> buff; // one block per read/write
289+
for (int i = 0; i < 100; ++i)
290+
{
291+
unsigned res = fes->readsome(buff.data(), buff.size());
292+
assertEquals( res, buff.size() );
293+
294+
assertFalse( fdsbad.write(buff.data(), buff.size()) ); // always reject on decode()
295+
296+
if (i < 2)
297+
{
298+
bool isdone = fdsgood.write(buff.data(), buff.size());
299+
assertEquals( (i == 1), isdone );
300+
}
301+
}
302+
303+
assertEquals( 619, fdsgood.block_size() );
304+
assertEquals( 1000, fdsgood.data_size() );
305+
assertTrue( fdsgood.good() );
306+
307+
assertEquals( 619, fdsbad.block_size() );
308+
assertEquals( 1007, fdsbad.data_size() );
309+
assertTrue( fdsbad.good() );
310+
311+
assertEquals( 101, fes->block_count() );
312+
assertEquals( 2, fes->blocks_required() );
313+
assertTrue( fes->good() );
272314
}
273315

316+

0 commit comments

Comments
 (0)