/* * Copyright © 2014-2016 Cask Data, Inc. * * Licensed 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 co.cask.cdap.gateway.router; import co.cask.cdap.common.conf.Constants; import com.google.common.collect.ImmutableList; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpVersion; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; /** * To test the RouterPathLookup regular expression tests. */ public class RouterPathTest { private static RouterPathLookup pathLookup; private static final HttpVersion VERSION = HttpVersion.HTTP_1_1; private static final String API_KEY = "SampleTestApiKey"; private static final String FALLBACKSERVICE = "gateway"; @BeforeClass public static void init() throws Exception { pathLookup = new RouterPathLookup(); } @Test public void testSystemServicePath() { String path = "/v3/system/services/foo/logs"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); String result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); path = "/v3/system/services/foo/live-info"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); // this clashes with a rule for stream handler and fails if the rules are evaluated in wrong order [CDAP-2159] path = "/v3/system/services/streams/logs"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); // this clashes with a rule for stream handler and fails if the rules are evaluated in wrong order [CDAP-2159] path = "/v3/system/services/streams/live-info"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } @Test public void testMetricsPath() throws Exception { //Following URIs might not give actual results but we want to test resilience of Router Path Lookup String flowPath = "/v3///metrics/system/apps/InvalidApp//"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), flowPath); String result = pathLookup.getRoutingService(FALLBACKSERVICE, flowPath, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); flowPath = "/v3/metrics"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("DELETE"), flowPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, flowPath, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); flowPath = "/v3/metrics//"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("POST"), flowPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, flowPath, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); testMetricsPath("/v3/metrics/search?target=tag&tag=namespace:user"); testMetricsPath("/v3/metrics/search?target=tag&tag=app:PurchaeHistory&tag=flow:PurchaseFlow"); testMetricsPath("/v3/metrics/search?target=metric&tag=app:PurchaeHistory&tag=flow:PurchaseFlow"); } private void testMetricsPath(String path) { HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); String result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); } @Test public void testAppFabricPath() throws Exception { //Default destination for URIs will APP_FABRIC_HTTP String path = "/v3/ping/"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); String result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); path = "/status"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); path = "/v3/monitor///abcd/"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("POST"), path); result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } @Test public void testLogPath() throws Exception { //Following URIs might not give actual results but we want to test resilience of Router Path Lookup String flowPath = "/v3/namespaces/default/apps//InvalidApp///flows/FlowName/logs/"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), flowPath); String result = pathLookup.getRoutingService(FALLBACKSERVICE, flowPath, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); flowPath = "///v3/namespaces/default///apps/InvalidApp/flows/FlowName/////logs"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("POST"), flowPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, flowPath, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); flowPath = "/v3/namespaces/default/apps/InvalidApp/service/ServiceName/runs/7e6adc79-0f5d-4252-70817ea47698/logs/"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), flowPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, flowPath, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); } @Test public void testServicePath() throws Exception { // The following two should resort to resort to APP_FABRIC_HTTP, because there is no actual method being called. String servicePath = "v3/namespaces/default/apps/AppName/services/CatalogLookup//methods////"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("PUT"), servicePath); httpRequest.setHeader(Constants.Gateway.API_KEY, API_KEY); String result = pathLookup.getRoutingService(FALLBACKSERVICE, servicePath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); servicePath = "v3/namespaces/some/apps/otherAppName/services/CatalogLookup//methods////"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), servicePath); httpRequest.setHeader(Constants.Gateway.API_KEY, API_KEY); result = pathLookup.getRoutingService(FALLBACKSERVICE, servicePath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); // v3 servicePaths servicePath = "/v3/namespaces/testnamespace/apps//PurchaseHistory///services/CatalogLookup///methods//ping/1"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), servicePath); httpRequest.setHeader(Constants.Gateway.API_KEY, API_KEY); result = pathLookup.getRoutingService(FALLBACKSERVICE, servicePath, httpRequest); Assert.assertEquals("service.testnamespace.PurchaseHistory.CatalogLookup", result); servicePath = "///v3/namespaces/testnamespace//apps/PurchaseHistory-123//services/weird!service@@NAme///methods/" + "echo/someParam"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("POST"), servicePath); httpRequest.setHeader(Constants.Gateway.API_KEY, API_KEY); result = pathLookup.getRoutingService(FALLBACKSERVICE, servicePath, httpRequest); Assert.assertEquals("service.testnamespace.PurchaseHistory-123.weird!service@@NAme", result); servicePath = "v3/namespaces/testnamespace/apps/SomeApp_Name/services/CatalogLookup/methods/getHistory/itemID"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), servicePath); httpRequest.setHeader(Constants.Gateway.API_KEY, API_KEY); result = pathLookup.getRoutingService(FALLBACKSERVICE, servicePath, httpRequest); Assert.assertEquals("service.testnamespace.SomeApp_Name.CatalogLookup", result); servicePath = "v3/namespaces/testnamespace/apps/AppName/services/CatalogLookup//methods////"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("PUT"), servicePath); httpRequest.setHeader(Constants.Gateway.API_KEY, API_KEY); result = pathLookup.getRoutingService(FALLBACKSERVICE, servicePath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); servicePath = "v3/namespaces/testnamespace/apps/AppName/services/CatalogLookup////methods////"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), servicePath); httpRequest.setHeader(Constants.Gateway.API_KEY, API_KEY); result = pathLookup.getRoutingService(FALLBACKSERVICE, servicePath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } @Test public void testStreamPath() throws Exception { //Following URIs might not give actual results but we want to test resilience of Router Path Lookup String streamPath = "/v3/namespaces/default/streams"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), streamPath); String result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); streamPath = "///v3/namespaces/default/streams///"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("POST"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); streamPath = "v3/namespaces/default///streams///"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("PUT"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); streamPath = "//v3/namespaces/default///streams/HelloStream//programs///"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); streamPath = "//v3/namespaces/default///streams/HelloStream//programs///"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("DELETE"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.STREAMS, result); streamPath = "//v3/namespaces/default///streams/HelloStream//programs///"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("POST"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.STREAMS, result); streamPath = "v3/namespaces/default//streams//flows///"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("DELETE"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.STREAMS, result); streamPath = "v3/namespaces/default//streams/InvalidStreamName/programs/"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); streamPath = "v3/namespaces/default//streams/InvalidStreamName/programs"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); streamPath = "v3/namespaces/default//streams/InvalidStreamName/programs/"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("DELETE"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.STREAMS, result); streamPath = "v3/namespaces/default//streams/InvalidStreamName/info/"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), streamPath); result = pathLookup.getRoutingService(FALLBACKSERVICE, streamPath, httpRequest); Assert.assertEquals(Constants.Service.STREAMS, result); } @Test public void testRouterFlowPathLookUp() throws Exception { String flowPath = "/v3/namespaces/default//apps/ResponseCodeAnalytics/flows/LogAnalyticsFlow/status"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), flowPath); String result = pathLookup.getRoutingService(FALLBACKSERVICE, flowPath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } @Test public void testRouterWorkFlowPathLookUp() throws Exception { String path = "/v3/namespaces/default/apps///PurchaseHistory///workflows/PurchaseHistoryWorkflow/status"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); String result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } @Test public void testRouterDeployPathLookUp() throws Exception { String path = "/v3/namespaces/default//apps/"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("PUT"), path); String result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } @Test public void testRouterFlowletInstancesLookUp() throws Exception { String path = "/v3/namespaces/default//apps/WordCount/flows/WordCountFlow/flowlets/StreamSource/instances"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("PUT"), path); String result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } @Test public void testRouterExplorePathLookUp() throws Exception { String explorePath = "/v3/namespaces/default//data///explore//datasets////mydataset//enable"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("POST"), explorePath); String result = pathLookup.getRoutingService(FALLBACKSERVICE, explorePath, httpRequest); Assert.assertEquals(Constants.Service.EXPLORE_HTTP_USER_SERVICE, result); } @Test public void testRouterExploreStatusPathLookUp() throws Exception { String explorePath = "/v3/explore/status"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), explorePath); String result = pathLookup.getRoutingService(FALLBACKSERVICE, explorePath, httpRequest); Assert.assertEquals(Constants.Service.EXPLORE_HTTP_USER_SERVICE, result); } @Test public void testRouterWebAppPathLookUp() throws Exception { //Calls to webapp service with appName in the first split of URI will be routed to webappService //But if it has v2 then use the regular router lookup logic to find the appropriate service final String webAppService = "webapp$HOST"; String path = "/sentiApp/abcd/efgh///"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); String result = pathLookup.getRoutingService(webAppService, path, httpRequest); Assert.assertEquals(webAppService, result); path = "/v3//metrics///"; httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), path); result = pathLookup.getRoutingService(webAppService, path, httpRequest); Assert.assertEquals(Constants.Service.METRICS, result); } @Test public void testRouterV3PathLookup() { final String namespacePath = "/v3////namespace/////"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("GET"), namespacePath); String result = pathLookup.getRoutingService(FALLBACKSERVICE, namespacePath, httpRequest); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } @Test public void testRouterFeedsLookup() { final String namespacePath = "/v3//feeds/test"; HttpRequest httpRequest = new DefaultHttpRequest(VERSION, new HttpMethod("PUT"), namespacePath); String result = pathLookup.getRoutingService(FALLBACKSERVICE, namespacePath, httpRequest); Assert.assertEquals(null, result); } @Test public void testMetadataPath() { // all app metadata assertMetadataRouting("/v3/namespaces/default//apps/WordCount//////metadata"); // all artifact metadata assertMetadataRouting("/v3/namespaces/default//artifacts/WordCount///versions/v1//metadata"); // all program metadata assertMetadataRouting("/v3/namespaces/default//apps/WordCount//flows//WordCountFlow//metadata"); // all dataset metadata assertMetadataRouting("/v3/namespaces/default//datasets/ds1//////metadata"); // all stream metadata assertMetadataRouting("/v3/namespaces/default//streams/s1//////metadata"); // all stream view metadata assertMetadataRouting("/v3/namespaces/default//streams/s1//views/v1///metadata"); // app metadata properties assertMetadataRouting("/v3/namespaces/default//apps/WordCount//////metadata///////properties"); // artifact metadata properties assertMetadataRouting("/v3/namespaces/default//artifacts/WordCount///versions/v1//metadata/properties"); // program metadata properties assertMetadataRouting("/v3/namespaces/default//apps/WordCount/flows/WordCountFlow/metadata/properties"); // dataset metadata properties assertMetadataRouting("/v3/namespaces/default/////datasets/ds1/metadata/properties"); // stream metadata properties assertMetadataRouting("/v3/namespaces////default////streams//s1/metadata/properties"); // stream view metadata properties assertMetadataRouting("/v3/namespaces////default////streams//s1/views/v1/metadata/properties"); // app metadata tags assertMetadataRouting("/v3/namespaces/default//apps/WordCount/////metadata/tags"); // artifact metadata tags assertMetadataRouting("/v3/namespaces/default//artifacts/WordCount//versions//1.0/metadata/tags"); // program metadata tags assertMetadataRouting("/v3/namespaces/default//apps/WordCount/flows/WordCountFlow/metadata/tags"); // dataset metadata tags assertMetadataRouting("/v3/namespaces/default/////datasets/ds1/metadata/tags"); // stream metadata tags assertMetadataRouting("/v3/namespaces////default////streams//s1/metadata/tags"); // stream views metadata tags assertMetadataRouting("/v3/namespaces////default////streams//s1//////views/////v1//metadata/tags"); // search metadata assertMetadataRouting("/v3/namespaces/default/metadata/search"); // lineage assertMetadataRouting("/v3/namespaces/default/////datasets/ds1/lineage"); assertMetadataRouting("/v3/namespaces/default/streams/st1/lineage"); // get metadata for accesses assertMetadataRouting("/v3/namespaces/default//apps/WordCount/flows/WordCountFlow/runs/runid/metadata"); } @Test public void testAuthorizationPaths() { assertAuthorizationRouting("/v3/////security/authorization/privileges///grant", HttpMethod.POST); assertAuthorizationRouting("/v3/security/authorization/////privileges/revoke", HttpMethod.POST); assertAuthorizationRouting("/v3/security/authorization/user/alice/privileges", HttpMethod.GET); assertAuthorizationRouting("/v3/security/authorization/roles/admins////", HttpMethod.GET); assertAuthorizationRouting("/v3/security/authorization/roles/admins", HttpMethod.DELETE); assertAuthorizationRouting("/v3/security/authorization/roles", HttpMethod.GET); assertAuthorizationRouting("/v3/security/authorization/group/devs/roles", HttpMethod.GET); assertAuthorizationRouting("/v3/security/authorization/group/devs/roles/admins", HttpMethod.PUT); assertAuthorizationRouting("//v3/security/authorization/group/devs/roles/admins", HttpMethod.DELETE); } private void assertMetadataRouting(String path) { for (HttpMethod method : ImmutableList.of(HttpMethod.GET, HttpMethod.POST, HttpMethod.DELETE)) { HttpRequest httpRequest = new DefaultHttpRequest(VERSION, method, path); String result = pathLookup.getRoutingService(FALLBACKSERVICE, path, httpRequest); Assert.assertEquals(Constants.Service.METADATA_SERVICE, result); } } private void assertAuthorizationRouting(String path, HttpMethod method) { HttpRequest request = new DefaultHttpRequest(VERSION, method, path); String result = pathLookup.getRoutingService(FALLBACKSERVICE, path, request); Assert.assertEquals(Constants.Service.APP_FABRIC_HTTP, result); } }