Issues (19)

tests/Service/ServiceTest.php (9 issues)

1
<?php
2
3
namespace TheAentMachine\Registry;
4
5
use PHPUnit\Framework\TestCase;
6
use TheAentMachine\Aenthill\CommonMetadata;
0 ignored issues
show
The type TheAentMachine\Aenthill\CommonMetadata was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use TheAentMachine\Service\Enum\VolumeTypeEnum;
8
use TheAentMachine\Service\Environment\SharedEnvVariable;
9
use TheAentMachine\Service\Exception\ServiceException;
10
use TheAentMachine\Service\Service;
11
use TheAentMachine\Service\Volume\BindVolume;
12
use TheAentMachine\Service\Volume\NamedVolume;
13
14
class ServiceTest extends TestCase
15
{
16
    private const VALID_PAYLOAD = <<< 'JSON'
17
{
18
  "serviceName" : "foo",
19
  "service": {
20
    "image"         : "foo/bar:baz",
21
    "command"       : ["foo", "-bar", "-baz", "--qux"],
22
    "internalPorts" : [1, 2, 3],
23
    "dependsOn"     : ["foo", "bar"],
24
    "ports"         : [{"source": 80, "target": 8080, "comment": "a line of comment"}],
25
    "environment"   : {
26
                        "FOO": {"value": "foo", "type": "sharedEnvVariable", "comment": "foo", "containerId": "baz"},
27
                        "BAR": {"value": "bar", "type": "sharedSecret", "comment": "bar"},
28
                        "BAZ": {"value": "baz", "type": "imageEnvVariable", "comment": "baz"},
29
                        "QUX": {"value": "qux", "type": "containerEnvVariable", "comment": "qux"}
30
                      },
31
    "labels"        : {
32
                        "foo": {"value": "fooo", "comment": "fooo"},
33
                        "bar": {"value": "baar", "comment": "baar"}
34
                      },
35
    "volumes"       : [
36
                        {"type": "volume", "source": "foo", "target": "/foo", "readOnly": true, "comment": "it's a named volume tho", "requestStorage": "8Gi"},
37
                        {"type": "bind", "source": "/bar", "target": "/bar", "readOnly": false, "comment": "a bind volume"},
38
                        {"type": "tmpfs", "source": "baz", "comment": "a tmpfs"}
39
                      ],
40
    "virtualHosts": [
41
      {"host": "foo", "port": 80, "comment": "a default virtual host"},
42
      {"port": 8080, "comment": "it's ok"},
43
      {"hostPrefix": "foo", "port": 80}
44
    ],
45
    "needBuild": true
46
  },
47
  "dockerfileCommands": [
48
    "RUN composer install"
49
  ],
50
  "destEnvTypes": [
51
    "DEV"
52
  ],
53
  "resources": {
54
    "requests": {
55
      "memory": "64Mi",
56
      "cpu": "250m"
57
    },
58
    "limits": {
59
      "memory": "128Mi",
60
      "cpu": "500m"
61
    }
62
  }
63
}
64
JSON;
65
66
    private const MISSING_SERVICE_NAME_PAYLOAD = <<< 'JSON'
67
{
68
  "service": {
69
    "internalPorts": [80]
70
  }
71
}
72
JSON;
73
74
    private const UNKNOWN_ENV_VARIABLE_TYPE_PAYLOAD = <<< 'JSON'
75
{
76
  "serviceName": "foo",
77
  "service": {
78
    "environment": {
79
      "FOO": {
80
        "value": "fooo",
81
        "type": "YIKES_THATS_SOME_BAD_TYPE_HERE"
82
      }
83
    }
84
  }
85
}
86
JSON;
87
88
    private const UNKNOWN_VOLUME_TYPE_PAYLOAD = <<< 'JSON'
89
{
90
  "serviceName": "foo",
91
  "service": {
92
    "volumes": [
93
      {
94
        "type": "AGAIN?WTH",
95
        "source": "foo"
96
      }
97
    ]
98
  }
99
}
100
JSON;
101
102
    /** @throws ServiceException */
103
    public function testValidPayload(): void
104
    {
105
        $array = \GuzzleHttp\json_decode(self::VALID_PAYLOAD, true);
106
        $service = Service::parsePayload($array);
107
        $out = $service->jsonSerialize();
108
        $this->assertEquals($array, $out);
109
        $this->assertTrue($service->isForDevEnvType());
0 ignored issues
show
The method isForDevEnvType() does not exist on TheAentMachine\Service\Service. ( Ignorable by Annotation )

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

109
        $this->assertTrue($service->/** @scrutinizer ignore-call */ isForDevEnvType());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
110
        $this->assertFalse($service->isForTestEnvType());
0 ignored issues
show
The method isForTestEnvType() does not exist on TheAentMachine\Service\Service. ( Ignorable by Annotation )

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

110
        $this->assertFalse($service->/** @scrutinizer ignore-call */ isForTestEnvType());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
111
        $this->assertFalse($service->isForProdEnvType());
0 ignored issues
show
The method isForProdEnvType() does not exist on TheAentMachine\Service\Service. ( Ignorable by Annotation )

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

111
        $this->assertFalse($service->/** @scrutinizer ignore-call */ isForProdEnvType());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
112
    }
113
114
    /** @throws ServiceException */
115
    public function testMissingServiceNamePayload(): void
116
    {
117
        $this->expectException(ServiceException::class);
118
        $array = \GuzzleHttp\json_decode(self::MISSING_SERVICE_NAME_PAYLOAD, true);
119
        Service::parsePayload($array)->jsonSerialize();
120
    }
121
122
    /** @throws ServiceException */
123
    public function testUnknownEnvVariableTypePayload(): void
124
    {
125
        $this->expectException(ServiceException::class);
126
        $array = \GuzzleHttp\json_decode(self::UNKNOWN_ENV_VARIABLE_TYPE_PAYLOAD, true);
127
        Service::parsePayload($array)->jsonSerialize();
128
    }
129
130
    /** @throws ServiceException */
131
    public function testUnknownVolumeTypePayload(): void
132
    {
133
        $this->expectException(ServiceException::class);
134
        $array = \GuzzleHttp\json_decode(self::UNKNOWN_VOLUME_TYPE_PAYLOAD, true);
135
        Service::parsePayload($array)->jsonSerialize();
136
    }
137
138
    /** @throws ServiceException */
139
    public function testSettersAndAdders(): void
140
    {
141
        $s = new Service();
142
        $s->setServiceName('foo');
143
        $s->setImage('foo/bar:baz');
144
        $s->setCommand(['foo', '-bar', '-baz']);
145
        $s->addCommand('--qux');
146
        $s->setInternalPorts([1, 2]);
147
        $s->addInternalPort(3);
148
        $s->setDependsOn(['foo']);
149
        $s->addDependsOn('bar');
150
        $s->addPort(80, 8080, 'a line of comment');
151
        $s->addLabel('foo', 'fooo', 'fooo');
152
        $s->addLabel('bar', 'baar', 'baar');
153
        $s->addSharedEnvVariable('FOO', 'foo', 'foo', 'baz');
154
        $s->addSharedSecret('BAR', 'bar', 'bar');
155
        $s->addImageEnvVariable('BAZ', 'baz', 'baz');
156
        $s->addContainerEnvVariable('QUX', 'qux', 'qux');
157
        $s->addNamedVolume('foo', '/foo', true, 'it\'s a named volume tho', '8Gi');
158
        $s->addBindVolume('/bar', '/bar', false, 'a bind volume');
159
        $s->addTmpfsVolume('baz', 'a tmpfs');
160
        $s->addDockerfileCommand('RUN composer install');
161
        $s->addVirtualHost('foo', 80, 'a default virtual host');
0 ignored issues
show
The call to TheAentMachine\Service\Service::addVirtualHost() has too many arguments starting with 80. ( Ignorable by Annotation )

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

161
        $s->/** @scrutinizer ignore-call */ 
162
            addVirtualHost('foo', 80, 'a default virtual host');

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
'foo' of type string is incompatible with the type integer expected by parameter $port of TheAentMachine\Service\Service::addVirtualHost(). ( Ignorable by Annotation )

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

161
        $s->addVirtualHost(/** @scrutinizer ignore-type */ 'foo', 80, 'a default virtual host');
Loading history...
162
        $s->addVirtualHost(null, 8080, "it's ok");
0 ignored issues
show
null of type null is incompatible with the type integer expected by parameter $port of TheAentMachine\Service\Service::addVirtualHost(). ( Ignorable by Annotation )

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

162
        $s->addVirtualHost(/** @scrutinizer ignore-type */ null, 8080, "it's ok");
Loading history...
163
        $s->addVirtualHostPrefix('foo', 80, null);
0 ignored issues
show
The method addVirtualHostPrefix() does not exist on TheAentMachine\Service\Service. Did you maybe mean addVirtualHost()? ( Ignorable by Annotation )

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

163
        $s->/** @scrutinizer ignore-call */ 
164
            addVirtualHostPrefix('foo', 80, null);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
164
        $s->setNeedBuild(true);
165
        $s->addDestEnvType(CommonMetadata::ENV_TYPE_DEV, true);
0 ignored issues
show
The method addDestEnvType() does not exist on TheAentMachine\Service\Service. ( Ignorable by Annotation )

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

165
        $s->/** @scrutinizer ignore-call */ 
166
            addDestEnvType(CommonMetadata::ENV_TYPE_DEV, true);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
166
        $s->setRequestMemory('64Mi');
167
        $s->setRequestCpu('250m');
168
        $s->setLimitMemory('128Mi');
169
        $s->setLimitCpu('500m');
170
        $outArray = $s->jsonSerialize();
171
        $expectedArray = \GuzzleHttp\json_decode(self::VALID_PAYLOAD, true);
172
        $this->assertEquals($outArray, $expectedArray);
173
174
        $outArray = $s->imageJsonSerialize();
175
        $expectedArray = [
176
            'serviceName' => 'foo',
177
            'dockerfileCommands' => [
178
                'FROM foo/bar:baz',
179
                'ENV BAZ=baz',
180
                'COPY /bar /bar',
181
                'CMD foo -bar -baz --qux',
182
                'RUN composer install'
183
            ],
184
            'destEnvTypes' => ['DEV']
185
        ];
186
        $this->assertEquals($outArray, $expectedArray);
187
    }
188
189
    /** @throws ServiceException */
190
    public function testInvalidRequestMemoryPattern(): void
191
    {
192
        $s = new Service();
193
        $s->setServiceName('foo');
194
        $s->setRequestMemory('0.5Zi');
195
        $this->expectException(ServiceException::class);
196
        $s->jsonSerialize();
197
    }
198
199
    /** @throws ServiceException */
200
    public function testInvalidRequestCpuPattern(): void
201
    {
202
        $s = new Service();
203
        $s->setServiceName('foo');
204
        $s->setRequestCpu('0,1');
205
        $this->expectException(ServiceException::class);
206
        $s->jsonSerialize();
207
    }
208
209
    public function testVolumeRemovers(): void
210
    {
211
        $s = new Service();
212
        $s->setServiceName('my-service');
213
        $s->addBindVolume('./foo', '/opt/app/foo', true);
214
        $s->addBindVolume('./bar', '/opt/app/baz', false);
215
        $s->addNamedVolume('my-data', '/data', true);
216
        $s->removeVolumesBySource('./bar');
217
        /** @var BindVolume[]|NamedVolume[] $volumes */
218
        $volumes = $s->getVolumes();
219
        $this->assertEquals(count($volumes), 2);
220
        $this->assertEquals($volumes[0]->getType(), VolumeTypeEnum::BIND_VOLUME);
221
        $this->assertEquals($volumes[0]->getSource(), './foo');
222
        $this->assertEquals($volumes[1]->getType(), VolumeTypeEnum::NAMED_VOLUME);
223
224
        $s->addBindVolume('./bar', '/opt/app/baz', false);
225
        $s->removeAllBindVolumes();
226
        $volumes = $s->getVolumes();
227
        $this->assertEquals(count($volumes), 1);
228
        $this->assertEquals($volumes[0]->getType(), VolumeTypeEnum::NAMED_VOLUME);
229
        $this->assertEquals($volumes[0]->getTarget(), '/data');
230
    }
231
232
    public function testEnvVariableContains(): void
233
    {
234
        $s = new Service();
235
        $s->setServiceName('my-service');
236
        $s->addSharedSecret('MYSQL_ROOT_PASSWORD', 'foo', 'comment', 'container');
237
        self::assertCount(0, $s->getAllSharedEnvVariable());
238
        self::assertCount(1, $s->getAllSharedSecret());
239
        self::assertCount(0, $s->getAllImageEnvVariable());
240
        self::assertCount(0, $s->getAllContainerEnvVariable());
241
        $variable = $s->getAllSharedSecret()['MYSQL_ROOT_PASSWORD'];
242
        $this->assertInstanceOf(SharedEnvVariable::class, $variable);
243
        $this->assertSame('foo', $variable->getValue());
244
        $this->assertSame('comment', $variable->getComment());
245
        $this->assertSame('container', $variable->getContainerId());
246
    }
247
}