| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.servicecomb.inspector.internal; |
| |
| import static org.apache.servicecomb.core.Const.RESTFUL; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.nio.charset.StandardCharsets; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.function.Function; |
| import java.util.stream.Collectors; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipInputStream; |
| |
| import javax.servlet.http.Part; |
| import javax.ws.rs.core.HttpHeaders; |
| import javax.ws.rs.core.MediaType; |
| import javax.ws.rs.core.Response.Status; |
| |
| import org.apache.commons.io.IOUtils; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.servicecomb.config.ConfigUtil; |
| import org.apache.servicecomb.config.priority.PriorityPropertyFactory; |
| import org.apache.servicecomb.core.SCBEngine; |
| import org.apache.servicecomb.core.Transport; |
| import org.apache.servicecomb.core.bootstrap.SCBBootstrap; |
| import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; |
| import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; |
| import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; |
| import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; |
| import org.apache.servicecomb.inspector.internal.model.DynamicPropertyView; |
| import org.apache.servicecomb.inspector.internal.model.PriorityPropertyView; |
| import org.apache.servicecomb.inspector.internal.swagger.SchemaFormat; |
| import org.apache.servicecomb.registry.RegistrationManager; |
| import org.apache.servicecomb.registry.api.registry.Microservice; |
| import org.apache.servicecomb.registry.definition.DefinitionConst; |
| import org.apache.servicecomb.swagger.invocation.Response; |
| import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; |
| import org.apache.servicecomb.swagger.invocation.exception.InvocationException; |
| import org.apache.servicecomb.transport.rest.servlet.ServletRestTransport; |
| import org.hamcrest.MatcherAssert; |
| import org.hamcrest.Matchers; |
| import org.junit.AfterClass; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| import com.netflix.config.DynamicProperty; |
| |
| import mockit.Deencapsulation; |
| import mockit.Expectations; |
| import mockit.Mocked; |
| import org.junit.jupiter.api.Assertions; |
| |
| public class TestInspectorImpl { |
| static Map<String, String> schemas = new LinkedHashMap<>(); |
| |
| static InspectorImpl inspector; |
| |
| @BeforeClass |
| public static void setup() throws IOException { |
| ConfigUtil.installDynamicConfig(); |
| schemas.put("schema1", IOUtils |
| .toString(TestInspectorImpl.class.getClassLoader().getResource("schema1.yaml"), StandardCharsets.UTF_8)); |
| schemas.put("schema2", IOUtils |
| .toString(TestInspectorImpl.class.getClassLoader().getResource("schema2.yaml"), StandardCharsets.UTF_8)); |
| |
| inspector = initInspector(null); |
| } |
| |
| private static InspectorImpl initInspector(String urlPrefix) { |
| SCBEngine scbEngine = SCBBootstrap.createSCBEngineForTest(); |
| scbEngine.getTransportManager().clearTransportBeforeInit(); |
| |
| if (StringUtils.isNotEmpty(urlPrefix)) { |
| Map<String, Transport> transportMap = Deencapsulation.getField(scbEngine.getTransportManager(), "transportMap"); |
| transportMap.put(RESTFUL, new ServletRestTransport()); |
| ClassLoaderScopeContext.setClassLoaderScopeProperty(DefinitionConst.URL_PREFIX, urlPrefix); |
| } |
| |
| scbEngine.run(); |
| InspectorImpl inspector = new InspectorImpl() |
| .setInspectorConfig(scbEngine.getPriorityPropertyManager().createConfigObject(InspectorConfig.class)) |
| .setSchemas(schemas); |
| inspector.correctBasePathForOnlineTest(scbEngine); |
| return inspector; |
| } |
| |
| @AfterClass |
| public static void teardown() { |
| ArchaiusUtils.resetConfig(); |
| SCBEngine.getInstance().destroy(); |
| ClassLoaderScopeContext.clearClassLoaderScopeProperty(); |
| } |
| |
| private Map<String, String> unzip(InputStream is) throws IOException { |
| Map<String, String> result = new LinkedHashMap<>(); |
| ZipInputStream zis = new ZipInputStream(is); |
| for (; ; ) { |
| ZipEntry zipEntry = zis.getNextEntry(); |
| if (zipEntry == null) { |
| zis.close(); |
| return result; |
| } |
| |
| result.put(zipEntry.getName(), IOUtils.toString(zis, StandardCharsets.UTF_8)); |
| } |
| } |
| |
| @Test |
| public void getSchemaIds() { |
| MatcherAssert.assertThat(inspector.getSchemaIds(), Matchers.contains("schema1", "schema2")); |
| } |
| |
| @Test |
| public void downloadSchemas_default_to_swagger(@Mocked Microservice microservice) throws IOException { |
| testDownloadSchemasSwagger(microservice, null); |
| } |
| |
| @Test |
| public void downloadSchemas_swagger(@Mocked Microservice microservice) throws IOException { |
| testDownloadSchemasSwagger(microservice, SchemaFormat.SWAGGER); |
| } |
| |
| private void testDownloadSchemasSwagger(Microservice microservice, SchemaFormat format) throws IOException { |
| new Expectations(RegistrationManager.INSTANCE) { |
| { |
| RegistrationManager.INSTANCE.getMicroservice(); |
| result = microservice; |
| microservice.getServiceName(); |
| result = "ms"; |
| } |
| }; |
| |
| Response response = inspector.downloadSchemas(format); |
| Part part = response.getResult(); |
| Assertions.assertEquals("ms.yaml.zip", part.getSubmittedFileName()); |
| |
| try (InputStream is = part.getInputStream()) { |
| Map<String, String> unziped = unzip(is); |
| |
| Assertions.assertEquals(schemas.size(), unziped.size()); |
| Assertions.assertEquals(schemas.get("schema1"), unziped.get("schema1.yaml")); |
| Assertions.assertEquals(schemas.get("schema2"), unziped.get("schema2.yaml")); |
| } |
| } |
| |
| @Test |
| public void downloadSchemas_html(@Mocked Microservice microservice) throws IOException { |
| new Expectations(RegistrationManager.INSTANCE) { |
| { |
| RegistrationManager.INSTANCE.getMicroservice(); |
| result = microservice; |
| microservice.getServiceName(); |
| result = "ms"; |
| } |
| }; |
| Response response = inspector.downloadSchemas(SchemaFormat.HTML); |
| Part part = response.getResult(); |
| Assertions.assertEquals("ms.html.zip", part.getSubmittedFileName()); |
| |
| try (InputStream is = part.getInputStream()) { |
| Map<String, String> unziped = unzip(is); |
| |
| Assertions.assertEquals(schemas.size(), unziped.size()); |
| Assertions.assertTrue(unziped.get("schema1.html").endsWith("</html>")); |
| Assertions.assertTrue(unziped.get("schema2.html").endsWith("</html>")); |
| } |
| } |
| |
| @Test |
| public void downloadSchemas_failed() { |
| SchemaFormat format = SchemaFormat.SWAGGER; |
| new Expectations(format) { |
| { |
| format.getSuffix(); |
| result = new RuntimeExceptionWithoutStackTrace("zip failed."); |
| } |
| }; |
| |
| try (LogCollector logCollector = new LogCollector()) { |
| Response response = inspector.downloadSchemas(format); |
| |
| Assertions.assertEquals("failed to create schemas zip file, format=SWAGGER.", |
| logCollector.getLastEvents().getMessage()); |
| |
| InvocationException invocationException = response.getResult(); |
| Assertions.assertEquals(Status.INTERNAL_SERVER_ERROR, invocationException.getStatus()); |
| Assertions.assertEquals("failed to create schemas zip file, format=SWAGGER.", |
| ((CommonExceptionData) invocationException.getErrorData()).getMessage()); |
| Assertions.assertEquals(Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatusCode()); |
| Assertions.assertEquals(Status.INTERNAL_SERVER_ERROR.getReasonPhrase(), response.getReasonPhrase()); |
| } |
| } |
| |
| @Test |
| public void getSchemaContentById_notExist() { |
| Response response = inspector.getSchemaContentById("notExist", null, false); |
| |
| InvocationException invocationException = response.getResult(); |
| Assertions.assertEquals(Status.NOT_FOUND, invocationException.getStatus()); |
| Assertions.assertEquals(Status.NOT_FOUND.getReasonPhrase(), |
| ((CommonExceptionData) invocationException.getErrorData()).getMessage()); |
| Assertions.assertEquals(404, response.getStatusCode()); |
| Assertions.assertEquals("Not Found", response.getReasonPhrase()); |
| } |
| |
| @Test |
| public void getSchemaContentById_view_swagger() throws IOException { |
| testViewSwaggerById("schema1", null); |
| testViewSwaggerById("schema1", SchemaFormat.SWAGGER); |
| testViewSwaggerById("schema2", null); |
| testViewSwaggerById("schema2", SchemaFormat.SWAGGER); |
| } |
| |
| private void testViewSwaggerById(String schemaId, SchemaFormat format) throws IOException { |
| Response response = inspector.getSchemaContentById(schemaId, format, false); |
| |
| Part part = response.getResult(); |
| Assertions.assertEquals(schemaId + ".yaml", part.getSubmittedFileName()); |
| Assertions.assertEquals("inline", response.getHeader(HttpHeaders.CONTENT_DISPOSITION)); |
| Assertions.assertEquals(MediaType.TEXT_HTML, response.getHeader(HttpHeaders.CONTENT_TYPE)); |
| |
| try (InputStream is = part.getInputStream()) { |
| Assertions.assertEquals(schemas.get(schemaId), IOUtils.toString(is, StandardCharsets.UTF_8)); |
| } |
| } |
| |
| @Test |
| public void getSchemaContentById_download_swagger() throws IOException { |
| testDownloadSwaggerById("schema1", null); |
| testDownloadSwaggerById("schema1", SchemaFormat.SWAGGER); |
| testDownloadSwaggerById("schema2", null); |
| testDownloadSwaggerById("schema2", SchemaFormat.SWAGGER); |
| } |
| |
| private void testDownloadSwaggerById(String schemaId, SchemaFormat format) throws IOException { |
| Response response = inspector.getSchemaContentById(schemaId, format, true); |
| |
| Part part = response.getResult(); |
| Assertions.assertEquals(schemaId + ".yaml", part.getSubmittedFileName()); |
| Assertions.assertNull(response.getHeader(HttpHeaders.CONTENT_DISPOSITION)); |
| Assertions.assertEquals(MediaType.TEXT_HTML, response.getHeader(HttpHeaders.CONTENT_TYPE)); |
| |
| try (InputStream is = part.getInputStream()) { |
| Assertions.assertEquals(schemas.get(schemaId), IOUtils.toString(is, StandardCharsets.UTF_8)); |
| } |
| } |
| |
| // create AsciiDoctor, cost seconds |
| @Test |
| public void getSchemaContentById_view_html() throws IOException { |
| testViewHtmlById("schema1"); |
| testViewHtmlById("schema2"); |
| } |
| |
| private void testViewHtmlById(String schemaId) throws IOException { |
| Response response = inspector.getSchemaContentById(schemaId, SchemaFormat.HTML, false); |
| |
| Part part = response.getResult(); |
| Assertions.assertEquals(schemaId + ".html", part.getSubmittedFileName()); |
| Assertions.assertEquals("inline", response.getHeader(HttpHeaders.CONTENT_DISPOSITION)); |
| Assertions.assertEquals(MediaType.TEXT_HTML, response.getHeader(HttpHeaders.CONTENT_TYPE)); |
| |
| try (InputStream is = part.getInputStream()) { |
| Assertions.assertTrue(IOUtils.toString(is, StandardCharsets.UTF_8).endsWith("</html>")); |
| } |
| } |
| |
| @Test |
| public void getSchemaContentById_download_html() throws IOException { |
| testDownloadHtmlById("schema1"); |
| testDownloadHtmlById("schema2"); |
| } |
| |
| private void testDownloadHtmlById(String schemaId) throws IOException { |
| Response response = inspector.getSchemaContentById(schemaId, SchemaFormat.HTML, true); |
| |
| Part part = response.getResult(); |
| Assertions.assertEquals(schemaId + ".html", part.getSubmittedFileName()); |
| Assertions.assertNull(response.getHeader(HttpHeaders.CONTENT_DISPOSITION)); |
| Assertions.assertEquals(MediaType.TEXT_HTML, response.getHeader(HttpHeaders.CONTENT_TYPE)); |
| |
| try (InputStream is = part.getInputStream()) { |
| Assertions.assertTrue(IOUtils.toString(is, StandardCharsets.UTF_8).endsWith("</html>")); |
| } |
| } |
| |
| @Test |
| public void getStaticResource_notExist() throws IOException { |
| Response response = inspector.getStaticResource("notExist"); |
| |
| InvocationException invocationException = response.getResult(); |
| Assertions.assertEquals(Status.NOT_FOUND, invocationException.getStatus()); |
| Assertions.assertEquals(Status.NOT_FOUND.getReasonPhrase(), |
| ((CommonExceptionData) invocationException.getErrorData()).getMessage()); |
| Assertions.assertEquals(404, response.getStatusCode()); |
| Assertions.assertEquals("Not Found", response.getReasonPhrase()); |
| } |
| |
| @Test |
| public void getStaticResource() throws IOException { |
| Response response = inspector.getStaticResource("index.html"); |
| |
| Part part = response.getResult(); |
| Assertions.assertEquals("inline", response.getHeader(HttpHeaders.CONTENT_DISPOSITION)); |
| Assertions.assertEquals(MediaType.TEXT_HTML, response.getHeader(HttpHeaders.CONTENT_TYPE)); |
| |
| try (InputStream is = part.getInputStream()) { |
| Assertions.assertTrue(IOUtils.toString(is, StandardCharsets.UTF_8).endsWith("</html>")); |
| } |
| } |
| |
| @Test |
| public void dynamicProperties() { |
| DynamicProperty.getInstance("zzz"); |
| ArchaiusUtils.setProperty("zzz", "abc"); |
| DynamicProperty.getInstance("yyy").addCallback(() -> { |
| }); |
| |
| List<DynamicPropertyView> views = inspector.dynamicProperties(); |
| Map<String, DynamicPropertyView> viewMap = views.stream() |
| .collect(Collectors.toMap(DynamicPropertyView::getKey, Function.identity())); |
| Assertions.assertEquals(1, viewMap.get("yyy").getCallbackCount()); |
| Assertions.assertEquals(0, viewMap.get("zzz").getCallbackCount()); |
| Assertions.assertEquals(0, viewMap.get("servicecomb.inspector.enabled").getCallbackCount()); |
| Assertions.assertEquals(0, viewMap.get("servicecomb.inspector.swagger.html.asciidoctorCss").getCallbackCount()); |
| |
| int count = ConfigUtil.getAllDynamicProperties().size(); |
| ConfigUtil.getAllDynamicProperties().remove("yyy"); |
| ConfigUtil.getAllDynamicProperties().remove("zzz"); |
| Assertions.assertEquals(count - 2, ConfigUtil.getAllDynamicProperties().size()); |
| } |
| |
| @Test |
| public void priorityProperties() { |
| PriorityPropertyFactory propertyFactory = new PriorityPropertyFactory(); |
| inspector.setPropertyFactory(propertyFactory); |
| |
| propertyFactory.getOrCreate(int.class, 0, 0, "high", "low"); |
| |
| List<PriorityPropertyView> views = inspector.priorityProperties(); |
| Assertions.assertEquals(1, views.size()); |
| MatcherAssert.assertThat( |
| views.get(0).getDynamicProperties().stream().map(DynamicPropertyView::getKey).collect(Collectors.toList()), |
| Matchers.contains("high", "low")); |
| } |
| |
| @Test |
| public void urlPrefix() { |
| InspectorImpl inspector = initInspector("/webroot/rest"); |
| |
| Map<String, String> schemas = Deencapsulation.getField(inspector, "schemas"); |
| Assertions.assertTrue(schemas.get("schema1").indexOf("/webroot/rest/metrics") > 0); |
| } |
| } |