libutil: fix copyNAR not reading the whole nar when dropped early
if a copyNAR generator was not drained to completion it would not read the full nar data from its source. this could happen if the copier was passed to parseAndDump wrapped as a source because copyNAR would yield nar metadata *before* it had read it, and GeneratorSource will drain a generator fully *only* if the source is allowed to throw EndOfFile. in the parseAndDump case this never happened because parseAndDump expects to be given an unterminated stream, and thus the combination left some nar metadata in the input Source, breaking the remote store protocols. fixes #732 Change-Id: Ia59a53375992bfcdb7bc6b37764ca779622bc8f7
This commit is contained in:
@@ -243,8 +243,7 @@ TEST_P(NarTest, parse)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(NarTest, parseAsync)
|
||||
{
|
||||
namespace parseAsync {
|
||||
struct File
|
||||
{
|
||||
bool executable;
|
||||
@@ -316,10 +315,15 @@ TEST_P(NarTest, parseAsync)
|
||||
parent.emplace(name, Symlink{target});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_P(NarTest, parseAsync)
|
||||
{
|
||||
using namespace parseAsync;
|
||||
|
||||
AsyncGeneratorInputStream source(rawStream());
|
||||
|
||||
std::map<std::string, Entry> contents;
|
||||
std::map<std::string, parseAsync::Entry> contents;
|
||||
ReconstructVisitor rv{contents};
|
||||
|
||||
kj::EventLoop el;
|
||||
@@ -327,7 +331,7 @@ TEST_P(NarTest, parseAsync)
|
||||
|
||||
auto entries = entriesFn()();
|
||||
parseDump(rv, source).wait(ws).value();
|
||||
auto parsed = Directory::toNar(contents.at(""));
|
||||
auto parsed = parseAsync::Directory::toNar(contents.at(""));
|
||||
while (true) {
|
||||
auto e = entries.next();
|
||||
auto p = parsed.next();
|
||||
@@ -357,6 +361,57 @@ TEST_P(NarTest, copyAsync)
|
||||
ASSERT_EQ(raw(), copied);
|
||||
}
|
||||
|
||||
TEST_P(NarTest, parseCopied)
|
||||
{
|
||||
GeneratorSource input(rawStream());
|
||||
GeneratorSource source(copyNAR(input));
|
||||
|
||||
auto entries = entriesFn()();
|
||||
auto parsed = parse(source);
|
||||
while (true) {
|
||||
auto e = entries.next();
|
||||
auto p = parsed.next();
|
||||
ASSERT_EQ(e.has_value(), p.has_value());
|
||||
if (!e) {
|
||||
break;
|
||||
}
|
||||
assert_eq(*e, *p);
|
||||
}
|
||||
|
||||
char buf;
|
||||
ASSERT_THROW(input(&buf, 1), EndOfFile);
|
||||
}
|
||||
|
||||
TEST_P(NarTest, parseCopiedAsync)
|
||||
{
|
||||
using namespace parseAsync;
|
||||
|
||||
AsyncGeneratorInputStream input(rawStream());
|
||||
auto source = copyNAR(input);
|
||||
|
||||
std::map<std::string, parseAsync::Entry> contents;
|
||||
ReconstructVisitor rv{contents};
|
||||
|
||||
kj::EventLoop el;
|
||||
kj::WaitScope ws{el};
|
||||
|
||||
auto entries = entriesFn()();
|
||||
parseDump(rv, *source).wait(ws).value();
|
||||
auto parsed = parseAsync::Directory::toNar(contents.at(""));
|
||||
while (true) {
|
||||
auto e = entries.next();
|
||||
auto p = parsed.next();
|
||||
ASSERT_EQ(e.has_value(), p.has_value());
|
||||
if (!e) {
|
||||
break;
|
||||
}
|
||||
assert_eq(*e, *p);
|
||||
}
|
||||
|
||||
char buf;
|
||||
ASSERT_EQ(input.read(&buf, 1).wait(ws).value(), 0);
|
||||
}
|
||||
|
||||
TEST_P(NarTest, index)
|
||||
{
|
||||
GeneratorSource source(rawStream());
|
||||
|
||||
Reference in New Issue
Block a user