blob: e653c4aa2121785c99badb59900776237f9d8ae9 [file] [log] [blame]
/*
* 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);
}
}