Completed
Push — 4.0 ( b59aea...80f83b )
by Loz
52s queued 21s
created

DatabaseTest::testIsSchemaUpdating()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 11
nc 1
nop 0
dl 0
loc 20
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\ORM\Tests;
4
5
use SilverStripe\ORM\DB;
6
use SilverStripe\ORM\Connect\MySQLDatabase;
7
use SilverStripe\MSSQL\MSSQLDatabase;
0 ignored issues
show
Bug introduced by
The type SilverStripe\MSSQL\MSSQLDatabase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use SilverStripe\Dev\SapphireTest;
9
use Exception;
10
use SilverStripe\ORM\Tests\DatabaseTest\MyObject;
11
12
/**
13
 * @skipUpgrade
14
*/
15
class DatabaseTest extends SapphireTest
16
{
17
18
    protected static $extra_dataobjects = array(
19
        MyObject::class,
20
    );
21
22
    protected $usesDatabase = true;
23
24
    public function testDontRequireField()
25
    {
26
        $schema = DB::get_schema();
27
        $this->assertArrayHasKey(
28
            'MyField',
29
            $schema->fieldList('DatabaseTest_MyObject')
30
        );
31
32
        $schema->dontRequireField('DatabaseTest_MyObject', 'MyField');
33
34
        $this->assertArrayHasKey(
35
            '_obsolete_MyField',
36
            $schema->fieldList('DatabaseTest_MyObject'),
37
            'Field is renamed to _obsolete_<fieldname> through dontRequireField()'
38
        );
39
40
        static::resetDBSchema(true);
41
    }
42
43
    public function testRenameField()
44
    {
45
        $schema = DB::get_schema();
46
47
        $schema->clearCachedFieldlist();
48
49
        $schema->renameField('DatabaseTest_MyObject', 'MyField', 'MyRenamedField');
50
51
        $this->assertArrayHasKey(
52
            'MyRenamedField',
53
            $schema->fieldList('DatabaseTest_MyObject'),
54
            'New fieldname is set through renameField()'
55
        );
56
        $this->assertArrayNotHasKey(
57
            'MyField',
58
            $schema->fieldList('DatabaseTest_MyObject'),
59
            'Old fieldname isnt preserved through renameField()'
60
        );
61
62
        static::resetDBSchema(true);
63
    }
64
65
    public function testMySQLCreateTableOptions()
66
    {
67
        if (!(DB::get_conn() instanceof MySQLDatabase)) {
68
            $this->markTestSkipped('MySQL only');
69
        }
70
71
72
        $ret = DB::query(
73
            sprintf(
74
                'SHOW TABLE STATUS WHERE "Name" = \'%s\'',
75
                'DatabaseTest_MyObject'
76
            )
77
        )->first();
78
        $this->assertEquals(
79
            $ret['Engine'],
80
            'InnoDB',
81
            "MySQLDatabase tables can be changed to InnoDB through DataObject::\$create_table_options"
82
        );
83
    }
84
85
    function testIsSchemaUpdating()
86
    {
87
        $schema = DB::get_schema();
88
89
        $this->assertFalse($schema->isSchemaUpdating(), 'Before the transaction the flag is false.');
90
91
        // Test complete schema update
92
        $test = $this;
93
        $schema->schemaUpdate(
94
            function () use ($test, $schema) {
95
                $test->assertTrue($schema->isSchemaUpdating(), 'During the transaction the flag is true.');
96
            }
97
        );
98
        $this->assertFalse($schema->isSchemaUpdating(), 'After the transaction the flag is false.');
99
100
        // Test cancelled schema update
101
        $schema->schemaUpdate(
102
            function () use ($test, $schema) {
103
                $schema->cancelSchemaUpdate();
104
                $test->assertFalse($schema->doesSchemaNeedUpdating(), 'After cancelling the transaction the flag is false');
105
            }
106
        );
107
    }
108
109
    public function testSchemaUpdateChecking()
110
    {
111
        $schema = DB::get_schema();
112
113
        // Initially, no schema changes necessary
114
        $test = $this;
115
        $schema->schemaUpdate(
116
            function () use ($test, $schema) {
117
                $test->assertFalse($schema->doesSchemaNeedUpdating());
118
119
                // If we make a change, then the schema will need updating
120
                $schema->transCreateTable("TestTable");
121
                $test->assertTrue($schema->doesSchemaNeedUpdating());
122
123
                // If we make cancel the change, then schema updates are no longer necessary
124
                $schema->cancelSchemaUpdate();
125
                $test->assertFalse($schema->doesSchemaNeedUpdating());
126
            }
127
        );
128
    }
129
130
    public function testHasTable()
131
    {
132
        $this->assertTrue(DB::get_schema()->hasTable('DatabaseTest_MyObject'));
133
        $this->assertFalse(DB::get_schema()->hasTable('asdfasdfasdf'));
134
    }
135
136
    public function testGetAndReleaseLock()
137
    {
138
        $db = DB::get_conn();
139
140
        if (!$db->supportsLocks()) {
141
            return $this->markTestSkipped('Tested database doesn\'t support application locks');
142
        }
143
144
        $this->assertTrue(
145
            $db->getLock('DatabaseTest'),
146
            'Can aquire lock'
147
        );
148
        // $this->assertFalse($db->getLock('DatabaseTest'), 'Can\'t repeatedly aquire the same lock');
149
        $this->assertTrue(
150
            $db->getLock('DatabaseTest'),
151
            'The same lock can be aquired multiple times in the same connection'
152
        );
153
154
        $this->assertTrue(
155
            $db->getLock('DatabaseTestOtherLock'),
156
            'Can aquire different lock'
157
        );
158
        $db->releaseLock('DatabaseTestOtherLock');
159
160
        // Release potentially stacked locks from previous getLock() invocations
161
        $db->releaseLock('DatabaseTest');
162
        $db->releaseLock('DatabaseTest');
163
164
        $this->assertTrue(
165
            $db->getLock('DatabaseTest'),
166
            'Can aquire lock after releasing it'
167
        );
168
        $db->releaseLock('DatabaseTest');
169
    }
170
171
    public function testCanLock()
172
    {
173
        $db = DB::get_conn();
174
175
        if (!$db->supportsLocks()) {
176
            return $this->markTestSkipped('Database doesn\'t support locks');
177
        }
178
179
        if ($db instanceof MSSQLDatabase) {
180
            return $this->markTestSkipped('MSSQLDatabase doesn\'t support inspecting locks');
181
        }
182
183
        $this->assertTrue($db->canLock('DatabaseTest'), 'Can lock before first aquiring one');
184
        $db->getLock('DatabaseTest');
185
        $this->assertFalse($db->canLock('DatabaseTest'), 'Can\'t lock after aquiring one');
186
        $db->releaseLock('DatabaseTest');
187
        $this->assertTrue($db->canLock('DatabaseTest'), 'Can lock again after releasing it');
188
    }
189
190
    public function testTransactions()
191
    {
192
        $conn = DB::get_conn();
193
        if (!$conn->supportsTransactions()) {
194
            $this->markTestSkipped("DB Doesn't support transactions");
195
            return;
196
        }
197
198
        // Test that successful transactions are comitted
199
        $obj = new DatabaseTest\MyObject();
200
        $failed = false;
201
        $conn->withTransaction(
202
            function () use (&$obj) {
203
                $obj->MyField = 'Save 1';
204
                $obj->write();
205
            },
206
            function () use (&$failed) {
207
                $failed = true;
208
            }
209
        );
210
        $this->assertEquals('Save 1', DatabaseTest\MyObject::get()->first()->MyField);
0 ignored issues
show
Bug Best Practice introduced by
The property MyField does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
211
        $this->assertFalse($failed);
212
213
        // Test failed transactions are rolled back
214
        $ex = null;
215
        $failed = false;
216
        try {
217
            $conn->withTransaction(
218
                function () use (&$obj) {
219
                    $obj->MyField = 'Save 2';
220
                    $obj->write();
221
                    throw new Exception("error");
222
                },
223
                function () use (&$failed) {
224
                    $failed = true;
225
                }
226
            );
227
        } catch (Exception $ex) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
228
        }
229
        $this->assertTrue($failed);
230
        $this->assertEquals('Save 1', DatabaseTest\MyObject::get()->first()->MyField);
231
        $this->assertInstanceOf('Exception', $ex);
232
        $this->assertEquals('error', $ex->getMessage());
0 ignored issues
show
Bug introduced by
The method getMessage() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

232
        $this->assertEquals('error', $ex->/** @scrutinizer ignore-call */ getMessage());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
233
    }
234
}
235