sapling/eden/fs/store/hg/test/HgPrefetchTest.cpp
Adam Simpkins 841b81c934 increase the timeouts in HgPrefetchTest
Summary:
This test seems to fail frequently while waiting on the tree data for the
"src" tree (at line 182).  The code previously was using a 1s timeout for this
operation; this changes it to use a 10s timeout.

I'm not sure what would have changed that makes this take longer now.  It's
possible something changed with the treemanifest code on the mercurial side.
It is somewhat surprising to me that this would regularly take more than 1s
though since this is only computing data locally about a pretty small test
repository.

Reviewed By: wez

Differential Revision: D9583645

fbshipit-source-id: 24695cc1b940540ec32461e2d80c30a3fd87a3e3
2018-08-30 13:07:49 -07:00

217 lines
6.6 KiB
C++

/*
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include <folly/FileUtil.h>
#include <folly/experimental/TestUtil.h>
#include <folly/logging/xlog.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "eden/fs/model/Tree.h"
#include "eden/fs/model/TreeEntry.h"
#include "eden/fs/store/MemoryLocalStore.h"
#include "eden/fs/store/hg/HgBackingStore.h"
#include "eden/fs/testharness/HgRepo.h"
#include "eden/fs/utils/PathFuncs.h"
#include "eden/fs/utils/UnboundedQueueExecutor.h"
using namespace facebook::eden;
using namespace std::chrono_literals;
using folly::StringPiece;
using folly::test::TemporaryDirectory;
using testing::HasSubstr;
TEST(HgPrefetch, test) {
MemoryLocalStore localStore;
TemporaryDirectory testDir("eden_hg_import_test");
AbsolutePath testPath{testDir.path().string()};
// Write a dummy ssh wrapper script
AbsolutePath dummySshPath = testPath + "dummyssh"_pc;
std::string dummySsh = R"(
#!/bin/bash
if [[ $# -ne 2 ]]; then
echo "unexpected number of ssh arguments: $@" >&2
exit 1
fi
if [[ $1 != "user@dummy" ]]; then
echo "unexpected ssh user argument: $@" >&2
exit 1
fi
if ! [[ $2 =~ "hg " ]]; then
echo "unexpected ssh command argument: $@" >&2
exit 1
fi
exec $2
)";
ASSERT_TRUE(folly::writeFile(
dummySsh,
dummySshPath.value().c_str(),
O_WRONLY | O_CREAT | O_TRUNC,
0755));
AbsolutePath systemHgrcPath = testPath + "hgrc"_pc;
auto baseHgrc = folly::sformat(
R"(
[ui]
ssh = {0}
[extensions]
fastmanifest =
treemanifest =
remotefilelog =
[remotefilelog]
pullprefetch =
bgprefetchrevs =
backgroundrepack = False
backgroundprefetch = False
reponame = eden_test_hg_prefetch
[fastmanifest]
usetree=True
cacheonchange=True
usecache=False
[treemanifest]
usecunionstore=True
)",
dummySshPath.value());
ASSERT_TRUE(folly::writeFile(baseHgrc, systemHgrcPath.value().c_str()));
// Create the server-side repository
HgRepo serverRepo{testPath + "server_repo"_pc};
serverRepo.hgInit({"--configfile", systemHgrcPath.value()});
serverRepo.appendToHgrc(baseHgrc);
serverRepo.appendToHgrc({
"[remotefilelog]",
"server = True",
"cachepath = " + (testPath + "server_hgcache"_pc).value(),
""
"[treemanifest]",
"server = True",
"",
});
// Create some test commits in the server repository
serverRepo.mkdir("foo");
StringPiece barData = "this is a test file\n";
serverRepo.writeFile("foo/bar.txt", barData);
StringPiece testData = "testing\n1234\ntesting\n";
serverRepo.writeFile("foo/test.txt", testData);
serverRepo.mkdir("src");
serverRepo.mkdir("src/eden");
StringPiece somelinkData = "this is the link contents";
serverRepo.symlink(somelinkData, "src/somelink"_relpath);
StringPiece mainData = "print('hello world\\n')\n";
serverRepo.writeFile("src/eden/main.py", mainData, 0755);
serverRepo.hg("add");
serverRepo.commit("Initial commit");
StringPiece mainData2 = "print('hello brave new world\\n')\n";
serverRepo.writeFile("src/eden/main.py", mainData2, 0755);
StringPiece abcData = "aaa\nbbb\nccc\n";
serverRepo.writeFile("src/eden/abc.py", abcData, 0644);
// Include a file with binary data in the file name.
// For good measure, use data that is not valid UTF-8
auto binaryFileName =
"a\xff"
"b\xfe"
"c\xfd.dat"_pc;
serverRepo.writeFile(
"src/eden/" + binaryFileName.value().str(), "data", 0755);
serverRepo.hg("add");
auto commit2 = serverRepo.commit("Commit 2");
serverRepo.writeFile("src/eden/main.py", "blah", 0755);
serverRepo.commit("Commit 3");
// Create the client-side repository
HgRepo clientRepo{testPath + "client_repo"_pc};
clientRepo.cloneFrom(
folly::to<std::string>("ssh://user@dummy/", serverRepo.path()),
{"--shallow",
"--configfile",
systemHgrcPath.value(),
"--config",
"remotefilelog.cachepath=" + (testPath + "client_hgcache"_pc).value()});
clientRepo.appendToHgrc(baseHgrc);
clientRepo.appendToHgrc({
"[remotefilelog]",
"cachepath = " + (testPath + "client_hgcache"_pc).value(),
"",
});
// Running "hg cat" with no server repo should fail before we run prefetch
auto catProcess = clientRepo.invokeHg(
{"--config",
"paths.default=",
"--config",
"ui.ssh=/bin/false",
"cat",
"-r",
commit2.toString(),
"src/eden/main.py"},
folly::Subprocess::Options()
.chdir(clientRepo.path().value())
.pipeStdout()
.pipeStderr());
auto catOutputs{catProcess.communicate()};
auto returnCode = catProcess.wait();
EXPECT_EQ(folly::ProcessReturnCode::EXITED, returnCode.state());
EXPECT_NE(0, returnCode.exitStatus());
EXPECT_THAT(
catOutputs.second, HasSubstr("no remotefilelog server configured"));
// Build an HgBackingStore for this repository
UnboundedQueueExecutor resultThreadPool(1, "ResultThread");
HgBackingStore store(clientRepo.path(), &localStore, &resultThreadPool);
// Now test running prefetch
// Build a list of file blob IDs to prefetch.
auto rootTree = store.getTreeForCommit(commit2).get(10s);
auto srcTree =
store.getTree(rootTree->getEntryAt("src"_pc).getHash()).get(10s);
auto edenTree =
store.getTree(srcTree->getEntryAt("eden"_pc).getHash()).get(10s);
auto fooTree =
store.getTree(rootTree->getEntryAt("foo"_pc).getHash()).get(10s);
std::vector<Hash> blobHashes;
blobHashes.push_back(edenTree->getEntryAt("main.py"_pc).getHash());
blobHashes.push_back(edenTree->getEntryAt("abc.py"_pc).getHash());
blobHashes.push_back(edenTree->getEntryAt("abc.py"_pc).getHash());
blobHashes.push_back(edenTree->getEntryAt(binaryFileName).getHash());
blobHashes.push_back(srcTree->getEntryAt("somelink"_pc).getHash());
blobHashes.push_back(fooTree->getEntryAt("bar.txt"_pc).getHash());
blobHashes.push_back(fooTree->getEntryAt("test.txt"_pc).getHash());
// Call prefetchBlobs()
store.prefetchBlobs(blobHashes).get(10s);
// Running "hg cat" with ssh disabled and no server repo should succeed now
// that we have prefetched the data.
//
// The treemanifest extension code currently seems to always connect to the
// server even if it doesn't need to download any data. Setting paths.default
// to the empty string works around this behavior.
clientRepo.hg(
"--config",
"paths.default=",
"--config",
"ui.ssh=/bin/false",
"--traceback",
"cat",
"-r",
commit2.toString(),
"src/eden/main.py");
}