Completed
Push — master ( 2d413b...465ef9 )
by Nils
02:33
created

RedirectRule::removeCredentials()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
namespace whm\Smoke\Rules\Http;
4
5
use GuzzleHttp\Psr7\Request;
6
use phm\HttpWebdriverClient\Http\Client\Guzzle\GuzzleClient;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\UriInterface;
9
use whm\Html\Uri;
10
use whm\Smoke\Rules\CheckResult;
11
use whm\Smoke\Rules\Rule;
12
13
/**
14
 * This rule can validate if a http request takes longer than a given max duration.
15
 * A website that is slower than one second is considered as slow.
16
 */
17
class RedirectRule implements Rule
18
{
19
    private $urls;
20
21
    public function init($redirectedUrls)
22
    {
23
        $this->urls = $redirectedUrls;
24
    }
25
26
    public function validate(ResponseInterface $response)
27
    {
28
        $client = new GuzzleClient();
29
        $errors = [];
30
31
        $targetUrl = (string)$this->removeCredentials($response->getUri());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method getUri() does only exist in the following implementations of said interface: phm\HttpWebdriverClient\...t\Chrome\ChromeResponse, phm\HttpWebdriverClient\...t\Guzzle\GuzzleResponse, phm\HttpWebdriverClient\...\Client\Guzzle\Response, phm\HttpWebdriverClient\...esponse\BrowserResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
32
33
34
        foreach ($this->urls as $url) {
35
            $uri = new Uri($url['url']);
36
37
            $urlResponses = $client->sendRequests([new Request('GET', $uri)]);
38
            $effectiveUrl = (string)$urlResponses[0]->getEffectiveUri();
39
40
            if ($effectiveUrl != $targetUrl) {
41
                $errors[] = 'The url "' . $url['url'] . '" gets redirected to "' . $effectiveUrl . '".';
42
            }
43
        }
44
45
        if (count($errors) > 0) {
46
            $message = 'Not all given urls do redirect to "' . $targetUrl . '"".<ul>';
47
            foreach ($errors as $error) {
48
                $message .= '<li>' . $error . '</li>';
49
            }
50
            $message .= "</ul>";
51
52
            return new CheckResult(CheckResult::STATUS_FAILURE, $message);
53
        } else {
54
            return new CheckResult(CheckResult::STATUS_SUCCESS, 'All given urls redirect to ' . (string)$response->getUri());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method getUri() does only exist in the following implementations of said interface: phm\HttpWebdriverClient\...t\Chrome\ChromeResponse, phm\HttpWebdriverClient\...t\Guzzle\GuzzleResponse, phm\HttpWebdriverClient\...\Client\Guzzle\Response, phm\HttpWebdriverClient\...esponse\BrowserResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
55
        }
56
    }
57
58
    private function removeCredentials(UriInterface $uri)
59
    {
60
        $query = '';
61
        if ($uri->getQuery()) {
62
            $query = "?" . $uri->getQuery();
63
        }
64
65
        $plainUri = $uri->getScheme() . '://' . $uri->getHost() . $uri->getPath() . $query;
66
67
        return new Uri($plainUri);
68
    }
69
}
70