#!/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.
#
# test_backup09.py
#   Verify opening a backup cursor forces a log file switch.
#

import os, shutil, stat
import helper, wiredtiger, wttest
from wtscenario import make_scenarios

class test_backup09(wttest.WiredTigerTestCase):
    # Have log writes go directly to the OS to avoid log_flush calls before
    # performing file copies not technically part of the backup cursor.
    conn_config = 'config_base=false,create,' \
        'log=(enabled),transaction_sync=(enabled,method=none)'
    uri = 'table:coll1'
    backup_dir = 'backup.dir'

    types = [
        # checkpoint: whether to explicitly checkpoint some data before opening
        #   the backup cursor.
        #
        # all_log_files: whether to copy all files in the source directory, or
        #   only the files returned from the backup cursor. Copying the
        #   additional log files will result in more operations being recovered.
        ('checkpoint', dict(checkpoint=True, all_log_files=False)),
        ('no_checkpoint', dict(checkpoint=False, all_log_files=False)),
        ('all_log_files', dict(checkpoint=True, all_log_files=True)),
    ]
    scenarios = make_scenarios(types)

    def data_and_start_backup(self):
        self.session.create(self.uri, 'key_format=i,value_format=i')

        cursor = self.session.open_cursor(self.uri)
        doc_id = 0

        for i in range(10):
            doc_id += 1
            cursor[doc_id] = doc_id

        if self.checkpoint:
            self.session.checkpoint()

        for i in range(10):
            doc_id += 1
            cursor[doc_id] = doc_id

        last_doc_in_backup = doc_id
        self.assertEqual(1, len([x for x in os.listdir('.') if x.startswith('WiredTigerLog.')]))
        backup_cursor = self.session.open_cursor('backup:')
        self.assertEqual(2, len([x for x in os.listdir('.') if x.startswith('WiredTigerLog.')]))

        for i in range(10):
            doc_id += 1
            cursor[doc_id] = doc_id

        cursor.close()
        return backup_cursor, last_doc_in_backup, doc_id

    def copy_and_restore(self, backup_cursor, last_doc_in_backup, last_doc_in_data):
        log_files_to_copy = 0
        os.mkdir(self.backup_dir)
        if self.all_log_files:
            helper.copy_wiredtiger_home(self, '.', self.backup_dir)
            log_files_copied = [x for x in os.listdir(self.backup_dir) if x.startswith('WiredTigerLog.')]
            self.assertEqual(len(log_files_copied), 2)
        else:
            while True:
                ret = backup_cursor.next()
                if ret != 0:
                    break
                shutil.copy(backup_cursor.get_key(), self.backup_dir)
                if backup_cursor.get_key().startswith('WiredTigerLog.'):
                    log_files_to_copy += 1

            self.assertEqual(ret, wiredtiger.WT_NOTFOUND)
            self.assertEqual(log_files_to_copy, 1)

        backup_conn = self.wiredtiger_open(self.backup_dir, self.conn_config)
        if self.all_log_files:
            self.captureout.checkAdditionalPattern(self, 'Both WiredTiger.turtle and WiredTiger.backup exist.*')

        session = backup_conn.open_session()
        cursor = session.open_cursor(self.uri)

        if self.all_log_files:
            doc_cnt = 0
            for key, val in cursor:
                doc_cnt += 1
                self.assertLessEqual(key, last_doc_in_data)

            self.assertEqual(doc_cnt, last_doc_in_data)
        else:
            doc_cnt = 0
            for key, val in cursor:
                doc_cnt += 1
                self.assertLessEqual(key, last_doc_in_backup)

            self.assertEqual(doc_cnt, last_doc_in_backup)

    def test_backup_rotates_log(self):
        if os.name == "nt" and self.all_log_files:
            self.skipTest('Unix specific test skipped on Windows')

        # Add some data, open a backup cursor, and add some more data. Return
        # the value of the last document that should appear on a restore.
        backup_cursor, last_doc_in_backup, last_doc_in_data = \
            self.data_and_start_backup()

        # Copy the files returned via the backup cursor and bring up WiredTiger
        # on the destination. Verify no document later than last_doc exists.
        self.copy_and_restore(
            backup_cursor, last_doc_in_backup, last_doc_in_data)

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