1#!/usr/bin/env python
2#
3# Public Domain 2014-2018 MongoDB, Inc.
4# Public Domain 2008-2014 WiredTiger, Inc.
5#
6# This is free and unencumbered software released into the public domain.
7#
8# Anyone is free to copy, modify, publish, use, compile, sell, or
9# distribute this software, either in source code form or as a compiled
10# binary, for any purpose, commercial or non-commercial, and by any
11# means.
12#
13# In jurisdictions that recognize copyright laws, the author or authors
14# of this software dedicate any and all copyright interest in the
15# software to the public domain. We make this dedication for the benefit
16# of the public at large and to the detriment of our heirs and
17# successors. We intend this dedication to be an overt act of
18# relinquishment in perpetuity of all present and future rights to this
19# software under copyright law.
20#
21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27# OTHER DEALINGS IN THE SOFTWARE.
28#
29
30import glob, os, shutil, string, subprocess
31import wiredtiger
32
33from wtdataset import SimpleDataSet, SimpleIndexDataSet, ComplexDataSet
34
35# python has a filecmp.cmp function, but different versions of python approach
36# file comparison differently.  To make sure we get byte for byte comparison,
37# we define it here.
38def compare_files(self, filename1, filename2):
39    self.pr('compare_files: ' + filename1 + ', ' + filename2)
40    bufsize = 4096
41    if os.path.getsize(filename1) != os.path.getsize(filename2):
42        print 'file comparison failed: ' + filename1 + ' size ' +\
43            str(os.path.getsize(filename1)) + ' != ' + filename2 +\
44            ' size ' + str(os.path.getsize(filename2))
45        return False
46    with open(filename1, "rb") as fp1:
47        with open(filename2, "rb") as fp2:
48            while True:
49                b1 = fp1.read(bufsize)
50                b2 = fp2.read(bufsize)
51                if b1 != b2:
52                    return False
53                # files are identical size
54                if not b1:
55                    return True
56
57# Iterate over a set of tables, ensuring that they have identical contents
58def compare_tables(self, session, uris, config=None):
59    cursors = list()
60    for next_uri in uris:
61        cursors.append(session.open_cursor(next_uri, None, config))
62
63    try:
64        done = False
65        while not done:
66            keys = list()
67            for next_cursor in cursors:
68                if (next_cursor.next() == wiredtiger.WT_NOTFOUND):
69                    done = True
70                    break
71                keys.append(next_cursor.get_value())
72            match = all(x == keys[0] for x in keys)
73            if not match:
74                return False
75
76        return True
77    finally:
78        for c in cursors:
79            c.close()
80
81# confirm a URI doesn't exist.
82def confirm_does_not_exist(self, uri):
83    self.pr('confirm_does_not_exist: ' + uri)
84    self.assertRaises(wiredtiger.WiredTigerError,
85        lambda: self.session.open_cursor(uri, None))
86    self.assertEqual(glob.glob('*' + uri.split(":")[-1] + '*'), [],
87        'confirm_does_not_exist: URI exists, file name matching \"' +
88        uri.split(":")[1] + '\" found')
89
90# confirm a URI exists and is empty.
91def confirm_empty(self, uri):
92    self.pr('confirm_empty: ' + uri)
93    cursor = self.session.open_cursor(uri, None)
94    if cursor.value_format == '8t':
95        for key,val in cursor:
96            self.assertEqual(val, 0)
97    else:
98        self.assertEqual(cursor.next(), wiredtiger.WT_NOTFOUND)
99    cursor.close()
100
101# copy a WT home directory
102def copy_wiredtiger_home(olddir, newdir, aligned=True):
103    # unaligned copy requires 'dd', which may not be available on Windows
104    if not aligned and os.name == "nt":
105        raise AssertionError(
106            'copy_wiredtiger_home: unaligned copy impossible on Windows')
107    shutil.rmtree(newdir, ignore_errors=True)
108    os.mkdir(newdir)
109    for fname in os.listdir(olddir):
110        fullname = os.path.join(olddir, fname)
111        # Skip lock file, on Windows it is locked.
112        # Skip temporary log files.
113        if os.path.isfile(fullname) and "WiredTiger.lock" not in fullname and \
114            "WiredTigerTmplog" not in fullname and \
115            "WiredTigerPreplog" not in fullname:
116            # Use a dd command that does not align on a block boundary.
117            if aligned:
118                shutil.copy(fullname, newdir)
119            else:
120                fullname = os.path.join(olddir, fname)
121                inpf = 'if=' + fullname
122                outf = 'of=' + newdir + '/' + fullname
123                cmd_list = ['dd', inpf, outf, 'bs=300']
124                a = subprocess.Popen(cmd_list)
125                a.wait()
126