Passed
Push — master ( 545e22...b70257 )
by Robbie
11:19 queued 10s
created

DatabaseTest::testTransactions()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 43
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 29
nc 3
nop 0
dl 0
loc 43
rs 9.456
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
        )->record();
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
    public 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(
105
                    $schema->doesSchemaNeedUpdating(),
106
                    'After cancelling the transaction the flag is false'
107
                );
108
            }
109
        );
110
    }
111
112
    public function testSchemaUpdateChecking()
113
    {
114
        $schema = DB::get_schema();
115
116
        // Initially, no schema changes necessary
117
        $test = $this;
118
        $schema->schemaUpdate(
119
            function () use ($test, $schema) {
120
                $test->assertFalse($schema->doesSchemaNeedUpdating());
121
122
                // If we make a change, then the schema will need updating
123
                $schema->transCreateTable("TestTable");
124
                $test->assertTrue($schema->doesSchemaNeedUpdating());
125
126
                // If we make cancel the change, then schema updates are no longer necessary
127
                $schema->cancelSchemaUpdate();
128
                $test->assertFalse($schema->doesSchemaNeedUpdating());
129
            }
130
        );
131
    }
132
133
    public function testHasTable()
134
    {
135
        $this->assertTrue(DB::get_schema()->hasTable('DatabaseTest_MyObject'));
136
        $this->assertFalse(DB::get_schema()->hasTable('asdfasdfasdf'));
137
    }
138
139
    public function testGetAndReleaseLock()
140
    {
141
        $db = DB::get_conn();
142
143
        if (!$db->supportsLocks()) {
144
            return $this->markTestSkipped('Tested database doesn\'t support application locks');
145
        }
146
147
        $this->assertTrue(
148
            $db->getLock('DatabaseTest'),
149
            'Can aquire lock'
150
        );
151
        // $this->assertFalse($db->getLock('DatabaseTest'), 'Can\'t repeatedly aquire the same lock');
152
        $this->assertTrue(
153
            $db->getLock('DatabaseTest'),
154
            'The same lock can be aquired multiple times in the same connection'
155
        );
156
157
        $this->assertTrue(
158
            $db->getLock('DatabaseTestOtherLock'),
159
            'Can aquire different lock'
160
        );
161
        $db->releaseLock('DatabaseTestOtherLock');
162
163
        // Release potentially stacked locks from previous getLock() invocations
164
        $db->releaseLock('DatabaseTest');
165
        $db->releaseLock('DatabaseTest');
166
167
        $this->assertTrue(
168
            $db->getLock('DatabaseTest'),
169
            'Can aquire lock after releasing it'
170
        );
171
        $db->releaseLock('DatabaseTest');
172
    }
173
174
    public function testCanLock()
175
    {
176
        $db = DB::get_conn();
177
178
        if (!$db->supportsLocks()) {
179
            return $this->markTestSkipped('Database doesn\'t support locks');
180
        }
181
182
        if ($db instanceof MSSQLDatabase) {
183
            return $this->markTestSkipped('MSSQLDatabase doesn\'t support inspecting locks');
184
        }
185
186
        $this->assertTrue($db->canLock('DatabaseTest'), 'Can lock before first aquiring one');
187
        $db->getLock('DatabaseTest');
188
        $this->assertFalse($db->canLock('DatabaseTest'), 'Can\'t lock after aquiring one');
189
        $db->releaseLock('DatabaseTest');
190
        $this->assertTrue($db->canLock('DatabaseTest'), 'Can lock again after releasing it');
191
    }
192
193
    public function testFieldTypes()
194
    {
195
        // Scaffold some data
196
        $obj = new MyObject();
197
        $obj->MyField = "value";
0 ignored issues
show
Bug Best Practice introduced by
The property MyField does not exist on SilverStripe\ORM\Tests\DatabaseTest\MyObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
198
        $obj->MyInt = 5;
0 ignored issues
show
Bug Best Practice introduced by
The property MyInt does not exist on SilverStripe\ORM\Tests\DatabaseTest\MyObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
199
        $obj->MyFloat = 6.0;
0 ignored issues
show
Bug Best Practice introduced by
The property MyFloat does not exist on SilverStripe\ORM\Tests\DatabaseTest\MyObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
200
        $obj->MyBoolean = true;
0 ignored issues
show
Bug Best Practice introduced by
The property MyBoolean does not exist on SilverStripe\ORM\Tests\DatabaseTest\MyObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
201
        $obj->write();
202
203
        $record = DB::prepared_query(
204
            'SELECT * FROM "DatabaseTest_MyObject" WHERE "ID" = ?',
205
            [ $obj->ID ]
206
        )->record();
207
208
        // IDs and ints are returned as ints
209
        $this->assertInternalType('int', $record['ID']);
210
        $this->assertInternalType('int', $record['MyInt']);
211
212
        $this->assertInternalType('float', $record['MyFloat']);
213
214
        // Booleans are returned as ints – we follow MySQL's lead
215
        $this->assertInternalType('int', $record['MyBoolean']);
216
217
        // Strings and enums are returned as strings
218
        $this->assertInternalType('string', $record['MyField']);
219
        $this->assertInternalType('string', $record['ClassName']);
220
221
        // Dates are returned as strings
222
        $this->assertInternalType('string', $record['Created']);
223
        $this->assertInternalType('string', $record['LastEdited']);
224
    }
225
}
226