Passed
Push — master ( 109b6e...716545 )
by Alaa
58s queued 11s
created

testFallsBackToMasterIfNecessaryAndAllowed()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 51
rs 9.069
c 0
b 0
f 0
cc 2
nc 2
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Wikibase\TermStore\MediaWiki\Tests\Integration\PackagePrivate;
4
5
use PHPUnit\Framework\TestCase;
6
use Wikibase\TermStore\MediaWiki\PackagePrivate\DatabaseTermIdsResolver;
7
use Wikibase\TermStore\MediaWiki\PackagePrivate\StaticTypeIdsStore;
8
use Wikibase\TermStore\MediaWiki\PackagePrivate\TypeIdsResolver;
9
use Wikibase\TermStore\MediaWiki\TermStoreSchemaUpdater;
10
use Wikibase\TermStore\MediaWiki\Tests\Util\FakeLoadBalancer;
11
use Wikimedia\Rdbms\Database;
12
use Wikimedia\Rdbms\DatabaseSqlite;
13
use Wikimedia\Rdbms\IDatabase;
14
use Wikimedia\Rdbms\ILoadBalancer;
15
16
/**
17
 * @covers \Wikibase\TermStore\MediaWiki\PackagePrivate\DatabaseTermIdsResolver
18
 */
19
class DatabaseTermIdsResolverTest extends TestCase {
20
21
	const TYPE_LABEL = 1;
22
	const TYPE_DESCRIPTION = 2;
23
	const TYPE_ALIAS = 3;
24
25
	/** @var TypeIdsResolver */
26
	private $typeIdsResolver;
27
28
	/** @var IDatabase */
29
	private $db;
30
31
	public function setUp() {
32
		$this->typeIdsResolver = new StaticTypeIdsStore( [
33
			'label' => self::TYPE_LABEL,
34
			'description' => self::TYPE_DESCRIPTION,
35
			'alias' => self::TYPE_ALIAS,
36
		] );
37
		$this->db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
38
		$this->db->sourceFile( TermStoreSchemaUpdater::getSqlFileAbsolutePath() );
39
	}
40
41
	public function testCanResolveEverything() {
42
		$this->db->insert( 'wbt_text',
43
			[ 'wbx_text' => 'text' ] );
44
		$text1Id = $this->db->insertId();
45
		$this->db->insert( 'wbt_text',
46
			[ 'wbx_text' => 'Text' ] );
47
		$text2Id = $this->db->insertId();
48
		$this->db->insert( 'wbt_text_in_lang',
49
			[ 'wbxl_language' => 'en', 'wbxl_text_id' => $text1Id ] );
50
		$textInLang1Id = $this->db->insertId();
51
		$this->db->insert( 'wbt_text_in_lang',
52
			[ 'wbxl_language' => 'de', 'wbxl_text_id' => $text2Id ] );
53
		$textInLang2Id = $this->db->insertId();
54
		$this->db->insert( 'wbt_term_in_lang',
55
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
56
		$termInLang1Id = $this->db->insertId();
57
		$this->db->insert( 'wbt_term_in_lang',
58
			[ 'wbtl_type_id' => self::TYPE_DESCRIPTION, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
59
		$termInLang2Id = $this->db->insertId();
60
		$this->db->insert( 'wbt_term_in_lang',
61
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang2Id ] );
62
		$termInLang3Id = $this->db->insertId();
63
64
		$resolver = new DatabaseTermIdsResolver(
65
			$this->typeIdsResolver,
66
			new FakeLoadBalancer( [
67
				'dbr' => $this->db,
68
			] )
69
		);
70
		$terms = $resolver->resolveTermIds( [ $termInLang1Id, $termInLang2Id, $termInLang3Id ] );
71
72
		$this->assertSame( [
73
			'label' => [
74
				'en' => [ 'text' ],
75
				'de' => [ 'Text' ],
76
			],
77
			'description' => [
78
				'en' => [ 'text' ],
79
			],
80
		], $terms );
81
	}
82
83
	public function testReadsEverythingFromReplicaIfPossible() {
84
		$this->db->insert( 'wbt_text',
85
			[ 'wbx_text' => 'text' ] );
86
		$text1Id = $this->db->insertId();
87
		$this->db->insert( 'wbt_text',
88
			[ 'wbx_text' => 'Text' ] );
89
		$text2Id = $this->db->insertId();
90
		$this->db->insert( 'wbt_text_in_lang',
91
			[ 'wbxl_language' => 'en', 'wbxl_text_id' => $text1Id ] );
92
		$textInLang1Id = $this->db->insertId();
93
		$this->db->insert( 'wbt_text_in_lang',
94
			[ 'wbxl_language' => 'de', 'wbxl_text_id' => $text2Id ] );
95
		$textInLang2Id = $this->db->insertId();
96
		$this->db->insert( 'wbt_term_in_lang',
97
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
98
		$termInLang1Id = $this->db->insertId();
99
		$this->db->insert( 'wbt_term_in_lang',
100
			[ 'wbtl_type_id' => self::TYPE_DESCRIPTION, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
101
		$termInLang2Id = $this->db->insertId();
102
		$this->db->insert( 'wbt_term_in_lang',
103
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang2Id ] );
104
		$termInLang3Id = $this->db->insertId();
105
106
		$dbw = $this->createMock( Database::class );
107
		$dbw->expects( $this->never() )->method( 'query' );
108
109
		$resolver = new DatabaseTermIdsResolver(
110
			$this->typeIdsResolver,
111
			new FakeLoadBalancer( [
112
				'dbr' => $this->db,
113
				'dbw' => $dbw,
114
			] )
115
		);
116
		$resolver->resolveTermIds( [ $termInLang1Id, $termInLang2Id, $termInLang3Id ] );
117
	}
118
119
	public function testFallsBackToMasterIfNecessaryAndAllowed() {
120
		$dbr = $this->db;
121
		$dbw = DatabaseSqlite::newStandaloneInstance( ':memory:' );
122
		$dbw->sourceFile( TermStoreSchemaUpdater::getSqlFileAbsolutePath() );
123
		// both master and replica have most of the data
124
		foreach ( [ $dbr, $dbw ] as $db ) {
125
			// note: we assume that both DBs get the same insert IDs
126
			$db->insert( 'wbt_text',
127
				[ 'wbx_text' => 'text' ] );
128
			$text1Id = $db->insertId();
129
			$db->insert( 'wbt_text',
130
				[ 'wbx_text' => 'Text' ] );
131
			$text2Id = $db->insertId();
132
			$db->insert( 'wbt_text_in_lang',
133
				[ 'wbxl_language' => 'en', 'wbxl_text_id' => $text1Id ] );
134
			$textInLang1Id = $db->insertId();
135
			$db->insert( 'wbt_text_in_lang',
136
				[ 'wbxl_language' => 'de', 'wbxl_text_id' => $text2Id ] );
137
			$textInLang2Id = $db->insertId();
138
			$db->insert( 'wbt_term_in_lang',
139
				[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
140
			$termInLang1Id = $db->insertId();
141
			$db->insert( 'wbt_term_in_lang',
142
				[ 'wbtl_type_id' => self::TYPE_DESCRIPTION, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
143
			$termInLang2Id = $db->insertId();
144
		}
145
		// only master has the last term_in_lang row
146
		$db->insert( 'wbt_term_in_lang',
0 ignored issues
show
Bug introduced by
The variable $db seems to be defined by a foreach iteration on line 124. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
147
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang2Id ] );
0 ignored issues
show
Bug introduced by
The variable $textInLang2Id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
148
		$termInLang3Id = $db->insertId();
149
150
		$resolver = new DatabaseTermIdsResolver(
151
			$this->typeIdsResolver,
152
			new FakeLoadBalancer( [
153
				'dbr' => $dbr,
154
				'dbw' => $dbw,
155
			] ),
156
			true
157
		);
158
		$terms = $resolver->resolveTermIds( [ $termInLang1Id, $termInLang2Id, $termInLang3Id ] );
0 ignored issues
show
Bug introduced by
The variable $termInLang1Id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $termInLang2Id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
159
160
		$this->assertSame( [
161
			'label' => [
162
				'en' => [ 'text' ],
163
				'de' => [ 'Text' ],
164
			],
165
			'description' => [
166
				'en' => [ 'text' ],
167
			],
168
		], $terms );
169
	}
170
171
	public function testDoesNotFallBackToMasterIfNotAllowed() {
172
		$dbr = $this->db;
173
		$dbw = DatabaseSqlite::newStandaloneInstance( ':memory:' );
174
		$dbw->sourceFile( TermStoreSchemaUpdater::getSqlFileAbsolutePath() );
175
		// both master and replica have most of the data
176
		foreach ( [ $dbr, $dbw ] as $db ) {
177
			// note: we assume that both DBs get the same insert IDs
178
			$db->insert( 'wbt_text',
179
				[ 'wbx_text' => 'text' ] );
180
			$text1Id = $db->insertId();
181
			$db->insert( 'wbt_text',
182
				[ 'wbx_text' => 'Text' ] );
183
			$text2Id = $db->insertId();
184
			$db->insert( 'wbt_text_in_lang',
185
				[ 'wbxl_language' => 'en', 'wbxl_text_id' => $text1Id ] );
186
			$textInLang1Id = $db->insertId();
187
			$db->insert( 'wbt_text_in_lang',
188
				[ 'wbxl_language' => 'de', 'wbxl_text_id' => $text2Id ] );
189
			$textInLang2Id = $db->insertId();
190
			$db->insert( 'wbt_term_in_lang',
191
				[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
192
			$termInLang1Id = $db->insertId();
193
			$db->insert( 'wbt_term_in_lang',
194
				[ 'wbtl_type_id' => self::TYPE_DESCRIPTION, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
195
			$termInLang2Id = $db->insertId();
196
		}
197
		// only master has the last term_in_lang row
198
		$db->insert( 'wbt_term_in_lang',
0 ignored issues
show
Bug introduced by
The variable $db seems to be defined by a foreach iteration on line 176. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
199
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang2Id ] );
0 ignored issues
show
Bug introduced by
The variable $textInLang2Id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
200
		$termInLang3Id = $db->insertId();
201
202
		$resolver = new DatabaseTermIdsResolver(
203
			$this->typeIdsResolver,
204
			new FakeLoadBalancer( [
205
				'dbr' => $dbr,
206
				'dbw' => $dbw,
207
			] ),
208
			false
209
		);
210
		$terms = $resolver->resolveTermIds( [ $termInLang1Id, $termInLang2Id, $termInLang3Id ] );
0 ignored issues
show
Bug introduced by
The variable $termInLang1Id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $termInLang2Id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
211
212
		$this->assertSame( [
213
			'label' => [
214
				'en' => [ 'text' ],
215
				// 'de' => [ 'Text' ], // this is the row missing from the replica
216
			],
217
			'description' => [
218
				'en' => [ 'text' ],
219
			],
220
		], $terms );
221
	}
222
223
}
224