Tests for ManifestDumpCommand and ListColumnFamiliesCommand

Summary:
Added tests for two LDBCommands namely i) ManifestDumpCommand and ii) ListColumnFamiliesCommand.
+ Minor fix in the sscanf formatter (along relace C cast with C++ cast) + replacing localtime with localtime_r which is thread safe.

Test Plan: make all && ./tools/ldb_test.py

Reviewers: anthony, igor, IslamAbdelRahman, kradhakrishnan, lgalanis, rven, sdong

Reviewed By: sdong

Subscribers: leveldb, dhruba

Differential Revision: https://reviews.facebook.net/D45819
This commit is contained in:
Amit Arya 2015-09-08 14:23:42 -07:00
parent 778cf4449b
commit 7a31960ee9
2 changed files with 66 additions and 10 deletions

View file

@ -1,10 +1,12 @@
import os import os
import glob
import os.path import os.path
import shutil import shutil
import subprocess import subprocess
import time import time
import unittest import unittest
import tempfile import tempfile
import re
def my_check_output(*popenargs, **kwargs): def my_check_output(*popenargs, **kwargs):
""" """
@ -43,7 +45,8 @@ class LDBTestCase(unittest.TestCase):
def dbParam(self, dbName): def dbParam(self, dbName):
return "--db=%s" % os.path.join(self.TMP_DIR, dbName) return "--db=%s" % os.path.join(self.TMP_DIR, dbName)
def assertRunOKFull(self, params, expectedOutput, unexpected=False): def assertRunOKFull(self, params, expectedOutput, unexpected=False,
isPattern=False):
""" """
All command-line params must be specified. All command-line params must be specified.
Allows full flexibility in testing; for example: missing db param. Allows full flexibility in testing; for example: missing db param.
@ -53,9 +56,16 @@ class LDBTestCase(unittest.TestCase):
output = my_check_output("./ldb %s |grep -v \"Created bg thread\"" % output = my_check_output("./ldb %s |grep -v \"Created bg thread\"" %
params, shell=True) params, shell=True)
if not unexpected: if not unexpected:
self.assertEqual(output.strip(), expectedOutput.strip()) if isPattern:
self.assertNotEqual(expectedOutput.search(output.strip()),
None)
else:
self.assertEqual(output.strip(), expectedOutput.strip())
else: else:
self.assertNotEqual(output.strip(), expectedOutput.strip()) if isPattern:
self.assertEqual(expectedOutput.search(output.strip()), None)
else:
self.assertNotEqual(output.strip(), expectedOutput.strip())
def assertRunFAILFull(self, params): def assertRunFAILFull(self, params):
""" """
@ -395,5 +405,52 @@ class LDBTestCase(unittest.TestCase):
dumpFilePath = os.path.join(self.TMP_DIR, "dump2") dumpFilePath = os.path.join(self.TMP_DIR, "dump2")
self.assertTrue(self.dumpLiveFiles("--db=%s" % dbPath, dumpFilePath)) self.assertTrue(self.dumpLiveFiles("--db=%s" % dbPath, dumpFilePath))
def getManifests(self, directory):
return glob.glob(directory + "/MANIFEST-*")
def copyManifests(self, src, dest):
return 0 == run_err_null("cp " + src + " " + dest)
def testManifestDump(self):
print "Running testManifestDump..."
dbPath = os.path.join(self.TMP_DIR, self.DB_NAME)
self.assertRunOK("put 1 1 --create_if_missing", "OK")
self.assertRunOK("put 2 2", "OK")
self.assertRunOK("put 3 3", "OK")
# Pattern to expect from manifest_dump.
num = "[0-9]+"
st = ".*"
subpat = st + " @ " + num + ": " + num
regex = num + ":" + num + "\[" + subpat + ".." + subpat + "\]"
expected_pattern = re.compile(regex)
cmd = "manifest_dump --db=%s"
manifest_files = self.getManifests(dbPath)
self.assertTrue(len(manifest_files) == 1)
# Test with the default manifest file in dbPath.
self.assertRunOKFull(cmd % dbPath, expected_pattern,
unexpected=False, isPattern=True)
self.copyManifests(manifest_files[0], manifest_files[0] + "1")
manifest_files = self.getManifests(dbPath)
self.assertTrue(len(manifest_files) == 2)
# Test with multiple manifest files in dbPath.
self.assertRunFAILFull(cmd % dbPath)
# Running it with the copy we just created should pass.
self.assertRunOKFull((cmd + " --path=%s")
% (dbPath, manifest_files[1]),
expected_pattern, unexpected=False,
isPattern=True)
def testListColumnFamilies(self):
print "Running testListColumnFamilies..."
dbPath = os.path.join(self.TMP_DIR, self.DB_NAME)
self.assertRunOK("put x1 y1 --create_if_missing", "OK")
cmd = "list_column_families %s | grep -v \"Column families\""
# Test on valid dbPath.
self.assertRunOKFull(cmd % dbPath, "{default}")
# Test on empty path.
self.assertRunFAILFull(cmd % "")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -608,12 +608,9 @@ void ManifestDumpCommand::DoCommand() {
struct dirent* entry; struct dirent* entry;
while ((entry = readdir(d.get())) != nullptr) { while ((entry = readdir(d.get())) != nullptr) {
unsigned int match; unsigned int match;
unsigned long long num; uint64_t num;
if (sscanf(entry->d_name, if (sscanf(entry->d_name, "MANIFEST-%lu%n", &num, &match) &&
"MANIFEST-%ln%ln", match == strlen(entry->d_name)) {
(unsigned long*)&num,
(unsigned long*)&match)
&& match == strlen(entry->d_name)) {
if (!found) { if (!found) {
manifestfile = db_path_ + "/" + std::string(entry->d_name); manifestfile = db_path_ + "/" + std::string(entry->d_name);
found = true; found = true;
@ -686,7 +683,9 @@ namespace {
string ReadableTime(int unixtime) { string ReadableTime(int unixtime) {
char time_buffer [80]; char time_buffer [80];
time_t rawtime = unixtime; time_t rawtime = unixtime;
struct tm * timeinfo = localtime(&rawtime); struct tm tInfo;
struct tm* timeinfo = localtime_r(&rawtime, &tInfo);
assert(timeinfo == &tInfo);
strftime(time_buffer, 80, "%c", timeinfo); strftime(time_buffer, 80, "%c", timeinfo);
return string(time_buffer); return string(time_buffer);
} }