Completed
Push — master ( d3eeb5...4b4eb0 )
by Nils
01:58
created

LeankoalaReporter::sendSingleResults()   C

Complexity

Conditions 7
Paths 14

Size

Total Lines 48
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 48
rs 6.7272
cc 7
eloc 32
nc 14
nop 0
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\Reporter as KoalaReporter;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use whm\Smoke\Config\Configuration;
11
use whm\Smoke\Extensions\Leankoala\LeankoalaExtension;
12
use whm\Smoke\Extensions\SmokeResponseRetriever\Retriever\Retriever;
13
use whm\Smoke\Rules\CheckResult;
14
use whm\Smoke\Scanner\Result;
15
16
/**
17
 * Class XUnitReporter.
18
 */
19
class LeankoalaReporter implements Reporter
20
{
21
    /**
22
     * @var Result[]
23
     */
24
    private $results = [];
25
26
    /**
27
     * @var Configuration
28
     */
29
    private $config;
30
    private $system;
31
    private $collect;
32
    private $identifier;
33
    private $systemUseRetriever;
34
    private $tool = 'smoke';
35
    private $groupBy;
36
    private $server;
37
    private $addComingFrom;
38
39
    /**
40
     * @var KoalaReporter
41
     */
42
    private $reporter;
43
44
    /**
45
     * @var Retriever
46
     */
47
    private $retriever;
48
49
    private $output;
50
51
    /**
52
     * @var LeankoalaExtension
53
     */
54
    private $leankoalaExtension;
55
56
    const STATUS_SUCCESS = 'success';
57
    const STATUS_FAILURE = 'failure';
58
59
    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)
60
    {
61
        $httpClient = new \GuzzleHttp\Client();
62
63
        $this->reporter = new KoalaReporter('', $apiKey, $httpClient, $server);
64
65
        if ($useMongo) {
66
            $this->reporter->setEventProcessor(MongoDBProcessor::createByEnvironmentVars('leankoala'));
67
        }
68
69
        $this->config = $_configuration;
70
        $this->systemUseRetriever = $systemUseRetriever;
71
72
        $this->system = $system;
73
        $this->collect = $collect;
74
        $this->identifier = $identifier;
75
        $this->groupBy = $groupBy;
76
77
        $this->addComingFrom = $addComingFrom;
78
79
        if ($tool) {
80
            $this->tool = $tool;
81
        }
82
83
        $this->leankoalaExtension = $_configuration->getExtension('Leankoala');
84
85
        $this->server = $server;
86
        $this->output = $_output;
87
    }
88
89
    public function setResponseRetriever(Retriever $retriever)
90
    {
91
        $this->retriever = $retriever;
92
    }
93
94
    public function processResults($results)
95
    {
96
        $this->results[] = $results;
97
    }
98
99
    public function finish()
100
    {
101
        if ($this->collect) {
102
            $this->sendCollectedResults();
103
        } else {
104
            $this->sendSingleResults();
105
        }
106
    }
107
108
    private function getComponent($ruleName)
109
    {
110
        $ruleArray = explode('_', $ruleName);
111
        $component = array_pop($ruleArray);
112
113
        return $component;
114
    }
115
116
    private function sendCollectedResults()
117
    {
118
        $checks = [];
119
120
        foreach ($this->results as $results) {
121
            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...
122
                /* @var CheckResult $result */
123
                $tool = 'Smoke' . $result->getRuleName();
124
                $checks[$tool][] = $result;
125
            }
126
        }
127
128
        foreach ($checks as $toolName => $results) {
129
            $attributes = array();
130
131
            if (count($results) === 0) {
132
                continue;
133
            }
134
135
            $message = 'The smoke test for #system_name# failed (Rule: ' . $toolName . ').<ul>';
136
            $status = Event::STATUS_SUCCESS;
137
            $failureCount = 0;
138
            $identifier = $toolName . '_' . $this->system;
139
140
            foreach ($results as $result) {
141
                /** @var CheckResult $result */
142
                if ($result->getStatus() === CheckResult::STATUS_FAILURE) {
143
                    $comingFrom = '';
144
                    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...
145
                        $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...
146
                    }
147
                    $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...
148
                    ++$failureCount;
149
                }
150
            }
151
            if ($failureCount > 0) {
152
                $status = Event::STATUS_FAILURE;
153
                $message .= '</ul>';
154
                $firstResult = array_pop($results);
155
                $attributes[] = new Attribute('html-content', (string)$firstResult->getResponse()->getBody(), true);
156
            } else {
157
                $message = 'All checks for system "#system_name#" succeeded [SmokeBasic:' . $toolName . '].';
158
            }
159
160
            $this->send($identifier, $this->system, $message, $status, $failureCount, $this->tool, $this->system, $attributes);
161
        }
162
    }
163
164
    private function sendSingleResults()
165
    {
166
        foreach ($this->results as $results) {
167
            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...
168
                /* @var CheckResult $result */
169
170
                $identifier = '_' . $this->getIdentifier($result);
171
                $tool = $this->getPrefix($result->getRuleName());
172
173
                $component = $this->getComponent($result->getRuleName());
174
                $system = $this->leankoalaExtension->getSystem($component);
175
176
                $attributes = array();
177
                if ($result->getStatus() == CheckResult::STATUS_FAILURE) {
178
                    $body = (string)$result->getResponse()->getBody();
179
                    if ($body == "") {
180
                        $attributes[] = new Attribute('html content', '<empty>');
181
                    } else {
182
                        $attributes[] = new Attribute('html content', $body, true);
183
                    }
184
                    $attributes[] = new Attribute('http header', json_encode($result->getResponse()->getHeaders()), true);
185
                    $attributes[] = new Attribute('http status code', $result->getResponse()->getStatusCode());
186
                }
187
188
                $checkResultAttributes = $result->getAttributes();
189
                foreach ($checkResultAttributes as $checkResultAttribute) {
190
                    $attributes[] = new Attribute($checkResultAttribute->getKey(), $checkResultAttribute->getValue(), $checkResultAttribute->isIsStorable());
191
                }
192
193
                if ($this->system) {
194
                    $currentSystem = $this->system;
195
                } else {
196
                    $currentSystem = $system;
197
                }
198
199
                $this->send(
200
                    $identifier,
201
                    $currentSystem,
202
                    $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...
203
                    $result->getStatus(),
204
                    $result->getValue(),
205
                    $tool,
206
                    $component,
207
                    $attributes
208
                );
209
            }
210
        }
211
    }
212
213
    private function getIdentifier(CheckResult $result)
214
    {
215
        return $this->tool . '_' . $result->getRuleName();
216
    }
217
218
    private function getPrefix($string)
219
    {
220
        return substr($string, 0, strpos($string, '_'));
221
    }
222
223
    /**
224
     * @param $identifier
225
     * @param $system
226
     * @param $message
227
     * @param $status
228
     * @param $value
229
     * @param $tool
230
     * @param $component
231
     * @param Attribute[] $attributes
232
     */
233
    private function send($identifier, $system, $message, $status, $value, $tool, $component, $attributes = [])
234
    {
235
        if ($status !== CheckResult::STATUS_NONE) {
236
            $event = new Event($identifier, $system, $status, $tool, $message, $value, '', $component);
237
            $event->addAttribute(new Attribute('_config', json_encode($this->config->getConfigArray()), true));
238
            foreach ($attributes as $attribute) {
239
                $event->addAttribute($attribute);
240
            }
241
            $this->reporter->sendEvent($event);
242
        }
243
    }
244
}
245