Completed
Push — master ( a44523...85e5eb )
by Nils
01:57
created

LeankoalaReporter::send()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 21
rs 8.7624
cc 5
eloc 15
nc 7
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace whm\Smoke\Extensions\SmokeReporter\Reporter;
4
5
use Koalamon\Client\Reporter\Event;
6
use Koalamon\Client\Reporter\Event\Attribute;
7
use Koalamon\Client\Reporter\Event\Processor\MongoDBProcessor;
8
use Koalamon\Client\Reporter\KoalamonException;
9
use Koalamon\Client\Reporter\Reporter as KoalaReporter;
10
use Symfony\Component\Console\Output\OutputInterface;
11
use whm\Smoke\Config\Configuration;
12
use whm\Smoke\Extensions\Leankoala\LeankoalaExtension;
13
use whm\Smoke\Extensions\SmokeResponseRetriever\Retriever\Retriever;
14
use whm\Smoke\Rules\CheckResult;
15
use whm\Smoke\Scanner\Result;
16
17
/**
18
 * Class XUnitReporter.
19
 */
20
class LeankoalaReporter implements Reporter
21
{
22
    /**
23
     * @var Result[]
24
     */
25
    private $results = [];
26
27
    /**
28
     * @var Configuration
29
     */
30
    private $config;
31
    private $system;
32
    private $collect;
33
    private $identifier;
34
    private $systemUseRetriever;
35
    private $tool = 'smoke';
36
    private $groupBy;
37
    private $server;
38
    private $addComingFrom;
39
40
    /**
41
     * @var KoalaReporter
42
     */
43
    private $reporter;
44
45
    /**
46
     * @var Retriever
47
     */
48
    private $retriever;
49
50
    /**
51
     * @var OutputInterface
52
     */
53
    private $output;
54
55
    /**
56
     * @var LeankoalaExtension
57
     */
58
    private $leankoalaExtension;
59
60
    const STATUS_SUCCESS = 'success';
61
    const STATUS_FAILURE = 'failure';
62
63
    public function init($apiKey, Configuration $_configuration, OutputInterface $_output, $server = 'https://webhook.koalamon.com', $system = '', $identifier = '', $tool = '', $collect = true, $systemUseRetriever = false, $groupBy = false, $addComingFrom = true, $useMongo = true)
64
    {
65
        $httpClient = new \GuzzleHttp\Client();
66
67
        $this->reporter = new KoalaReporter('', $apiKey, $httpClient, $server);
68
69
        if ($useMongo) {
70
            $this->reporter->setEventProcessor(MongoDBProcessor::createByEnvironmentVars('leankoala'));
71
        }
72
73
        $this->config = $_configuration;
74
        $this->systemUseRetriever = $systemUseRetriever;
75
76
        $this->system = $system;
77
        $this->collect = $collect;
78
        $this->identifier = $identifier;
79
        $this->groupBy = $groupBy;
80
81
        $this->addComingFrom = $addComingFrom;
82
83
        if ($tool) {
84
            $this->tool = $tool;
85
        }
86
87
        $this->leankoalaExtension = $_configuration->getExtension('Leankoala');
88
89
        $this->server = $server;
90
        $this->output = $_output;
91
    }
92
93
    public function setResponseRetriever(Retriever $retriever)
94
    {
95
        $this->retriever = $retriever;
96
    }
97
98
    public function processResults($results)
99
    {
100
        $this->results[] = $results;
101
    }
102
103
    public function finish()
104
    {
105
        if ($this->collect) {
106
            $this->sendCollectedResults();
107
        } else {
108
            $this->sendSingleResults();
109
        }
110
    }
111
112
    private function getComponent($ruleName)
113
    {
114
        $ruleArray = explode('_', $ruleName);
115
        $component = array_pop($ruleArray);
116
117
        return $component;
118
    }
119
120
    private function sendCollectedResults()
121
    {
122
        $checks = [];
123
124
        foreach ($this->results as $results) {
125
            foreach ($results as $result) {
0 ignored issues
show
Bug introduced by
The expression $results of type object<whm\Smoke\Scanner\Result> is not traversable.
Loading history...
126
                /* @var CheckResult $result */
127
                $tool = 'Smoke' . $result->getRuleName();
128
                $checks[$tool][] = $result;
129
            }
130
        }
131
132
        foreach ($checks as $toolName => $results) {
133
            $attributes = array();
134
135
            if (count($results) === 0) {
136
                continue;
137
            }
138
139
            $message = 'The smoke test for #system_name# failed (Rule: ' . $toolName . ').<ul>';
140
            $status = Event::STATUS_SUCCESS;
141
            $failureCount = 0;
142
            $identifier = $toolName . '_' . $this->system;
143
144
            foreach ($results as $result) {
145
                /** @var CheckResult $result */
146
                if ($result->getStatus() === CheckResult::STATUS_FAILURE) {
147
                    $comingFrom = '';
148
                    if ($this->addComingFrom && $this->retriever->getComingFrom($result->getResponse()->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.

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...
149
                        $comingFrom = ', coming from: ' . $this->retriever->getComingFrom($result->getResponse()->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.

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...
150
                    }
151
                    $message .= '<li>' . $result->getMessage() . ' (url: ' . (string)$result->getResponse()->getUri() . $comingFrom . ')</li>';
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.

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...
152
                    ++$failureCount;
153
                }
154
            }
155
            if ($failureCount > 0) {
156
                $status = Event::STATUS_FAILURE;
157
                $message .= '</ul>';
158
                $firstResult = array_pop($results);
159
                $attributes[] = new Attribute('html-content', (string)$firstResult->getResponse()->getBody(), true);
160
            } else {
161
                $message = 'All checks for system "#system_name#" succeeded [SmokeBasic:' . $toolName . '].';
162
            }
163
164
            $this->send($identifier, $this->system, $message, $status, $failureCount, $this->tool, $this->system, $attributes);
165
        }
166
    }
167
168
    private function sendSingleResults()
169
    {
170
        foreach ($this->results as $results) {
171
            foreach ($results as $result) {
0 ignored issues
show
Bug introduced by
The expression $results of type object<whm\Smoke\Scanner\Result> is not traversable.
Loading history...
172
                /* @var CheckResult $result */
173
174
                $identifier = '_' . $this->getIdentifier($result);
175
                $tool = $this->getPrefix($result->getRuleName());
176
177
                $component = $this->getComponent($result->getRuleName());
178
                $system = $this->leankoalaExtension->getSystem($component);
179
180
                $attributes = array();
181
                if ($result->getStatus() == CheckResult::STATUS_FAILURE) {
182
                    $body = (string)$result->getResponse()->getBody();
183
                    if ($body == "") {
184
                        $attributes[] = new Attribute('html content', '<empty>');
185
                    } else {
186
                        $attributes[] = new Attribute('html content', $body, true);
187
                    }
188
                    $attributes[] = new Attribute('http header', json_encode($result->getResponse()->getHeaders()), true);
189
                    $attributes[] = new Attribute('http status code', $result->getResponse()->getStatusCode());
190
                }
191
192
                $checkResultAttributes = $result->getAttributes();
193
                foreach ($checkResultAttributes as $checkResultAttribute) {
194
                    $attributes[] = new Attribute($checkResultAttribute->getKey(), $checkResultAttribute->getValue(), $checkResultAttribute->isIsStorable());
195
                }
196
197
                if ($this->system) {
198
                    $currentSystem = $this->system;
199
                } else {
200
                    $currentSystem = $system;
201
                }
202
203
                $this->send(
204
                    $identifier,
205
                    $currentSystem,
206
                    $result->getMessage() . ' (url: ' . (string)$result->getResponse()->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.

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...
207
                    $result->getStatus(),
208
                    $result->getValue(),
209
                    $tool,
210
                    $component,
211
                    $attributes
212
                );
213
            }
214
        }
215
    }
216
217
    private function getIdentifier(CheckResult $result)
218
    {
219
        return $this->tool . '_' . $result->getRuleName();
220
    }
221
222
    private function getPrefix($string)
223
    {
224
        return substr($string, 0, strpos($string, '_'));
225
    }
226
227
    /**
228
     * @param $identifier
229
     * @param $system
230
     * @param $message
231
     * @param $status
232
     * @param $value
233
     * @param $tool
234
     * @param $component
235
     * @param Attribute[] $attributes
236
     */
237
    private function send($identifier, $system, $message, $status, $value, $tool, $component, $attributes = [])
238
    {
239
        if ($status !== CheckResult::STATUS_NONE) {
240
            $event = new Event($identifier, $system, $status, $tool, $message, $value, '', $component);
241
            $event->addAttribute(new Attribute('_config', json_encode($this->config->getConfigArray()), true));
242
            foreach ($attributes as $attribute) {
243
                $event->addAttribute($attribute);
244
            }
245
246
            try {
247
                $this->reporter->sendEvent($event);
248
            } catch (KoalamonException $e) {
249
                $this->output->writeln("\n  <error> Error sending result to leankoala. </error>");
250
                $this->output->writeln('   Url: ' . $e->getUrl());
251
                $this->output->writeln('   Payload: ' . $e->getPayload());
252
                $this->output->writeln("");
253
            } catch (\Exception $e) {
254
                $this->output->writeln($e->getMessage());
255
            }
256
        }
257
    }
258
}
259