|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @package framework |
|
4
|
|
|
* @subpackage Testing |
|
5
|
|
|
*/ |
|
6
|
|
|
class DatabaseTest extends SapphireTest { |
|
7
|
|
|
|
|
8
|
|
|
protected $extraDataObjects = array( |
|
9
|
|
|
'DatabaseTest_MyObject', |
|
10
|
|
|
); |
|
11
|
|
|
|
|
12
|
|
|
protected $usesDatabase = true; |
|
13
|
|
|
|
|
14
|
|
|
public function testDontRequireField() { |
|
15
|
|
|
$schema = DB::get_schema(); |
|
16
|
|
|
$this->assertArrayHasKey( |
|
17
|
|
|
'MyField', |
|
18
|
|
|
$schema->fieldList('DatabaseTest_MyObject') |
|
19
|
|
|
); |
|
20
|
|
|
|
|
21
|
|
|
$schema->dontRequireField('DatabaseTest_MyObject', 'MyField'); |
|
22
|
|
|
|
|
23
|
|
|
$this->assertArrayHasKey( |
|
24
|
|
|
'_obsolete_MyField', |
|
25
|
|
|
$schema->fieldList('DatabaseTest_MyObject'), |
|
26
|
|
|
'Field is renamed to _obsolete_<fieldname> through dontRequireField()' |
|
27
|
|
|
); |
|
28
|
|
|
|
|
29
|
|
|
$this->resetDBSchema(true); |
|
30
|
|
|
} |
|
31
|
|
|
|
|
32
|
|
|
public function testRenameField() { |
|
33
|
|
|
$schema = DB::get_schema(); |
|
34
|
|
|
|
|
35
|
|
|
$schema->clearCachedFieldlist(); |
|
36
|
|
|
|
|
37
|
|
|
$schema->renameField('DatabaseTest_MyObject', 'MyField', 'MyRenamedField'); |
|
38
|
|
|
|
|
39
|
|
|
$this->assertArrayHasKey( |
|
40
|
|
|
'MyRenamedField', |
|
41
|
|
|
$schema->fieldList('DatabaseTest_MyObject'), |
|
42
|
|
|
'New fieldname is set through renameField()' |
|
43
|
|
|
); |
|
44
|
|
|
$this->assertArrayNotHasKey( |
|
45
|
|
|
'MyField', |
|
46
|
|
|
$schema->fieldList('DatabaseTest_MyObject'), |
|
47
|
|
|
'Old fieldname isnt preserved through renameField()' |
|
48
|
|
|
); |
|
49
|
|
|
|
|
50
|
|
|
$this->resetDBSchema(true); |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
public function testMySQLCreateTableOptions() { |
|
54
|
|
|
if(!(DB::get_conn() instanceof MySQLDatabase)) { |
|
55
|
|
|
$this->markTestSkipped('MySQL only'); |
|
56
|
|
|
} |
|
57
|
|
|
|
|
58
|
|
|
|
|
59
|
|
|
$ret = DB::query(sprintf( |
|
60
|
|
|
'SHOW TABLE STATUS WHERE "Name" = \'%s\'', |
|
61
|
|
|
'DatabaseTest_MyObject' |
|
62
|
|
|
))->first(); |
|
63
|
|
|
$this->assertEquals($ret['Engine'],'InnoDB', |
|
64
|
|
|
"MySQLDatabase tables can be changed to InnoDB through DataObject::\$create_table_options" |
|
65
|
|
|
); |
|
66
|
|
|
} |
|
67
|
|
|
|
|
68
|
|
|
function testIsSchemaUpdating() { |
|
69
|
|
|
$schema = DB::get_schema(); |
|
70
|
|
|
|
|
71
|
|
|
$this->assertFalse($schema->isSchemaUpdating(), 'Before the transaction the flag is false.'); |
|
72
|
|
|
|
|
73
|
|
|
// Test complete schema update |
|
74
|
|
|
$test = $this; |
|
75
|
|
|
$schema->schemaUpdate(function() use ($test, $schema) { |
|
76
|
|
|
$test->assertTrue($schema->isSchemaUpdating(), 'During the transaction the flag is true.'); |
|
77
|
|
|
}); |
|
78
|
|
|
$this->assertFalse($schema->isSchemaUpdating(), 'After the transaction the flag is false.'); |
|
79
|
|
|
|
|
80
|
|
|
// Test cancelled schema update |
|
81
|
|
|
$schema->schemaUpdate(function() use ($test, $schema) { |
|
82
|
|
|
$schema->cancelSchemaUpdate(); |
|
83
|
|
|
$test->assertFalse($schema->doesSchemaNeedUpdating(), 'After cancelling the transaction the flag is false'); |
|
84
|
|
|
}); |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
public function testSchemaUpdateChecking() { |
|
88
|
|
|
$schema = DB::get_schema(); |
|
89
|
|
|
|
|
90
|
|
|
// Initially, no schema changes necessary |
|
91
|
|
|
$test = $this; |
|
92
|
|
|
$schema->schemaUpdate(function() use ($test, $schema) { |
|
93
|
|
|
$test->assertFalse($schema->doesSchemaNeedUpdating()); |
|
94
|
|
|
|
|
95
|
|
|
// If we make a change, then the schema will need updating |
|
96
|
|
|
$schema->transCreateTable("TestTable"); |
|
97
|
|
|
$test->assertTrue($schema->doesSchemaNeedUpdating()); |
|
98
|
|
|
|
|
99
|
|
|
// If we make cancel the change, then schema updates are no longer necessary |
|
100
|
|
|
$schema->cancelSchemaUpdate(); |
|
101
|
|
|
$test->assertFalse($schema->doesSchemaNeedUpdating()); |
|
102
|
|
|
}); |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
|
|
public function testHasTable() { |
|
106
|
|
|
$this->assertTrue(DB::get_schema()->hasTable('DatabaseTest_MyObject')); |
|
107
|
|
|
$this->assertFalse(DB::get_schema()->hasTable('asdfasdfasdf')); |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
public function testGetAndReleaseLock() { |
|
111
|
|
|
$db = DB::get_conn(); |
|
112
|
|
|
|
|
113
|
|
|
if(!$db->supportsLocks()) { |
|
114
|
|
|
return $this->markTestSkipped('Tested database doesn\'t support application locks'); |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
|
|
$this->assertTrue($db->getLock('DatabaseTest'), |
|
118
|
|
|
'Can aquire lock'); |
|
119
|
|
|
// $this->assertFalse($db->getLock('DatabaseTest'), 'Can\'t repeatedly aquire the same lock'); |
|
120
|
|
|
$this->assertTrue($db->getLock('DatabaseTest'), |
|
121
|
|
|
'The same lock can be aquired multiple times in the same connection'); |
|
122
|
|
|
|
|
123
|
|
|
$this->assertTrue($db->getLock('DatabaseTestOtherLock'), |
|
124
|
|
|
'Can aquire different lock'); |
|
125
|
|
|
$db->releaseLock('DatabaseTestOtherLock'); |
|
126
|
|
|
|
|
127
|
|
|
// Release potentially stacked locks from previous getLock() invocations |
|
128
|
|
|
$db->releaseLock('DatabaseTest'); |
|
129
|
|
|
$db->releaseLock('DatabaseTest'); |
|
130
|
|
|
|
|
131
|
|
|
$this->assertTrue($db->getLock('DatabaseTest'), |
|
132
|
|
|
'Can aquire lock after releasing it'); |
|
133
|
|
|
$db->releaseLock('DatabaseTest'); |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
|
|
public function testCanLock() { |
|
137
|
|
|
$db = DB::get_conn(); |
|
138
|
|
|
|
|
139
|
|
|
if(!$db->supportsLocks()) { |
|
140
|
|
|
return $this->markTestSkipped('Database doesn\'t support locks'); |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
if($db instanceof MSSQLDatabase) { |
|
|
|
|
|
|
144
|
|
|
return $this->markTestSkipped('MSSQLDatabase doesn\'t support inspecting locks'); |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
$this->assertTrue($db->canLock('DatabaseTest'), 'Can lock before first aquiring one'); |
|
148
|
|
|
$db->getLock('DatabaseTest'); |
|
149
|
|
|
$this->assertFalse($db->canLock('DatabaseTest'), 'Can\'t lock after aquiring one'); |
|
150
|
|
|
$db->releaseLock('DatabaseTest'); |
|
151
|
|
|
$this->assertTrue($db->canLock('DatabaseTest'), 'Can lock again after releasing it'); |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
public function testTransactions() { |
|
155
|
|
|
$conn = DB::getConn(); |
|
|
|
|
|
|
156
|
|
|
if(!$conn->supportsTransactions()) { |
|
157
|
|
|
$this->markTestSkipped("DB Doesn't support transactions"); |
|
158
|
|
|
return; |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
// Test that successful transactions are comitted |
|
162
|
|
|
$obj = new DatabaseTest_MyObject(); |
|
163
|
|
|
$failed = false; |
|
164
|
|
|
$conn->withTransaction(function() use (&$obj) { |
|
165
|
|
|
$obj->MyField = 'Save 1'; |
|
|
|
|
|
|
166
|
|
|
$obj->write(); |
|
167
|
|
|
}, function() use (&$failed) { |
|
168
|
|
|
$failed = true; |
|
169
|
|
|
}); |
|
170
|
|
|
$this->assertEquals('Save 1', DatabaseTest_MyObject::get()->first()->MyField); |
|
171
|
|
|
$this->assertFalse($failed); |
|
172
|
|
|
|
|
173
|
|
|
// Test failed transactions are rolled back |
|
174
|
|
|
$ex = null; |
|
175
|
|
|
$failed = false; |
|
176
|
|
|
try { |
|
177
|
|
|
$conn->withTransaction(function() use (&$obj) { |
|
178
|
|
|
$obj->MyField = 'Save 2'; |
|
|
|
|
|
|
179
|
|
|
$obj->write(); |
|
180
|
|
|
throw new Exception("error"); |
|
181
|
|
|
}, function() use (&$failed) { |
|
182
|
|
|
$failed = true; |
|
183
|
|
|
}); |
|
184
|
|
|
} catch ( Exception $ex) {} |
|
|
|
|
|
|
185
|
|
|
$this->assertTrue($failed); |
|
186
|
|
|
$this->assertEquals('Save 1', DatabaseTest_MyObject::get()->first()->MyField); |
|
187
|
|
|
$this->assertInstanceOf('Exception', $ex); |
|
188
|
|
|
$this->assertEquals('error', $ex->getMessage()); |
|
189
|
|
|
} |
|
190
|
|
|
|
|
191
|
|
|
|
|
192
|
|
|
} |
|
193
|
|
|
|
|
194
|
|
|
class DatabaseTest_MyObject extends DataObject implements TestOnly { |
|
195
|
|
|
|
|
196
|
|
|
private static $create_table_options = array(MySQLSchemaManager::ID => 'ENGINE=InnoDB'); |
|
197
|
|
|
|
|
198
|
|
|
private static $db = array( |
|
199
|
|
|
'MyField' => 'Varchar' |
|
200
|
|
|
); |
|
201
|
|
|
} |
|
202
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.jsonfile (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.jsonto be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
requireorrequire-devsection?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceofchecks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.