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# test_readonly02.py
30#   Readonly: Test readonly mode with illegal config combinations
31#   and error checking during updates.
32#
33
34from helper import copy_wiredtiger_home
35from suite_subprocess import suite_subprocess
36import os, wiredtiger, wttest
37
38class test_readonly02(wttest.WiredTigerTestCase, suite_subprocess):
39    tablename = 'table:test_readonly02'
40    create = True
41    create_params = 'key_format=i,value_format=i'
42    entries = 10
43
44    conn_params = \
45        'create,statistics=(fast),' + \
46        'log=(enabled,file_max=100K,zero_fill=true),' + \
47        'operation_tracking=(enabled=false),'
48    conn_params_rd = \
49        'create,readonly=true,statistics=(fast),' + \
50        'log=(enabled,zero_fill=false),' + \
51        'operation_tracking=(enabled=false),'
52    conn_params_rdcfg = \
53        'create,readonly=true,statistics=(fast),log=(enabled),' + \
54        'operation_tracking=(enabled=false),'
55
56    #
57    # Run to make sure incompatible configuration options return an error.
58    # The situations that cause failures (instead of silent overrides) are:
59    #   1. setting readonly on a new database directory
60    #   2. an unclean shutdown and reopening readonly
61    #   3. logging with zero-fill enabled and readonly
62    #
63    badcfg1 = 'log=(enabled,zero_fill=true)'
64
65    def setUpConnectionOpen(self, dir):
66        self.home = dir
67        rdonlydir = dir + '.rdonly'
68        #
69        # First time through check readonly on a non-existent database.
70        #
71        if self.create:
72            #   1. setting readonly on a new database directory
73            # Setting readonly prevents creation so we should see an
74            # error because the lock file does not exist.
75            msg = '/No such file/'
76            if os.name != 'posix':
77                msg = '/cannot find the file/'
78            os.mkdir(rdonlydir)
79            self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
80                lambda: self.wiredtiger_open(
81                rdonlydir, self.conn_params_rd), msg)
82
83        self.create = False
84        conn = self.wiredtiger_open(dir, self.conn_params)
85        return conn
86
87    def check_unclean(self):
88        backup = "WT_COPYDIR"
89        copy_wiredtiger_home(self.home, backup, True)
90        msg = '/needs recovery/'
91        #   2. an unclean shutdown and reopening readonly
92        self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
93            lambda: self.wiredtiger_open(backup, self.conn_params_rd), msg)
94
95    def close_checkerror(self, cfg):
96        ''' Close the connection and reopen readonly'''
97        #
98        # Close the original connection.  Reopen readonly and also with
99        # the given configuration string.
100        #
101        self.close_conn()
102        conn_params = self.conn_params_rd + cfg
103        msg = '/Invalid argument/'
104        self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
105            lambda: self.wiredtiger_open(self.home, conn_params), msg)
106
107    def test_readonly(self):
108        tablearg = self.tablename
109        self.session.create(tablearg, self.create_params)
110        c = self.session.open_cursor(tablearg, None, None)
111        for i in range(self.entries):
112            c[i+1] = i % 255
113        # Check for an error on an unclean recovery/restart.
114        self.check_unclean()
115
116        # Close the connection.  Reopen readonly with other bad settings.
117        #   3. logging with zero-fill enabled and readonly
118        self.close_checkerror(self.badcfg1)
119
120if __name__ == '__main__':
121    wttest.run()
122