Completed
Pull Request — master (#30)
by Alaa
01:52
created

testReadsEverythingFromReplicaIfPossible()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 9.36
c 0
b 0
f 0
cc 1
nc 1
nop 0
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
	/** @var ILoadBalancer */
32
	private $loadBalancer;
33
34
	public function setUp() {
35
		$this->typeIdsResolver = new StaticTypeIdsStore( [
36
			'label' => self::TYPE_LABEL,
37
			'description' => self::TYPE_DESCRIPTION,
38
			'alias' => self::TYPE_ALIAS,
39
		] );
40
		$this->db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
41
		$this->db->sourceFile( TermStoreSchemaUpdater::getSqlFileAbsolutePath() );
42
		$this->loadBalancer = new FakeLoadBalancer( [
43
			'dbr' => $this->db,
44
		] );
45
	}
46
47
	public function testCanResolveEverything() {
48
		$this->db->insert( 'wbt_text',
49
			[ 'wbx_text' => 'text' ] );
50
		$text1Id = $this->db->insertId();
51
		$this->db->insert( 'wbt_text',
52
			[ 'wbx_text' => 'Text' ] );
53
		$text2Id = $this->db->insertId();
54
		$this->db->insert( 'wbt_text_in_lang',
55
			[ 'wbxl_language' => 'en', 'wbxl_text_id' => $text1Id ] );
56
		$textInLang1Id = $this->db->insertId();
57
		$this->db->insert( 'wbt_text_in_lang',
58
			[ 'wbxl_language' => 'de', 'wbxl_text_id' => $text2Id ] );
59
		$textInLang2Id = $this->db->insertId();
60
		$this->db->insert( 'wbt_term_in_lang',
61
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
62
		$termInLang1Id = $this->db->insertId();
63
		$this->db->insert( 'wbt_term_in_lang',
64
			[ 'wbtl_type_id' => self::TYPE_DESCRIPTION, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
65
		$termInLang2Id = $this->db->insertId();
66
		$this->db->insert( 'wbt_term_in_lang',
67
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang2Id ] );
68
		$termInLang3Id = $this->db->insertId();
69
70
		$resolver = new DatabaseTermIdsResolver( $this->typeIdsResolver, $this->loadBalancer );
71
		$terms = $resolver->resolveTermIds( [ $termInLang1Id, $termInLang2Id, $termInLang3Id ] );
72
73
		$this->assertSame( [
74
			'label' => [
75
				'en' => [ 'text' ],
76
				'de' => [ 'Text' ],
77
			],
78
			'description' => [
79
				'en' => [ 'text' ],
80
			],
81
		], $terms );
82
	}
83
84
	public function testReadsEverythingFromReplicaIfPossible() {
85
		$this->db->insert( 'wbt_text',
86
			[ 'wbx_text' => 'text' ] );
87
		$text1Id = $this->db->insertId();
88
		$this->db->insert( 'wbt_text',
89
			[ 'wbx_text' => 'Text' ] );
90
		$text2Id = $this->db->insertId();
91
		$this->db->insert( 'wbt_text_in_lang',
92
			[ 'wbxl_language' => 'en', 'wbxl_text_id' => $text1Id ] );
93
		$textInLang1Id = $this->db->insertId();
94
		$this->db->insert( 'wbt_text_in_lang',
95
			[ 'wbxl_language' => 'de', 'wbxl_text_id' => $text2Id ] );
96
		$textInLang2Id = $this->db->insertId();
97
		$this->db->insert( 'wbt_term_in_lang',
98
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
99
		$termInLang1Id = $this->db->insertId();
100
		$this->db->insert( 'wbt_term_in_lang',
101
			[ 'wbtl_type_id' => self::TYPE_DESCRIPTION, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
102
		$termInLang2Id = $this->db->insertId();
103
		$this->db->insert( 'wbt_term_in_lang',
104
			[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang2Id ] );
105
		$termInLang3Id = $this->db->insertId();
106
107
		$dbw = $this->createMock( Database::class );
108
		$dbw->expects( $this->never() )->method( 'query' );
109
110
		$resolver = new DatabaseTermIdsResolver(
111
			$this->typeIdsResolver,
112
			new FakeLoadBalancer( [
113
				'dbr' => $this->db,
114
				'dbw' => $dbw,
115
			] )
116
		);
117
		$resolver->resolveTermIds( [ $termInLang1Id, $termInLang2Id, $termInLang3Id ] );
118
	}
119
120
	public function testFallsBackToMasterIfNecessary() {
121
		$dbr = $this->db;
122
		$dbw = DatabaseSqlite::newStandaloneInstance( ':memory:' );
123
		$dbw->sourceFile( TermStoreSchemaUpdater::getSqlFileAbsolutePath() );
124
		// both master and replica have most of the data
125
		foreach ( [ $dbr, $dbw ] as $db ) {
126
			// note: we assume that both DBs get the same insert IDs
127
			$db->insert( 'wbt_text',
128
				[ 'wbx_text' => 'text' ] );
129
			$text1Id = $db->insertId();
130
			$db->insert( 'wbt_text',
131
				[ 'wbx_text' => 'Text' ] );
132
			$text2Id = $db->insertId();
133
			$db->insert( 'wbt_text_in_lang',
134
				[ 'wbxl_language' => 'en', 'wbxl_text_id' => $text1Id ] );
135
			$textInLang1Id = $db->insertId();
136
			$db->insert( 'wbt_text_in_lang',
137
				[ 'wbxl_language' => 'de', 'wbxl_text_id' => $text2Id ] );
138
			$textInLang2Id = $db->insertId();
139
			$db->insert( 'wbt_term_in_lang',
140
				[ 'wbtl_type_id' => self::TYPE_LABEL, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
141
			$termInLang1Id = $db->insertId();
142
			$db->insert( 'wbt_term_in_lang',
143
				[ 'wbtl_type_id' => self::TYPE_DESCRIPTION, 'wbtl_text_in_lang_id' => $textInLang1Id ] );
144
			$termInLang2Id = $db->insertId();
145
		}
146
		// only master has the last term_in_lang row
147
		$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 125. 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...
148
			[ '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...
149
		$termInLang3Id = $db->insertId();
150
151
		$resolver = new DatabaseTermIdsResolver(
152
			$this->typeIdsResolver,
153
			new FakeLoadBalancer( [
154
				'dbr' => $dbr,
155
				'dbw' => $dbw,
156
			] )
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
}
172