708b2051cb5f784b6addf5a556d022e5d04d47be
[federation.git] / gateway / src / test / java / org / acumos / federation / gateway / FederationControllerTest.java
1 /*-
2  * ===============LICENSE_START=======================================================
3  * Acumos
4  * ===================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
6  * ===================================================================================
7  * This Acumos software file is distributed by AT&T and Tech Mahindra
8  * under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * This file is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ===============LICENSE_END=========================================================
19  */
20 package org.acumos.federation.gateway;
21
22 import java.io.InputStream;
23
24 import javax.servlet.http.HttpServletResponse;
25
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.fail;
30 import org.junit.Test;
31 import org.junit.Before;
32 import org.junit.runner.RunWith;
33
34 import static org.mockito.Mockito.when;
35 import static org.mockito.Mockito.any;
36
37
38 import org.springframework.beans.factory.annotation.Autowired;
39 import org.springframework.boot.web.server.LocalServerPort;
40 import org.springframework.boot.test.context.SpringBootTest;
41 import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
42 import org.springframework.boot.test.mock.mockito.MockBean;
43 import org.springframework.core.ParameterizedTypeReference;
44 import org.springframework.http.HttpMethod;
45 import org.springframework.test.context.junit4.SpringRunner;
46 import org.springframework.test.context.ContextConfiguration;
47 import org.springframework.web.client.HttpClientErrorException.Conflict;
48 import org.springframework.web.client.HttpClientErrorException.Forbidden;
49 import org.springframework.web.client.HttpClientErrorException.NotFound;
50 import org.springframework.web.client.HttpServerErrorException.InternalServerError;
51
52 import org.acumos.cds.client.ICommonDataServiceRestClient;
53 import org.acumos.cds.client.CommonDataServiceRestClientImpl;
54
55 import org.acumos.federation.client.FederationClient;
56 import org.acumos.federation.client.GatewayClient;
57 import org.acumos.federation.client.ClientBase;
58 import org.acumos.federation.client.config.ClientConfig;
59 import org.acumos.federation.client.config.BasicAuthConfig;
60 import org.acumos.federation.client.config.TlsConfig;
61
62 import org.acumos.federation.client.test.ClientMocking;
63 import static org.acumos.federation.client.test.ClientMocking.getConfig;
64 import static org.acumos.federation.client.test.ClientMocking.xq;
65
66 @RunWith(SpringRunner.class)
67 @ContextConfiguration(classes=FederationServer.class)
68 @SpringBootTest(
69     classes = Application.class,
70     webEnvironment = WebEnvironment.RANDOM_PORT,
71     properties = {
72         "spring.main.allow-bean-definition-overriding=true",
73         "federation.ssl.key-store=classpath:acumosa.pkcs12",
74         "federation.ssl.key-store-password=acumosa",
75         "federation.ssl.key-store-type=PKCS12",
76         "federation.ssl.trust-store=classpath:acumosTrustStore.jks",
77         "federation.ssl.trust-store-password=acumos",
78         "federation.address=localhost",
79         "federation.server.port=0",
80         "federation.registration-enabled=true",
81         "cdms.client.url=http://dummy.org:999",
82         "cdms.client.username=dummyuser",
83         "cdms.client.password=dummypass",
84         "nexus.url=http://dummy.org:1234"
85     }
86 )
87 public class FederationControllerTest {
88         @LocalServerPort
89         private int port;
90
91         @Autowired
92         private ServiceConfig cdmsConfig;
93
94         @Autowired
95         private NexusConfig nexusConfig;
96
97         @Autowired
98         private PeerService peerService;
99
100         @MockBean
101         private Clients clients;
102
103         private SimulatedDockerClient docker;
104
105         static ClientConfig anonConfig() {
106                 ClientConfig ret = getConfig("bogus");
107                 ret.getSsl().setKeyStore(null);
108                 ret.setCreds(null);
109                 return ret;
110         }
111
112         private static class RawAnonClient extends ClientBase {
113                 public RawAnonClient(String url) throws Exception {
114                         super(url, anonConfig(), null, null);
115                 }
116
117                 public byte[] get(String uri) {
118                         return handle(uri, HttpMethod.GET, new ParameterizedTypeReference<byte[]>(){});
119                 }
120         }
121
122         @Before
123         public void init() throws Exception {
124                 String url = cdmsConfig.getUrl();
125                 ClientConfig ccc = new ClientConfig();
126                 ccc.setCreds(cdmsConfig);
127                 ICommonDataServiceRestClient cdsClient = CommonDataServiceRestClientImpl.getInstance(url, ClientBase.buildRestTemplate(url, ccc, null, null));
128
129                 (new ClientMocking())
130                     .on("GET /peer/search?self=true&subjectName=gateway.acumosa.org&_j=a&page=0&size=100", xq("{ 'content': [ {'peerId': '1', 'subjectName': 'gateway.acumosa.org', 'statusCode': 'AC', 'self': true, 'local': true } ], 'last': true, 'number': 0, 'size': 100, 'numberOfElements': 1 }"))
131                     .on("GET /peer/search?subjectName=gateway.acumosa.org&_j=a&page=0&size=100", xq("{ 'content': [ {'peerId': '1', 'subjectName': 'gateway.acumosa.org', 'statusCode': 'AC', 'self': true } ], 'last': true, 'number': 0, 'size': 100, 'numberOfElements': 1 }"))
132                     .on("GET /peer/search?subjectName=gateway.acumosb.org&_j=a&page=0&size=100", xq("{ 'content': [ {'peerId': '2', 'subjectName': 'gateway.acumosb.org', 'statusCode': 'XX', 'self': false } ], 'last': true, 'number': 0, 'size': 100, 'numberOfElements': 1 }"))
133                     .on("GET /peer/search?self=true&subjectName=Bad=?#/.CN%Value&_j=a&page=0&size=100", xq("{}"))
134                     .on("GET /peer/2", xq("{'peerId': '2', 'subjectName': 'gateway.acumosb.org', 'statusCode': 'RQ', 'self': false }"))
135                     .on("PUT /peer/2", "")
136                     .on("GET /peer/search?subjectName=gateway.acumosc.org&_j=a&page=0&size=100", xq("{ 'content': [ ], 'last': true, 'number': 0, 'size': 100, 'numberOfElements': 0 }"))
137                     .on("POST /peer", xq("{}"))
138                     .on("GET /catalog/search?accessTypeCode=PB&_j=a&page=0&size=100", xq("{ 'content': [ { 'catalogId': '1' }, { 'catalogId': '2' } ], 'last': true, 'number': 2, 'size': 100, 'numberOfElements': 2 }"))
139                     .on("GET /access/peer/1/catalog", xq("[ '2', '7', '8' ]"))
140                     .on("GET /peer?page=0&size=100", xq("{ 'content': [ { 'peerId': '1' }, { 'peerId': '2' } ], 'last': true, 'number': 2, 'size': 100, 'numberOfElements': 2 }"))
141                     .on("GET /catalog/1/solution/count", xq("{ 'count': 1 }"))
142                     .on("GET /catalog/2/solution/count", xq("{ 'count': 2 }"))
143                     .on("GET /catalog/7", xq("{ 'catalogId': '7' }"))
144                     .on("GET /catalog/7/solution/count", xq("{ 'count': 3 }"))
145                     .on("GET /catalog/8", "")
146                     .on("GET /peer/search?self=true&subjectName=No.Such.Peer&_j=a&page=0&size=100", xq("{ 'content': [], 'last': true, 'number': 0, 'size': 100, 'numberOfElements': 0 }"))
147                     .on("GET /access/peer/1/catalog/somecatid", xq("{ 'count': '1' }"))
148                     .on("GET /access/peer/1/catalog/badcatid", xq("{ 'count': '0' }"))
149                     .on("GET /catalog/solution?ctlg=somecatid&page=0&size=100", xq("{ 'content': [ { 'solutionId': 'somesolid' }, { 'solutionId': 'othersolid', 'origin': 'https://someoneelse.org:1234/solution/othersolid' } ], 'last': true, 'number': 2, 'size': 100, 'numberOfElements': 2 }"))
150                     .on("GET /access/peer/1/solution/somesolid", xq("{ 'count': '1' }"))
151                     .on("GET /access/peer/1/solution/badsolid", xq("{ 'count': '0' }"))
152                     .on("GET /access/peer/1/solution/norevssolid", xq("{ 'count': '1' }"))
153                     .on("GET /solution/somesolid", xq("{ 'solutionId': 'somesolid' }"))
154                     .on("GET /solution/norevssolid", xq("{ 'solutionId': 'norevssolid' }"))
155                     .on("GET /solution/somesolid/revision", xq("[ { 'solutionId': 'somesolid', 'revisionId': 'somerevid' }, { 'solutionId': 'somesolid', 'revisionId': 'otherrevid' } ]"))
156                     .on("GET /solution/norevssolid/revision", "[]")
157                     .on("GET /solution/somesolid/pic", "")
158                     .on("GET /solution/ignored/revision/somerevid", xq("{ 'solutionId': 'somesolid', 'revisionId': 'somerevid' }"))
159                     .on("GET /solution/ignored/revision/badrevid", xq("{ 'solutionId': 'badsolid', 'revisionId': 'badrevid' }"))
160                     .on("GET /solution/ignored/revision/norevid", "")
161                     .on("GET /revision/somerevid/artifact", xq("[ { 'artifactId': 'someartid' }, { 'artifactId': 'otherartid', 'uri': 'dockerregistry:997/a/b', 'artifactTypeCode': 'DI' }, { 'artifactId': 'nexusartid', 'uri': 'a/b/c.x' } ]"))
162                     .on("GET /revision/badrevid/artifact", xq("[ { 'artifactId': 'badartid' }, { 'artifactId': 'otherbadartid' } ]"))
163                     .on("GET /revision/somerevid/catalog/somecatid/descr", xq("{ 'revisionId': 'somerevid', 'catalogId': 'somecatid', 'description': 'Etc., etc., etc.' }"))
164                     .on("GET /revision/somerevid/catalog/somecatid/document", xq("[ { 'documentId': 'somedocid' }, { 'documentId': 'otherdocid' } ]"))
165                     .on("GET /artifact/someartid", xq("{ 'artifactId': 'someartid', 'uri': 'a/b/c/d' }"))
166                     .on("GET /artifact/dockerartid", xq("{ 'artifactId': 'someartid', 'uri': 'dockerregistry:1234/a/b:1.0', 'artifactTypeCode': 'DI' }"))
167                     .on("GET /document/somedocid", xq("{ 'documentId': 'somedocid', 'uri': 'd/c/b/a' }"))
168                     .on("GET /peer/1/sub", "[]")
169                     .on("GET /peer/2/sub", "[]")
170                     .on("GET /solution/ignored/revision/altrevid", xq("{ 'solutionId': 'somesolid', 'revisionId': 'altrevid' }"))
171                     .on("GET /revision/altrevid/artifact", xq("[ { 'artifactId': 'altart1', 'artifactTypeCode': 'DI', 'version': 'aa1ver', 'uri': 'host:999/xxx/stuff:aa1ver' }, { 'artifactId': 'altart2', 'artifactTypeCode': 'DI', 'version': 'aa2ver', 'uri': 'someimagename' }]"))
172                     .on("GET /revision/altrevid/catalog/somecatid/document", xq("[ { 'documentId': 'altdoc1', 'version': 'ad1ver', 'uri': 'somepath/ad1name/ua/ad1name-ua.ad1type' }, { 'documentId': 'altdoc2', 'version': 'ad2ver', 'uri': 'somepath/ad2name/ua/ad2name.ad2type' }]"))
173                     .applyTo(cdsClient);
174
175                 when(clients.getCDSClient()).thenReturn(cdsClient);
176
177                 ClientConfig ncc = new ClientConfig();
178                 ncc.setCreds(nexusConfig);
179                 NexusClient nexusClient = new NexusClient(nexusConfig.getUrl(), ncc);
180
181                 (new ClientMocking())
182                     .on("GET /a/b/c/d", "vwxyz")
183                     .on("GET /d/c/b/a", "wxyz")
184                     .applyTo(nexusClient);
185                 when(clients.getNexusClient()).thenReturn(nexusClient);
186
187                 docker = new SimulatedDockerClient();
188                 docker.setSaveResult("abcdefg".getBytes());
189                 when(clients.getDockerClient()).thenReturn(docker.getClient());
190         }
191
192         @Test
193         public void testConfig() throws Exception {
194
195                 FederationClient self = new FederationClient("https://localhost:" + port, getConfig("acumosa"));
196                 FederationClient known = new FederationClient("https://localhost:" + port, getConfig("acumosb"));
197                 FederationClient unknown = new FederationClient("https://localhost:" + port, getConfig("acumosc"));
198                 assertNotNull(unknown.register());
199                 try {
200                         self.register();
201                         fail();
202                 } catch (Conflict c) {
203                         // expected case
204                 }
205                 assertNotNull(known.unregister());
206                 assertNotNull(self.ping());
207                 assertEquals(2, self.getPeers().size());
208                 try {
209                         unknown.unregister();
210                         fail();
211                 } catch (Forbidden ux) {
212                         // expected case
213                 }
214                 try {
215                         known.ping();
216                         fail();
217                 } catch (Forbidden ux) {
218                         // expected case
219                 }
220                 assertEquals(3, self.getCatalogs().size());
221                 assertNull(peerService.getSelf("No.Such.Peer"));
222                 assertEquals(2, self.getSolutions("somecatid").size());
223                 try {
224                         self.getSolutions("badcatid");
225                         fail();
226                 } catch (NotFound nf) {
227                         // expected case
228                 }
229                 assertNotNull(self.getSolution("somesolid"));
230                 try {
231                         self.getSolution("badsolid");
232                         fail();
233                 } catch (NotFound nf) {
234                         // expected case
235                 }
236                 try {
237                         self.getSolution("norevssolid");
238                         fail();
239                 } catch (NotFound nf) {
240                         // expected case
241                 }
242                 assertEquals(2, self.getSolutionRevisions("somesolid").size());
243                 try {
244                         self.getSolutionRevisions("badsolid");
245                         fail();
246                 } catch (NotFound nf) {
247                         // expected case
248                 }
249                 try {
250                         self.getSolutionRevisions("norevssolid");
251                         fail();
252                 } catch (NotFound nf) {
253                         // expected case
254                 }
255                 assertNotNull(self.getSolutionRevision("somesolid", "somerevid", "somecatid"));
256                 try {
257                         self.getSolutionRevision("somesolid", "badrevid", "badcatid");
258                         fail();
259                 } catch (NotFound nf) {
260                         // expected case
261                 }
262                 try {
263                         self.getSolutionRevision("somesolid", "norevid", null);
264                         fail();
265                 } catch (NotFound nf) {
266                         // expected case
267                 }
268                 assertEquals(3, self.getArtifacts("somesolid", "somerevid").size());
269                 try {
270                         self.getArtifacts("somesolid", "badrevid");
271                         fail();
272                 } catch (NotFound nf) {
273                         // expected case
274                 }
275                 try {
276                         self.getArtifacts("somesolid", "norevid");
277                         fail();
278                 } catch (NotFound nf) {
279                         // expected case
280                 }
281                 byte[] buf = new byte[1000];
282                 try (InputStream is = self.getArtifactContent("someartid")) {
283                         assertEquals(5, is.read(buf));
284                 }
285                 try (InputStream is = self.getArtifactContent("dockerartid")) {
286                         assertEquals(7, is.read(buf));
287                 }
288                 docker.setDoPullTimeout(true);
289                 try {
290                         self.getArtifactContent("dockerartid");
291                         fail();
292                 } catch (InternalServerError ise) {
293                         // expected case
294                 }
295                 assertEquals(2, self.getDocuments("somerevid", "somecatid").size());
296                 try (InputStream is = self.getDocumentContent("somedocid")) {
297                         assertEquals(4, is.read(buf));
298                 }
299                 try {
300                         self.getDocuments("somerevid", "badcatid");
301                         fail();
302                 } catch (NotFound nf) {
303                         // expected case
304                 }
305                 assertNotNull(self.getDocuments("altrevid", "somecatid"));
306                 assertNotNull(self.getArtifacts("somesolid", "altrevid"));
307         }
308
309         @Test
310         public void testSwagger() throws Exception {
311                 RawAnonClient rac = new RawAnonClient("https://localhost:" + port);
312                 assertNotNull(rac);
313                 rac.get("/swagger-ui.html");
314                 rac.get("/v2/api-docs");
315         }
316 }