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

LeankoalaReporter   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 6
Bugs 0 Features 1
Metric Value
wmc 32
c 6
b 0
f 1
lcom 1
cbo 13
dl 0
loc 239
rs 9.6

10 Methods

Rating   Name   Duplication   Size   Complexity  
B init() 0 29 3
A setResponseRetriever() 0 4 1
A processResults() 0 4 1
A finish() 0 8 2
A getComponent() 0 7 1
C sendCollectedResults() 0 47 10
C sendSingleResults() 0 48 7
A getIdentifier() 0 4 1
A getPrefix() 0 4 1
B send() 0 21 5
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