Towards dump implementation. Add logging to dump.py. Use and clean up temp dir for dump tests
This commit is contained in:
parent
874f8ba891
commit
0ff75050f2
140
resync/dump.py
140
resync/dump.py
@ -1,8 +1,9 @@
|
||||
"""Dump handler for ResourceSync"""
|
||||
|
||||
import logging
|
||||
import os.path
|
||||
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
|
||||
from sitemap import Sitemap
|
||||
from resync.resource_dump_manifest import ResourceDumpManifest
|
||||
|
||||
class DumpError(Exception):
|
||||
pass
|
||||
@ -10,49 +11,79 @@ class DumpError(Exception):
|
||||
class Dump(object):
|
||||
"""Dump of content for a Resource Dump or Change Dump
|
||||
|
||||
The resource_list must be comprised of Resource objects
|
||||
The resources itearable must be comprised of Resource objects
|
||||
which have the path attributes set to indicate the local
|
||||
location of the copies of the resources.
|
||||
|
||||
rl = ResourceList()
|
||||
# ... add items by whatever means, may have >50k items and/or
|
||||
# >100MB total size of files ...
|
||||
d = Dump(rl)
|
||||
d.write(dumpfile="/tmp/rd")
|
||||
"""
|
||||
|
||||
def __init__(self, format=None, compress=True):
|
||||
def __init__(self, resources=None, format=None, compress=True):
|
||||
self.resources = resources
|
||||
self.format = ('zip' if (format is None) else format)
|
||||
self.compress = compress
|
||||
self.manifest_class = ResourceDumpManifest #FIXME
|
||||
self.max_size = 100*1024*1024 #100MB
|
||||
self.max_files = 50000
|
||||
self.path_prefix = None
|
||||
self.logger = logging.getLogger('dump')
|
||||
|
||||
def write(self, resource_list=None, dumpfile=None):
|
||||
"""Wrapper to Write a dump file"""
|
||||
self.check_files(resource_list)
|
||||
if (self.format == 'zip'):
|
||||
self.write_zip(resource_list,dumpfile)
|
||||
elif (self.format == 'warc'):
|
||||
self.write_warc(resource_list,dumpfile)
|
||||
else:
|
||||
raise DumpError("Unknown dump format '%s'" % (self.format))
|
||||
def write(self, basename=None, write_separate_manifests=True):
|
||||
"""Write one or more dump files to complete this dump
|
||||
|
||||
def write_zip(self, resource_list=None, dumpfile=None):
|
||||
"""Write a ZIP format dump file"""
|
||||
Returns the number of dump/archive files written.
|
||||
"""
|
||||
self.check_files()
|
||||
n=0
|
||||
for manifest in self.partition_dumps():
|
||||
dumpbase="%s%05d" % (basename,n)
|
||||
dumpfile="%s.%s" % (dumpbase,self.format)
|
||||
if (write_separate_manifests):
|
||||
manifest.write(basename=dumpbase+'.xml')
|
||||
if (self.format == 'zip'):
|
||||
self.write_zip(manifest.resources,dumpfile)
|
||||
elif (self.format == 'warc'):
|
||||
self.write_warc(manifest.resources,dumpfile)
|
||||
else:
|
||||
raise DumpError("Unknown dump format requested (%s)" % (self.format))
|
||||
n+=1
|
||||
self.logger.info("Wrote %d dump files" % (n))
|
||||
return(n)
|
||||
|
||||
def write_zip(self, resources=None, dumpfile=None):
|
||||
"""Write a ZIP format dump file
|
||||
|
||||
Writes a ZIP file containing the resources in the iterable resources along with
|
||||
a manifest file manifest.xml (written first). No checks on the size of files
|
||||
or total size are performed, this is expected to have been done beforehand.
|
||||
"""
|
||||
compression = ( ZIP_DEFLATED if self.compress else ZIP_STORED )
|
||||
zf = ZipFile(dumpfile, mode="w", compression=compression, allowZip64=True)
|
||||
# Write resource_list first
|
||||
s = Sitemap()
|
||||
# Write resources first
|
||||
rdm = ResourceDumpManifest(resources=resources)
|
||||
real_path = {}
|
||||
for resource in resource_list:
|
||||
for resource in resources:
|
||||
archive_path = self.archive_path(resource.path)
|
||||
real_path[archive_path] = resource.path
|
||||
resource.path = archive_path
|
||||
zf.writestr('manifest.xml',s.resources_as_xml(resource_list))
|
||||
# Add all files in the resource_list
|
||||
for resource in resource_list:
|
||||
zf.writestr('manifest.xml',rdm.as_xml())
|
||||
# Add all files in the resources
|
||||
for resource in resources:
|
||||
zf.write(real_path[resource.path], arcname=resource.path)
|
||||
zf.close()
|
||||
zipsize = os.path.getsize(dumpfile)
|
||||
print "Wrote ZIP file dump %s with size %d bytes" % (dumpfile,zipsize)
|
||||
self.logger.info("Wrote ZIP file dump %s with size %d bytes" % (dumpfile,zipsize))
|
||||
|
||||
def write_warc(self, resource_list=None, dumpfile=None):
|
||||
"""Write a WARC dump file"""
|
||||
def write_warc(self, resources=None, dumpfile=None):
|
||||
"""Write a WARC dump file
|
||||
|
||||
WARC support is not part of ResourceSync v1.0 (Z39.99 2014) but is left
|
||||
in this library for experimentation.
|
||||
"""
|
||||
# Load library late as we want to be able to run rest of code
|
||||
# without this installed
|
||||
try:
|
||||
@ -60,8 +91,8 @@ class Dump(object):
|
||||
except:
|
||||
raise DumpError("Failed to load WARC library")
|
||||
wf = WARCFile(dumpfile, mode="w", compress=self.compress)
|
||||
# Add all files in the resource_list
|
||||
for resource in resource_list:
|
||||
# Add all files in the resources
|
||||
for resource in resources:
|
||||
wh = WARCHeader({})
|
||||
wh.url = resource.uri
|
||||
wh.ip_address = None
|
||||
@ -73,19 +104,21 @@ class Dump(object):
|
||||
wf.write_record( WARCRecord( header=wh, payload=resource.path ) )
|
||||
wf.close()
|
||||
warcsize = os.path.getsize(dumpfile)
|
||||
print "Wrote WARC file dump %s with size %d bytes" % (dumpfile,warcsize)
|
||||
self.logging.info("Wrote WARC file dump %s with size %d bytes" % (dumpfile,warcsize))
|
||||
|
||||
def check_files(self,resource_list):
|
||||
"""Go though and check all files in resource_list, add up size, find common path
|
||||
def check_files(self,set_length=True,check_length=True):
|
||||
"""Go though and check all files in self.resources, add up size, and find
|
||||
longest common path that can be used when writing the dump file. Saved in
|
||||
self.path_prefix.
|
||||
|
||||
Will find the longest common path prefix that can be used when writing the
|
||||
dump file. Saved in self.path_prefix.
|
||||
Parameters set_length and check_length control control whether then set_length
|
||||
attribute should be set from the file size if not specified, and whether any
|
||||
length specified should be checked. By default both are True. In any event, the
|
||||
total size calculated is the size of files on disk.
|
||||
"""
|
||||
if (len(resource_list) > self.max_files):
|
||||
raise DumpError("Number of files to dump (%d) exceeds maximum (%d)" % (len(resource_list),self.max_files))
|
||||
total_size = 0 #total size of all files in bytes
|
||||
path_prefix = None
|
||||
for resource in resource_list:
|
||||
for resource in self.resources:
|
||||
if (resource.path is None):
|
||||
#explicit test because exception raised by getsize otherwise confusing
|
||||
raise DumpError("No file path defined for resource %s" % resource.uri)
|
||||
@ -93,12 +126,45 @@ class Dump(object):
|
||||
path_prefix = os.path.dirname(resource.path)
|
||||
else:
|
||||
path_prefix = os.path.commonprefix( [ path_prefix, os.path.dirname(resource.path) ])
|
||||
total_size += os.path.getsize(resource.path)
|
||||
size = os.path.getsize(resource.path)
|
||||
if (resource.length is not None):
|
||||
if (check_length and resource.length!=size):
|
||||
raise DumpError("Size of resource %s is %d on disk, not %d as specified" %
|
||||
(resource.uri, size, resource.length) )
|
||||
elif (set_length):
|
||||
resource.length = size
|
||||
if (size > self.max_size):
|
||||
raise DumpError("Size of file (%s, %d) exceeds maximum (%d) dump size" % (resource.path,size,self.max_size))
|
||||
total_size += size
|
||||
self.path_prefix = path_prefix
|
||||
self.total_size = total_size
|
||||
print "Total size of files to include in dump %d bytes" % (total_size)
|
||||
if (total_size > self.max_size):
|
||||
raise DumpError("Size of files to dump (%d) exceeds maximum (%d)" % (total_size,self.max_size))
|
||||
self.logger.info("Total size of files to include in dump %d bytes" % (total_size))
|
||||
return True
|
||||
|
||||
def partition_dumps(self):
|
||||
"""Yeild a set of manifest object that parition the dumps
|
||||
|
||||
Simply adds resources/files to a manifest until their are either the
|
||||
the correct number of files or the size limit is exceeded, then yields
|
||||
that manifest.
|
||||
"""
|
||||
manifest=self.manifest_class()
|
||||
manifest_size=0
|
||||
manifest_files=0
|
||||
for resource in self.resources:
|
||||
manifest.add(resource)
|
||||
manifest_size+=resource.length
|
||||
manifest_files+=1
|
||||
if (manifest_size>=self.max_size or
|
||||
manifest_files>=self.max_files):
|
||||
yield(manifest)
|
||||
# Need to start a new manifest
|
||||
manifest=self.manifest_class()
|
||||
manifest_size=0
|
||||
manifest_files=0
|
||||
if (manifest_files>0):
|
||||
yield(manifest)
|
||||
|
||||
|
||||
def archive_path(self,real_path):
|
||||
"""Return the archive path for file with real_path
|
||||
|
||||
@ -17,9 +17,19 @@ class ResourceDump(ResourceList):
|
||||
A Resource Dump comprises a set of content packages that are
|
||||
the resources listed. Properties similar to a ResourceList
|
||||
and implemented as a sub-class of ResourceList.
|
||||
|
||||
See the Dump class for details of how to create a Resource
|
||||
Dump from a ResourceList.
|
||||
"""
|
||||
|
||||
def __init__(self, resources=None, md=None, ln=None, uri=None, allow_multifile=None, mapper=None):
|
||||
super(ResourceDump, self).__init__(resources=resources, md=md, ln=ln, uri=uri,
|
||||
mapper=mapper)
|
||||
self.capability_name='resourcedump'
|
||||
|
||||
def write(self, basename="/tmp/resource_dump.xml", dumpfile=None):
|
||||
"""Write out a Resource Dump document and optionally also the actual dump files
|
||||
|
||||
Dump files will be written if the dumpfile argument is set to a base filename.
|
||||
"""
|
||||
super(ResourceDump,self).write(basename)
|
||||
|
||||
@ -1,19 +1,168 @@
|
||||
import os.path
|
||||
import unittest
|
||||
import tempfile
|
||||
import shutil
|
||||
import sys
|
||||
import zipfile
|
||||
from resync.dump import Dump, DumpError
|
||||
from resync.resource_list import ResourceList
|
||||
from resync.change_list import ChangeList
|
||||
from resync.resource import Resource
|
||||
from resync.resource_dump_manifest import ResourceDumpManifest
|
||||
from resync.change_dump_manifest import ChangeDumpManifest
|
||||
|
||||
class TestDump(unittest.TestCase):
|
||||
|
||||
def test00_dump_creation(self):
|
||||
i=ResourceList()
|
||||
i.add( Resource('http://ex.org/a', length=1, path='resync/test/testdata/a') )
|
||||
i.add( Resource('http://ex.org/b', length=2, path='resync/test/testdata/b') )
|
||||
_tmpdir=None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Create tmp dir to write to and check
|
||||
cls._tmpdir=tempfile.mkdtemp()
|
||||
if (not os.path.isdir(cls._tmpdir)):
|
||||
raise Exception("Failed to create tempdir to use for dump tests")
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# Cleanup
|
||||
if (not os.path.isdir(cls._tmpdir)):
|
||||
raise Exception("Ooops, no tempdir (%s) to clean up?" % (tmpdir))
|
||||
shutil.rmtree(cls._tmpdir)
|
||||
|
||||
@property
|
||||
def tmpdir(self):
|
||||
# read-only access to _tmpdir, just in case... The rmtree scares me
|
||||
return(self._tmpdir)
|
||||
|
||||
def test00_dump_zip_resource_list(self):
|
||||
rl=ResourceDumpManifest()
|
||||
rl.add( Resource('http://ex.org/a', length=7, path='resync/test/testdata/a') )
|
||||
rl.add( Resource('http://ex.org/b', length=21, path='resync/test/testdata/b') )
|
||||
d=Dump()
|
||||
d.check_files(resource_list=i)
|
||||
zipf=os.path.join(self.tmpdir,"test00_dump.zip")
|
||||
d.write_zip(resources=rl,dumpfile=zipf) # named args
|
||||
self.assertTrue( os.path.exists(zipf) )
|
||||
self.assertTrue( zipfile.is_zipfile(zipf) )
|
||||
zo=zipfile.ZipFile(zipf,'r')
|
||||
self.assertEqual( len(zo.namelist()), 3 )
|
||||
zo.close()
|
||||
os.unlink(zipf)
|
||||
|
||||
def test01_dump_zip_change_list(self):
|
||||
cl=ChangeDumpManifest()
|
||||
cl.add( Resource('http://ex.org/a', length=7, path='resync/test/testdata/a', change="updated") )
|
||||
cl.add( Resource('http://ex.org/b', length=21, path='resync/test/testdata/b', change="updated") )
|
||||
d=Dump()
|
||||
zipf=os.path.join(self.tmpdir,"test01_dump.zip")
|
||||
d.write_zip(cl,zipf) # positional args
|
||||
self.assertTrue( os.path.exists(zipf) )
|
||||
self.assertTrue( zipfile.is_zipfile(zipf) )
|
||||
zo=zipfile.ZipFile(zipf,'r')
|
||||
self.assertEqual( len(zo.namelist()), 3 )
|
||||
zo.close()
|
||||
os.unlink(zipf)
|
||||
|
||||
def test02_dump_check_files(self):
|
||||
cl=ChangeList()
|
||||
cl.add( Resource('http://ex.org/a', length=7, path='resync/test/testdata/a', change="updated") )
|
||||
cl.add( Resource('http://ex.org/b', length=21, path='resync/test/testdata/b', change="updated") )
|
||||
d=Dump(resources=cl)
|
||||
self.assertTrue(d.check_files())
|
||||
self.assertEqual(d.total_size, 28)
|
||||
|
||||
#FIXME -- need some code to actually write and read dump
|
||||
def test03_dump_multi_file_max_size(self):
|
||||
rl=ResourceList()
|
||||
for letter in map(chr,xrange(ord('a'),ord('l')+1)):
|
||||
uri='http://ex.org/%s' % (letter)
|
||||
fname='resync/test/testdata/a_to_z/%s' % (letter)
|
||||
rl.add( Resource(uri, path=fname) )
|
||||
self.assertEqual( len(rl), 12 )
|
||||
#d=Dump(rl)
|
||||
#tmpdir=tempfile.mkdtemp()
|
||||
#tmpbase=os.path.join(tmpdir,'base')
|
||||
#d.max_size=2000 # start new zip after size exceeds 2000 bytes
|
||||
#n=d.write(tmpbase)
|
||||
#self.assertEqual( n, 2, 'expect to write 2 dump files' )
|
||||
#
|
||||
# Now repeat with large size limit but small number of files limit
|
||||
d2=Dump(rl)
|
||||
tmpbase=os.path.join(self.tmpdir,'test03_')
|
||||
d2.max_files=4
|
||||
n=d2.write(tmpbase)
|
||||
self.assertEqual( n, 3, 'expect to write 3 dump files' )
|
||||
self.assertTrue( os.path.isfile(tmpbase+'00000.zip') )
|
||||
self.assertTrue( os.path.isfile(tmpbase+'00001.zip') )
|
||||
self.assertTrue( os.path.isfile(tmpbase+'00002.zip') )
|
||||
# Look at the first file in detail
|
||||
zipf=tmpbase+'00000.zip'
|
||||
zo=zipfile.ZipFile(zipf,'r')
|
||||
self.assertEqual( zo.namelist(), ['manifest.xml','a','b','c','d'] )
|
||||
#self.assertEqual( zo.getinfo('manifest.xml').file_size, 470 )
|
||||
self.assertEqual( zo.getinfo('a').file_size, 9 )
|
||||
self.assertEqual( zo.getinfo('b').file_size, 1116 )
|
||||
self.assertEqual( zo.getinfo('c').file_size, 32 )
|
||||
self.assertEqual( zo.getinfo('d').file_size, 13 )
|
||||
zo.close()
|
||||
os.unlink(zipf)
|
||||
# Check second and third files have expected contents
|
||||
zipf=tmpbase+'00001.zip'
|
||||
zo=zipfile.ZipFile(zipf,'r')
|
||||
self.assertEqual( zo.namelist(), ['manifest.xml','e','f','g','h'] )
|
||||
zo.close()
|
||||
os.unlink(zipf)
|
||||
zipf=tmpbase+'00002.zip'
|
||||
zo=zipfile.ZipFile(zipf,'r')
|
||||
self.assertEqual( zo.namelist(), ['manifest.xml','i','j','k','l'] )
|
||||
zo.close()
|
||||
os.unlink(zipf)
|
||||
|
||||
def test04_dump_multi_file_max_size(self):
|
||||
rl=ResourceList()
|
||||
for letter in map(chr,xrange(ord('a'),ord('l')+1)):
|
||||
uri='http://ex.org/%s' % (letter)
|
||||
fname='resync/test/testdata/a_to_z/%s' % (letter)
|
||||
rl.add( Resource(uri, path=fname) )
|
||||
self.assertEqual( len(rl), 12 )
|
||||
d2=Dump(rl)
|
||||
tmpbase=os.path.join(self.tmpdir,'test0f_')
|
||||
d2.max_size=2000
|
||||
n=d2.write(tmpbase)
|
||||
self.assertEqual( n, 2, 'expect to write 2 dump files' )
|
||||
self.assertTrue( os.path.isfile(tmpbase+'00000.zip') )
|
||||
self.assertTrue( os.path.isfile(tmpbase+'00001.zip') )
|
||||
# Look at the first file in detail
|
||||
zipf=tmpbase+'00000.zip'
|
||||
zo=zipfile.ZipFile(zipf,'r')
|
||||
self.assertEqual( zo.namelist(), ['manifest.xml','a','b','c','d','e','f'] )
|
||||
#self.assertEqual( zo.getinfo('manifest.xml').file_size, 470 )
|
||||
self.assertEqual( zo.getinfo('a').file_size, 9 )
|
||||
self.assertEqual( zo.getinfo('b').file_size, 1116 )
|
||||
self.assertEqual( zo.getinfo('c').file_size, 32 )
|
||||
self.assertEqual( zo.getinfo('d').file_size, 13 )
|
||||
self.assertEqual( zo.getinfo('e').file_size, 20 )
|
||||
self.assertEqual( zo.getinfo('f').file_size, 1625 )
|
||||
zo.close()
|
||||
os.unlink(zipf)
|
||||
# Check second and third files have expected contents
|
||||
zipf=tmpbase+'00001.zip'
|
||||
zo=zipfile.ZipFile(zipf,'r')
|
||||
self.assertEqual( zo.namelist(), ['manifest.xml','g','h','i','j','k','l'] )
|
||||
zo.close()
|
||||
os.unlink(zipf)
|
||||
|
||||
def test10_no_path(self):
|
||||
rl=ResourceList()
|
||||
rl.add( Resource('http://ex.org/a', length=7, path='resync/test/testdata/a') )
|
||||
rl.add( Resource('http://ex.org/b', length=21 ) )
|
||||
d=Dump(rl)
|
||||
self.assertRaises( DumpError, d.check_files )
|
||||
|
||||
def test11_bad_size(self):
|
||||
rl=ResourceList()
|
||||
rl.add( Resource('http://ex.org/a', length=9999, path='resync/test/testdata/a') )
|
||||
d=Dump(rl)
|
||||
self.assertTrue( d.check_files(check_length=False) )
|
||||
self.assertRaises( DumpError, d.check_files )
|
||||
|
||||
if __name__ == '__main__':
|
||||
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestDump)
|
||||
|
||||
1
resync/test/testdata/a_to_z/a
vendored
Normal file
1
resync/test/testdata/a_to_z/a
vendored
Normal file
@ -0,0 +1 @@
|
||||
aaaaaaaaa
|
||||
18
resync/test/testdata/a_to_z/b
vendored
Normal file
18
resync/test/testdata/a_to_z/b
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
1
resync/test/testdata/a_to_z/c
vendored
Normal file
1
resync/test/testdata/a_to_z/c
vendored
Normal file
@ -0,0 +1 @@
|
||||
ccccccccccccccccccccccccccccccc
|
||||
1
resync/test/testdata/a_to_z/d
vendored
Normal file
1
resync/test/testdata/a_to_z/d
vendored
Normal file
@ -0,0 +1 @@
|
||||
dddddddddddd
|
||||
1
resync/test/testdata/a_to_z/e
vendored
Normal file
1
resync/test/testdata/a_to_z/e
vendored
Normal file
@ -0,0 +1 @@
|
||||
eeeeeeeeeeeeeeeeeee
|
||||
25
resync/test/testdata/a_to_z/f
vendored
Normal file
25
resync/test/testdata/a_to_z/f
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
1
resync/test/testdata/a_to_z/g
vendored
Normal file
1
resync/test/testdata/a_to_z/g
vendored
Normal file
@ -0,0 +1 @@
|
||||
ggggggg
|
||||
1
resync/test/testdata/a_to_z/h
vendored
Normal file
1
resync/test/testdata/a_to_z/h
vendored
Normal file
@ -0,0 +1 @@
|
||||
hhhhhhhhhhhhhhhhhh
|
||||
1
resync/test/testdata/a_to_z/i
vendored
Normal file
1
resync/test/testdata/a_to_z/i
vendored
Normal file
@ -0,0 +1 @@
|
||||
iiii
|
||||
1
resync/test/testdata/a_to_z/j
vendored
Normal file
1
resync/test/testdata/a_to_z/j
vendored
Normal file
@ -0,0 +1 @@
|
||||
jjjjjjjj
|
||||
24
resync/test/testdata/a_to_z/k
vendored
Normal file
24
resync/test/testdata/a_to_z/k
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
1
resync/test/testdata/a_to_z/l
vendored
Normal file
1
resync/test/testdata/a_to_z/l
vendored
Normal file
@ -0,0 +1 @@
|
||||
lllll
|
||||
1
resync/test/testdata/a_to_z/m
vendored
Normal file
1
resync/test/testdata/a_to_z/m
vendored
Normal file
@ -0,0 +1 @@
|
||||
m
|
||||
Loading…
Reference in New Issue
Block a user