#!/usr/bin/env python
#
# Public Domain 2014-present MongoDB, Inc.
# Public Domain 2008-2014 WiredTiger, Inc.
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

import os
import shutil
import string
from wtbackup import backup_base
import wiredtiger, wttest
from wiredtiger import stat
from wtdataset import SimpleDataSet, ComplexDataSet, ComplexLSMDataSet
try:
    # Windows does not getrlimit/setrlimit so we must catch the resource
    # module load.
    import resource
except:
    None

# test_backup06.py
#    Test that opening a backup cursor does not open file handles.
class test_backup06(backup_base):
    conn_config = 'statistics=(fast)'
    # This will create several hundred tables.
    num_table_sets = 10
    pfx='test_backup'

    # We try to do some schema operations.  Have some well
    # known names.
    schema_uri = 'file:schema_test'
    rename_uri = 'file:new_test'
    trename_uri = 'table:new_test'

    fobjs = [
        ( 'file:' + pfx + '.1', SimpleDataSet),
        ( 'file:' + pfx + '.2', SimpleDataSet),
    ]
    tobjs = [
        ('table:' + pfx + '.3', SimpleDataSet),
        ('table:' + pfx + '.4', SimpleDataSet),
        ('table:' + pfx + '.5', ComplexDataSet),
        ('table:' + pfx + '.6', ComplexDataSet),
        ('table:' + pfx + '.7', ComplexLSMDataSet),
        ('table:' + pfx + '.8', ComplexLSMDataSet),
    ]

    # Populate a set of objects.
    def populate_many(self):
        for t in range(0, self.num_table_sets):
            for i in self.fobjs:
                uri = i[0] + "." + str(t)
                i[1](self, uri, 10).populate()
            for i in self.tobjs:
                uri = i[0] + "." + str(t)
                i[1](self, uri, 10).populate()

    # Test that the open handle count does not change.
    def test_cursor_open_handles(self):
        if os.name == "nt":
            self.skipTest('Unix specific test skipped on Windows')

        limits = resource.getrlimit(resource.RLIMIT_NOFILE)
        if limits[0] < 1024:
            new = (1024, limits[1])
            resource.setrlimit(resource.RLIMIT_NOFILE, new)
        self.populate_many()
        # Close and reopen the connection so the populate dhandles are
        # not in the list.
        self.reopen_conn()

        new = (limits[0], limits[1])
        resource.setrlimit(resource.RLIMIT_NOFILE, new)

        # Confirm that opening a backup cursor does not open
        # file handles.
        stat_cursor = self.session.open_cursor('statistics:', None, None)
        dh_before = stat_cursor[stat.conn.dh_conn_handle_count][2]
        stat_cursor.close()
        cursor = self.session.open_cursor('backup:', None, None)
        stat_cursor = self.session.open_cursor('statistics:', None, None)
        dh_after = stat_cursor[stat.conn.dh_conn_handle_count][2]
        stat_cursor.close()
        if (dh_before != dh_after):
            print("Dhandles open before backup open: " + str(dh_before))
            print("Dhandles open after backup open: " + str(dh_after))
        self.assertEqual(dh_after == dh_before, True)
        cursor.close()

    def test_cursor_schema_protect(self):
        schema_uri = 'file:schema_test'
        rename_uri = 'file:new_test'
        trename_uri = 'table:new_test'

        #
        # Set up a number of tables.  Close and reopen the connection so that
        # we do not have open dhandles.  Then we want to open a backup cursor
        # testing both with and without the configuration setting.
        # We want to confirm that we open data handles when using schema
        # protection and we do not open the data handles when set to false.
        # We also want to make sure we detect and get an error when set to
        # false.  When set to true the open handles protect against schema
        # operations.
        self.populate(self.fobjs)
        self.populate(self.tobjs)
        cursor = self.session.open_cursor('backup:', None, None)
        # Check that we can create.
        self.session.create(schema_uri, None)
        for i in self.fobjs:
            self.assertRaises(wiredtiger.WiredTigerError,
                lambda: self.session.drop(i[0], None))
            self.assertRaises(wiredtiger.WiredTigerError,
                lambda: self.session.rename(i[0], rename_uri))
        for i in self.tobjs:
            self.assertRaises(wiredtiger.WiredTigerError,
                lambda: self.session.drop(i[0], None))
            self.assertRaises(wiredtiger.WiredTigerError,
                lambda: self.session.rename(i[0], trename_uri))
        cursor.close()

    # Test cursor reset runs through the list twice.
    def test_cursor_reset(self):
        self.populate(self.fobjs)
        self.populate(self.tobjs)
        cursor = self.session.open_cursor('backup:', None, None)
        i = 0
        while True:
            ret = cursor.next()
            if ret != 0:
                break
            i += 1
        self.assertEqual(ret, wiredtiger.WT_NOTFOUND)
        total = i * 2
        cursor.reset()
        while True:
            ret = cursor.next()
            if ret != 0:
                break
            i += 1
        self.assertEqual(ret, wiredtiger.WT_NOTFOUND)
        self.assertEqual(i, total)
        cursor.close()

if __name__ == '__main__':
    wttest.run()
