RpTest   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 99
dl 0
loc 183
rs 10
c 1
b 0
f 0
wmc 25

7 Methods

Rating   Name   Duplication   Size   Complexity  
A printImplementation() 0 5 1
A configure() 0 10 1
F execute() 0 115 19
A __construct() 0 11 1
A printSeparator() 0 3 1
A printRemoteLog() 0 11 1
A printEnvironment() 0 6 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Facile\OpenIDClient\ConformanceTest\Command;
6
7
use Symfony\Component\Console\Command\Command;
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Input\InputOption;
10
use Symfony\Component\Console\Output\OutputInterface;
11
use Facile\OpenIDClient\ConformanceTest\Helper\RPLogsHelper;
12
use Facile\OpenIDClient\ConformanceTest\Provider\RpProfileTestsProvider;
13
use Facile\OpenIDClient\ConformanceTest\RpTest\RpTestInterface;
14
use Facile\OpenIDClient\ConformanceTest\Runner\RpTestResult;
15
use Facile\OpenIDClient\ConformanceTest\Runner\RpTestRunner;
16
use Facile\OpenIDClient\ConformanceTest\TestInfo;
17
use function count;
18
use function fnmatch;
19
use function sprintf;
20
21
class RpTest extends Command
22
{
23
    /** @var RpTestRunner */
24
    private $testRunner;
25
    /** @var RpProfileTestsProvider */
26
    private $testsProvider;
27
    /** @var RPLogsHelper */
28
    private $logsHelper;
29
30
    public function __construct(
31
        RpTestRunner $testRunner,
32
        RpProfileTestsProvider $testsProvider,
33
        RPLogsHelper $logsHelper
34
    )
35
    {
36
        $this->testRunner = $testRunner;
37
        $this->testsProvider = $testsProvider;
38
        $this->logsHelper = $logsHelper;
39
40
        parent::__construct('test');
41
    }
42
43
    protected function configure(): void
44
    {
45
        $this->setName('test')
46
            ->addOption('profile', 'p', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Profile', $this->testsProvider->getAvailableProfiles())
47
            ->addOption('test-id', 't', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Filter test to execute')
48
            ->addOption('show-implementation', 'i', InputOption::VALUE_NONE, 'Whether to show implementation')
49
            ->addOption('show-environment', 'e', InputOption::VALUE_NONE, 'Whether to show environment')
50
            ->addOption('show-remote-logs', 'l', InputOption::VALUE_NONE, 'Whether to show remote logs')
51
            ->addOption('keep-logs', 'k', InputOption::VALUE_NONE, 'Whether to keep server logs')
52
            ->addOption('ignore-errors', null, InputOption::VALUE_NONE, 'Whether to stops on errors')
53
        ;
54
    }
55
56
    protected function execute(InputInterface $input, OutputInterface $output): int
57
    {
58
        $profiles = $input->getOption('profile');
59
        $testIds = $input->getOption('test-id');
60
        $showImplementation = (bool) $input->getOption('show-implementation');
61
        $showEnvironment = (bool) $input->getOption('show-environment');
62
        $showRemoteLogs = (bool) $input->getOption('show-remote-logs');
63
        $keepLogs = (bool) $input->getOption('keep-logs');
64
        $ignoreErrors = (bool) $input->getOption('ignore-errors');
65
66
        $retries = 5;
67
68
        $counters = [
69
            'executed' => [],
70
            'success' => [],
71
            'errors' => [],
72
        ];
73
74
        foreach ($profiles as $profile) {
75
            $tests = $this->testsProvider->getTests($profile);
76
            $responseType = $this->testsProvider->getResponseTypeForProfile($profile);
77
78
            $testInfo = new TestInfo($profile, $responseType);
79
80
            if (! $keepLogs) {
81
                $this->logsHelper->clearLogs($testInfo->getRoot(), $testInfo->getRpId());
82
            }
83
84
            if (count($testIds)) {
0 ignored issues
show
Bug introduced by
It seems like $testIds can also be of type boolean and null and string; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

84
            if (count(/** @scrutinizer ignore-type */ $testIds)) {
Loading history...
85
                $tests = \array_filter($tests, static function (RpTestInterface $test) use ($testIds) {
86
                    foreach ($testIds as $testId) {
87
                        if (fnmatch($testId, $test->getTestId())) {
88
                            return true;
89
                        }
90
                    }
91
92
                    return false;
93
                    //return \in_array($test->getTestId(), $testIds, true);
94
                });
95
            }
96
97
            foreach ($tests as $test) {
98
                $testName = $test->getTestId() . ' @' . $testInfo->getProfile();
99
                $counters['executed'][] = $testName;
100
101
                $startTime = new \DateTimeImmutable();
102
                $output->writeln("<comment>Test started at:</comment> <info>{$startTime->format(\DateTimeImmutable::RFC3339)}</info>", OutputInterface::VERBOSITY_DEBUG);
103
                $output->writeln('Executing test ' . $testName . '...', OutputInterface::VERBOSITY_DEBUG);
104
105
                $count = 0;
106
107
                do {
108
                    $result = $this->testRunner->run($test, $testInfo);
109
                } while (null !== $result->getException() && ++$count < $retries);
110
111
                $output->writeln("<comment>Test:</comment> <info>$testName</info>", OutputInterface::VERBOSITY_NORMAL);
112
113
                if ($count > 1) {
114
                    $output->writeln("<comment>Attempts:</comment> <info>$count</info>", OutputInterface::VERBOSITY_NORMAL);
115
                }
116
117
                if ($showEnvironment) {
118
                    $output->writeln('');
119
                    $this->printEnvironment($result, $output);
120
                }
121
122
                if ($showImplementation) {
123
                    $output->writeln('');
124
                    $this->printImplementation($result, $output);
125
                }
126
127
128
                if ($showRemoteLogs) {
129
                    $output->writeln('');
130
                    $this->printRemoteLog($result, $output);
131
                }
132
133
                if ($exception = $result->getException()) {
134
                    $counters['errors'][] = $testName;
135
                    $output->writeln('<comment>Result:</comment> <error>Test failed!</error>', OutputInterface::VERBOSITY_NORMAL);
136
                    $output->writeln((string) $exception, OutputInterface::VERBOSITY_DEBUG);
137
                } else {
138
                    $counters['success'][] = $testName;
139
                    $output->writeln('<comment>Result:</comment> <info>Test OK</info>', OutputInterface::VERBOSITY_NORMAL);
140
                }
141
142
                $this->printSeparator($output, OutputInterface::VERBOSITY_NORMAL);
143
144
                if (! $ignoreErrors && $result->getException()) {
145
                    return 1;
146
                }
147
            }
148
        }
149
150
        $output->writeln('<info>--- SUMMARY ---</info>', OutputInterface::VERBOSITY_NORMAL);
151
        $output->writeln(sprintf('<comment>Executed:</comment> <info>%d</info>', count($counters['executed'])), OutputInterface::VERBOSITY_NORMAL);
152
        $output->writeln(sprintf('<comment>Success:</comment> <info>%d</info>', count($counters['success'])), OutputInterface::VERBOSITY_NORMAL);
153
        $output->writeln(sprintf('<comment>Errors:</comment> <info>%d</info>', count($counters['errors'])), OutputInterface::VERBOSITY_NORMAL);
154
155
        if (count($counters['errors'])) {
156
            $this->printSeparator($output, OutputInterface::VERBOSITY_NORMAL);
157
            $output->writeln('<info>Failed tests</info>', OutputInterface::VERBOSITY_NORMAL);
158
159
            foreach ($counters['errors'] as $testName) {
160
                $output->writeln(sprintf('  - <comment>%s</comment>', $testName), OutputInterface::VERBOSITY_NORMAL);
161
            }
162
        }
163
164
165
166
        if (count($counters['errors'])) {
167
            return 1;
168
        }
169
170
        return 0;
171
    }
172
173
    private function printSeparator(OutputInterface $output, int $options = 0): void
174
    {
175
        $output->writeln(\str_repeat('-', 80), $options);
176
    }
177
178
    private function printRemoteLog(RpTestResult $result, OutputInterface $output): void
179
    {
180
        $testInfo = $result->getTestInfo();
181
        $body = (string) $this->logsHelper->getLog(
182
            $testInfo->getRoot(),
183
            $testInfo->getRpId(),
184
            $result->getTest()->getTestId()
185
        )
186
            ->getBody();
187
        $output->writeln('<comment>Remote Log:</comment>');
188
        $output->writeln("<info>{$body}</info>");
189
    }
190
191
    private function printEnvironment(RpTestResult $result, OutputInterface $output): void
192
    {
193
        $testInfo = $result->getTestInfo();
194
        $output->writeln('<comment>Environment:</comment>');
195
        $output->writeln("<info>RP ID: {$testInfo->getRpId()}</info>");
196
        $output->writeln("<info>response_type: {$testInfo->getResponseType()}</info>");
197
    }
198
199
    private function printImplementation(RpTestResult $result, OutputInterface $output): void
200
    {
201
        $output->writeln('<comment>Implementation:</comment>');
202
        $output->writeln('');
203
        $output->writeln('<info>' . $result->getImplementation() . '</info>');
204
    }
205
}
206