KoalamonReporter::finish()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
namespace whm\Smoke\Extensions\SmokeReporter\Reporter;
4
5
use Koalamon\Client\Reporter\Event;
6
use Koalamon\Client\Reporter\WebhookReporter as KoalaReporter;
7
use Symfony\Component\Console\Output\OutputInterface;
8
use whm\Html\Uri;
9
use whm\Smoke\Config\Configuration;
10
use whm\Smoke\Extensions\SmokeResponseRetriever\Retriever\Retriever;
11
use whm\Smoke\Scanner\Result;
12
13
/**
14
 * Class XUnitReporter.
15
 */
16
class KoalamonReporter implements Reporter
0 ignored issues
show
Bug introduced by
There is one abstract method processResults in this class; you could implement it, or declare this class as abstract.
Loading history...
17
{
18
    /**
19
     * @var Result[]
20
     */
21
    private $results = [];
22
23
    private $config;
24
    private $system;
25
    private $collect;
26
    private $identifier;
27
    private $systemUseRetriever;
28
    private $tool = 'smoke';
29
    private $groupBy;
30
    private $server;
31
    private $addComingFrom;
32
33
    /**
34
     * @var KoalaReporter
35
     */
36
    private $reporter;
37
38
    /*
39
     * @var Retriever
40
     */
41
    private $retriever;
42
43
    private $output;
44
45
    const STATUS_SUCCESS = 'success';
46
    const STATUS_FAILURE = 'failure';
47
48
    public function init($apiKey, Configuration $_configuration, OutputInterface $_output, $server = 'https://webhook.koalamon.com', $system = '', $identifier = '', $tool = '', $collect = true, $systemUseRetriever = false, $groupBy = false, $addComingFrom = true)
49
    {
50
        $httpClient = new \GuzzleHttp\Client();
51
        $this->reporter = new KoalaReporter('', $apiKey, $httpClient, $server);
52
53
        $this->config = $_configuration;
54
        $this->systemUseRetriever = $systemUseRetriever;
55
56
        $this->system = $system;
57
        $this->collect = $collect;
58
        $this->identifier = $identifier;
59
        $this->groupBy = $groupBy;
60
61
        $this->addComingFrom = $addComingFrom;
62
63
        if ($tool) {
64
            $this->tool = $tool;
65
        }
66
67
        $this->server = $server;
68
        $this->output = $_output;
69
    }
70
71
    public function setResponseRetriever(Retriever $retriever)
72
    {
73
        $this->retriever = $retriever;
74
    }
75
76
    /**
77
     * @param Rule [];
78
     *
79
     * @return array
80
     */
81
    private function getRuleKeys()
82
    {
83
        $keys = array();
84
        foreach ($this->config->getRules() as $key => $rule) {
85
            $keys[] = $key;
86
        }
87
88
        return $keys;
89
    }
90
91
    public function processResult(Result $result)
92
    {
93
        $this->results[] = $result;
94
    }
95
96
    public function finish()
97
    {
98
        $this->output->writeln('Sending results to ' . $this->server . " ... \n");
99
100
        if ($this->groupBy === 'prefix') {
101
            $this->sendGroupedByPrefix();
102
        } else {
103
            if ($this->collect) {
104
                $this->sendCollected();
105
            } else {
106
                $this->sendSingle();
107
            }
108
        }
109
    }
110
111
    private function getPrefix($string)
112
    {
113
        return substr($string, 0, strpos($string, '_'));
114
    }
115
116
    private function sendGroupedByPrefix()
117
    {
118
        $failureMessages = array();
119
        $counter = array();
120
121
        if ($this->systemUseRetriever) {
122
            $systems = $this->retriever->getSystems();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface whm\Smoke\Extensions\Smo...ver\Retriever\Retriever as the method getSystems() does only exist in the following implementations of said interface: whm\Smoke\Extensions\Smo...ever\Koalamon\Retriever, whm\Smoke\Extensions\Smo...ListRetriever\Retriever.

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...
123
        } else {
124
            $systems = array($this->system);
125
        }
126
127
        foreach ($this->getRuleKeys() as $rule) {
128
            foreach ($systems as $system) {
129
                $identifier = $this->tool . '_' . $this->getPrefix($rule) . '_' . $system;
130
                $failureMessages[$identifier]['message'] = '';
131
                $failureMessages[$identifier]['system'] = $system;
132
                $failureMessages[$identifier]['tool'] = $this->getPrefix($rule);
133
134
                $counter[$identifier] = 0;
135
            }
136
        }
137
138
        foreach ($this->results as $result) {
139
            if ($result->isFailure()) {
140
                foreach ($result->getMessages() as $ruleLKey => $message) {
141
                    $system = $this->system;
142
                    if ($this->systemUseRetriever) {
143
                        $system = $this->retriever->getSystem(($result->getUrl()));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface whm\Smoke\Extensions\Smo...ver\Retriever\Retriever as the method getSystem() does only exist in the following implementations of said interface: whm\Smoke\Extensions\Smo...ListRetriever\Retriever.

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...
144
                    }
145
146
                    $identifer = $this->tool . '_' . $this->getPrefix($ruleLKey) . '_' . $system;
147
148
                    if ($failureMessages[$identifer]['message'] === '') {
149
                        $failureMessages[$identifer]['message'] = 'The ' . $this->getPrefix($ruleLKey) . ' test for #system_name# failed.<ul>';
150
                    }
151
                    ++$counter[$identifer];
152
                    $message = '<li>' . $message . '<br>url: ' . $result->getUrl();
153
                    if ($this->addComingFrom) {
154
                        $message .= ', coming from: ' . $this->retriever->getComingFrom($result->getUrl());
155
                    }
156
                    $message .= '</li>';
157
                    $failureMessages[$identifer]['message'] .= $message;
158
                }
159
            }
160
        }
161
162
        foreach ($failureMessages as $key => $failureMessage) {
163
            if ($failureMessage['message'] !== '') {
164
                $this->send($this->identifier . '_' . $key, $failureMessage['system'], $failureMessage['message'] . '</ul>', self::STATUS_FAILURE, '', $counter[$key], $failureMessage['tool']);
165
            } else {
166
                $this->send($this->identifier . '_' . $key, $failureMessage['system'], '', self::STATUS_SUCCESS, '', 0, $failureMessage['tool']);
167
            }
168
        }
169
    }
170
171
    private function sendSingle()
172
    {
173
        $rules = $this->getRuleKeys();
174
        foreach ($this->results as $result) {
175
            $failedTests = array();
176
            if ($result->isFailure()) {
177
                foreach ($result->getMessages() as $ruleLKey => $message) {
178
                    $identifier = 'smoke_' . $ruleLKey . '_' . $result->getUrl();
179
180
                    if ($this->system === '') {
181
                        $system = str_replace('http://', '', $result->getUrl());
182
                    } else {
183
                        $system = $this->system;
184
                    }
185
                    $this->send($identifier, $system, 'smoke', $message, self::STATUS_FAILURE, (string) $result->getUrl());
186
                    $failedTests[] = $ruleLKey;
187
                }
188
            }
189
            foreach ($rules as $rule) {
190
                if (!in_array($rule, $failedTests, true)) {
191
                    $identifier = 'smoke_' . $rule . '_' . $result->getUrl();
192
193
                    if ($this->systemUseRetriever) {
194
                        $system = $this->retriever->getSystem($result->getUrl());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface whm\Smoke\Extensions\Smo...ver\Retriever\Retriever as the method getSystem() does only exist in the following implementations of said interface: whm\Smoke\Extensions\Smo...ListRetriever\Retriever.

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...
195
                    } elseif ($this->system === '') {
196
                        $system = str_replace('http://', '', $result->getUrl());
197
                    } else {
198
                        $system = $this->system;
199
                    }
200
                    $this->send($identifier, $system, 'smoke_' . $rule . '_' . $result->getUrl(), self::STATUS_SUCCESS, (string) $result->getUrl());
201
                }
202
            }
203
        }
204
    }
205
206
    private function sendCollected()
207
    {
208
        $failureMessages = array();
209
        $counter = array();
210
211
        foreach ($this->getRuleKeys() as $rule) {
212
            $failureMessages[$rule] = '';
213
            $counter[$rule] = 0;
214
        }
215
216
        foreach ($this->results as $result) {
217
            if ($result->isFailure()) {
218
                foreach ($result->getMessages() as $ruleLKey => $message) {
219
                    $system = $this->system;
220
                    if ($this->systemUseRetriever) {
221
                        $system = $this->retriever->getSystem(new Uri($result->getUrl()));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface whm\Smoke\Extensions\Smo...ver\Retriever\Retriever as the method getSystem() does only exist in the following implementations of said interface: whm\Smoke\Extensions\Smo...ListRetriever\Retriever.

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...
222
                    }
223
                    if ($failureMessages[$ruleLKey] === '') {
224
                        $failureMessages[$ruleLKey]['message'] = '    The smoke test for #system_name# failed (Rule: ' . $ruleLKey . ').<ul>';
225
                    }
226
                    ++$counter[$ruleLKey];
227
228
                    $comingFrom = '';
229
230
                    if ($this->addComingFrom && $this->retriever->getComingFrom($result->getUrl())) {
231
                        $comingFrom = ', coming from: ' . $this->retriever->getComingFrom($result->getUrl());
232
                    }
233
234
                    $failureMessages[$ruleLKey]['message'] .= '<li>' . $message . ' (url: ' . $result->getUrl() . $comingFrom . ')</li > ';
235
                    $failureMessages[$ruleLKey]['system'] = $system;
236
                }
237
            }
238
        }
239
240
        foreach ($failureMessages as $key => $failureMessage) {
241
            if ($failureMessage !== '') {
242
                $this->send($this->identifier . '_' . $key, $this->system, $failureMessage['message'] . ' </ul > ', self::STATUS_FAILURE, '', $counter[$key]);
243
            } else {
244
                $this->send($this->identifier . '_' . $key, $this->system, '', self::STATUS_SUCCESS, '', 0);
245
            }
246
        }
247
    }
248
249
    private function send($identifier, $system, $message, $status, $url = '', $value = 0, $tool = null)
0 ignored issues
show
Unused Code introduced by
The parameter $url is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
250
    {
251
        if (is_null($tool)) {
252
            $tool = $this->tool;
253
        }
254
        $event = new Event($identifier, $system, $status, $tool, $message, $value);
255
256
        $this->reporter->sendEvent($event);
257
    }
258
}
259