init
This commit is contained in:
107
visual/sentinel-dashboard/src/test/java/Test.java
Normal file
107
visual/sentinel-dashboard/src/test/java/Test.java
Normal file
@@ -0,0 +1,107 @@
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Description:
|
||||
* @Author: Gary
|
||||
* @DateTime:2022/11/13 23:19
|
||||
* @Version: V2.0
|
||||
*/
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Test().mains();
|
||||
}
|
||||
|
||||
public void mains() {
|
||||
List<User> userList = new ArrayList<>();
|
||||
userList.add(new User("1","test1","1"));
|
||||
userList.add(new User("2","test2","2"));
|
||||
userList.add(new User("3","test3","2"));
|
||||
userList.add(new User("4","test4","2"));
|
||||
userList.add(new User("5","test5","1"));
|
||||
|
||||
Map<String,List<User>> listMap = new HashMap<>();
|
||||
for (User user : userList) {
|
||||
List<User> users = listMap.get(user.getUserType());
|
||||
if (users == null || users.isEmpty()){
|
||||
users = new ArrayList<>();
|
||||
}
|
||||
users.add(user);
|
||||
listMap.put(user.getUserType(),users);
|
||||
}
|
||||
|
||||
Map<String, User> collect = userList.stream().collect(Collectors.toMap(User::getId, Function.identity()));
|
||||
Map<User, String> collect1 = userList.stream().collect(Collectors.toMap(Function.identity(), User::getId));
|
||||
|
||||
Map<String, List<User>> collect2 = userList.stream().collect(Collectors.groupingBy(User::getUserType));
|
||||
|
||||
Set<String> strings = collect2.keySet();
|
||||
|
||||
|
||||
collect.forEach((k,v)->{
|
||||
System.out.println(k+"k");
|
||||
System.out.println(v.toString());
|
||||
});
|
||||
|
||||
userList.forEach(user -> {
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
System.out.println("");
|
||||
|
||||
|
||||
}
|
||||
|
||||
class User{
|
||||
|
||||
public User(String id, String username, String userType) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.userType = userType;
|
||||
}
|
||||
|
||||
private String id;
|
||||
|
||||
private String username;
|
||||
|
||||
private String userType;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getUserType() {
|
||||
return userType;
|
||||
}
|
||||
|
||||
public void setUserType(String userType) {
|
||||
this.userType = userType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" +
|
||||
"id='" + id + '\'' +
|
||||
", username='" + username + '\'' +
|
||||
", userType='" + userType + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.protocol.RequestContent;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SentinelApiClientTest {
|
||||
@Test
|
||||
public void postRequest() throws HttpException, IOException {
|
||||
// Processor is required because it will determine the final request body including
|
||||
// headers before outgoing.
|
||||
RequestContent processor = new RequestContent();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("a", "1");
|
||||
params.put("b", "2+");
|
||||
params.put("c", "3 ");
|
||||
|
||||
HttpUriRequest request;
|
||||
|
||||
request = SentinelApiClient.postRequest("/test", params, false);
|
||||
assertNotNull(request);
|
||||
processor.process(request, null);
|
||||
assertNotNull(request.getFirstHeader("Content-Type"));
|
||||
assertEquals("application/x-www-form-urlencoded", request.getFirstHeader("Content-Type").getValue());
|
||||
|
||||
request = SentinelApiClient.postRequest("/test", params, true);
|
||||
assertNotNull(request);
|
||||
processor.process(request, null);
|
||||
assertNotNull(request.getFirstHeader("Content-Type"));
|
||||
assertEquals("application/x-www-form-urlencoded; charset=UTF-8", request.getFirstHeader("Content-Type").getValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.contrib.java.lang.system.EnvironmentVariables;
|
||||
|
||||
public class DashboardConfigTest {
|
||||
@Rule
|
||||
public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
|
||||
|
||||
@Test
|
||||
public void testGetConfigStr() {
|
||||
// clear cache
|
||||
DashboardConfig.clearCache();
|
||||
|
||||
// if not set, return null
|
||||
assertEquals(null, DashboardConfig.getConfigStr("a"));
|
||||
|
||||
// test property
|
||||
System.setProperty("a", "111");
|
||||
assertEquals("111", DashboardConfig.getConfigStr("a"));
|
||||
|
||||
// test env
|
||||
environmentVariables.set("a", "222");
|
||||
// return value in cache
|
||||
assertEquals("111", DashboardConfig.getConfigStr("a"));
|
||||
|
||||
// clear cache and then test
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals("222", DashboardConfig.getConfigStr("a"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetConfigInt() {
|
||||
// clear cache
|
||||
DashboardConfig.clearCache();
|
||||
|
||||
// default value
|
||||
assertEquals(0, DashboardConfig.getConfigInt("t", 0, 10));
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(1, DashboardConfig.getConfigInt("t", 1, 10));
|
||||
|
||||
// property, wrong format
|
||||
System.setProperty("t", "asdf");
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(0, DashboardConfig.getConfigInt("t", 0, 10));
|
||||
System.setProperty("t", "");
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(0, DashboardConfig.getConfigInt("t", 0, 10));
|
||||
|
||||
// min value
|
||||
System.setProperty("t", "2");
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(2, DashboardConfig.getConfigInt("t", 0, 1));
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(10, DashboardConfig.getConfigInt("t", 0, 10));
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(2, DashboardConfig.getConfigInt("t", 0, -1));
|
||||
|
||||
// env
|
||||
environmentVariables.set("t", "20");
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(20, DashboardConfig.getConfigInt("t", 0, 10));
|
||||
|
||||
// wrong format env var, but it will override property
|
||||
environmentVariables.set("t", "20dddd");
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(0, DashboardConfig.getConfigInt("t", 0, 10));
|
||||
|
||||
// clear env, it will take property
|
||||
environmentVariables.set("t", "");
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(10, DashboardConfig.getConfigInt("t", 0, 10));
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(2, DashboardConfig.getConfigInt("t", 0, 1));
|
||||
|
||||
// enable cache
|
||||
System.setProperty("t", "666");
|
||||
DashboardConfig.clearCache();
|
||||
assertEquals(666, DashboardConfig.getConfigInt("t", 0, 1));
|
||||
System.setProperty("t", "777");
|
||||
assertEquals(666, DashboardConfig.getConfigInt("t", 0, 1));
|
||||
System.setProperty("t", "555");
|
||||
assertEquals(666, DashboardConfig.getConfigInt("t", 0, 1));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.config;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.FakeAuthServiceImpl;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* disable auth in test.
|
||||
*
|
||||
* @author wxq
|
||||
*/
|
||||
@TestConfiguration
|
||||
@Import(AuthConfiguration.class)
|
||||
public class NoAuthConfigurationTest {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public AuthService<HttpServletRequest> httpServletRequestNoopAuthService() {
|
||||
return new FakeAuthServiceImpl();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.controller.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
|
||||
import com.alibaba.csp.sentinel.dashboard.config.NoAuthConfigurationTest;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiPredicateItemEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.SimpleMachineDiscovery;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.AddApiReqVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.ApiPredicateItemVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.UpdateApiReqVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemApiDefinitionStore;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.URL_MATCH_STRATEGY_EXACT;
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.any;
|
||||
import static org.mockito.BDDMockito.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.mock;
|
||||
import static org.mockito.BDDMockito.verify;
|
||||
|
||||
/**
|
||||
* Test cases for {@link GatewayApiController}.
|
||||
*
|
||||
* @author cdfive
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(GatewayApiController.class)
|
||||
@Import({NoAuthConfigurationTest.class, InMemApiDefinitionStore.class, AppManagement.class, SimpleMachineDiscovery.class})
|
||||
public class GatewayApiControllerTest {
|
||||
|
||||
private static final String TEST_APP = "test_app";
|
||||
|
||||
private static final String TEST_IP = "localhost";
|
||||
|
||||
private static final Integer TEST_PORT = 8719;
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private InMemApiDefinitionStore repository;
|
||||
|
||||
@MockBean
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
repository.clearAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryApis() throws Exception {
|
||||
String path = "/gateway/api/list.json";
|
||||
|
||||
List<ApiDefinitionEntity> entities = new ArrayList<>();
|
||||
|
||||
// Mock two entities
|
||||
ApiDefinitionEntity entity = new ApiDefinitionEntity();
|
||||
entity.setId(1L);
|
||||
entity.setApp(TEST_APP);
|
||||
entity.setIp(TEST_IP);
|
||||
entity.setPort(TEST_PORT);
|
||||
entity.setApiName("foo");
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
|
||||
Set<ApiPredicateItemEntity> itemEntities = new LinkedHashSet<>();
|
||||
entity.setPredicateItems(itemEntities);
|
||||
ApiPredicateItemEntity itemEntity = new ApiPredicateItemEntity();
|
||||
itemEntity.setPattern("/aaa");
|
||||
itemEntity.setMatchStrategy(URL_MATCH_STRATEGY_EXACT);
|
||||
|
||||
itemEntities.add(itemEntity);
|
||||
entities.add(entity);
|
||||
|
||||
ApiDefinitionEntity entity2 = new ApiDefinitionEntity();
|
||||
entity2.setId(2L);
|
||||
entity2.setApp(TEST_APP);
|
||||
entity2.setIp(TEST_IP);
|
||||
entity2.setPort(TEST_PORT);
|
||||
entity2.setApiName("biz");
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
|
||||
Set<ApiPredicateItemEntity> itemEntities2 = new LinkedHashSet<>();
|
||||
entity2.setPredicateItems(itemEntities2);
|
||||
ApiPredicateItemEntity itemEntity2 = new ApiPredicateItemEntity();
|
||||
itemEntity2.setPattern("/bbb");
|
||||
itemEntity2.setMatchStrategy(URL_MATCH_STRATEGY_PREFIX);
|
||||
|
||||
itemEntities2.add(itemEntity2);
|
||||
entities.add(entity2);
|
||||
|
||||
CompletableFuture<List<ApiDefinitionEntity>> completableFuture = mock(CompletableFuture.class);
|
||||
given(completableFuture.get()).willReturn(entities);
|
||||
given(sentinelApiClient.fetchApis(TEST_APP, TEST_IP, TEST_PORT)).willReturn(completableFuture);
|
||||
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(path);
|
||||
requestBuilder.param("app", TEST_APP);
|
||||
requestBuilder.param("ip", TEST_IP);
|
||||
requestBuilder.param("port", String.valueOf(TEST_PORT));
|
||||
|
||||
// Do controller logic
|
||||
MvcResult mvcResult = mockMvc.perform(requestBuilder)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
|
||||
|
||||
// Verify the fetchApis method has been called
|
||||
verify(sentinelApiClient).fetchApis(TEST_APP, TEST_IP, TEST_PORT);
|
||||
|
||||
// Verify if two same entities are got
|
||||
Result<List<ApiDefinitionEntity>> result = JSONObject.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<List<ApiDefinitionEntity>>>(){});
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
List<ApiDefinitionEntity> data = result.getData();
|
||||
assertEquals(2, data.size());
|
||||
assertEquals(entities, data);
|
||||
|
||||
// Verify the entities are add into memory repository
|
||||
List<ApiDefinitionEntity> entitiesInMem = repository.findAllByApp(TEST_APP);
|
||||
assertEquals(2, entitiesInMem.size());
|
||||
assertEquals(entities, entitiesInMem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddApi() throws Exception {
|
||||
String path = "/gateway/api/new.json";
|
||||
|
||||
AddApiReqVo reqVo = new AddApiReqVo();
|
||||
reqVo.setApp(TEST_APP);
|
||||
reqVo.setIp(TEST_IP);
|
||||
reqVo.setPort(TEST_PORT);
|
||||
|
||||
reqVo.setApiName("customized_api");
|
||||
|
||||
List<ApiPredicateItemVo> itemVos = new ArrayList<>();
|
||||
ApiPredicateItemVo itemVo = new ApiPredicateItemVo();
|
||||
itemVo.setMatchStrategy(URL_MATCH_STRATEGY_EXACT);
|
||||
itemVo.setPattern("/product");
|
||||
itemVos.add(itemVo);
|
||||
reqVo.setPredicateItems(itemVos);
|
||||
|
||||
given(sentinelApiClient.modifyApis(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any())).willReturn(true);
|
||||
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(path);
|
||||
requestBuilder.content(JSON.toJSONString(reqVo)).contentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
// Do controller logic
|
||||
MvcResult mvcResult = mockMvc.perform(requestBuilder)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andDo(MockMvcResultHandlers.print()).andReturn();
|
||||
|
||||
// Verify the modifyApis method has been called
|
||||
verify(sentinelApiClient).modifyApis(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any());
|
||||
|
||||
Result<ApiDefinitionEntity> result = JSONObject.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<ApiDefinitionEntity>>() {});
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
// Verify the result
|
||||
ApiDefinitionEntity entity = result.getData();
|
||||
assertNotNull(entity);
|
||||
assertEquals(TEST_APP, entity.getApp());
|
||||
assertEquals(TEST_IP, entity.getIp());
|
||||
assertEquals(TEST_PORT, entity.getPort());
|
||||
assertEquals("customized_api", entity.getApiName());
|
||||
assertNotNull(entity.getId());
|
||||
assertNotNull(entity.getGmtCreate());
|
||||
assertNotNull(entity.getGmtModified());
|
||||
|
||||
Set<ApiPredicateItemEntity> predicateItemEntities = entity.getPredicateItems();
|
||||
assertEquals(1, predicateItemEntities.size());
|
||||
ApiPredicateItemEntity predicateItemEntity = predicateItemEntities.iterator().next();
|
||||
assertEquals(URL_MATCH_STRATEGY_EXACT, predicateItemEntity.getMatchStrategy().intValue());
|
||||
assertEquals("/product", predicateItemEntity.getPattern());
|
||||
|
||||
// Verify the entity which is add in memory repository
|
||||
List<ApiDefinitionEntity> entitiesInMem = repository.findAllByApp(TEST_APP);
|
||||
assertEquals(1, entitiesInMem.size());
|
||||
assertEquals(entity, entitiesInMem.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateApi() throws Exception {
|
||||
String path = "/gateway/api/save.json";
|
||||
|
||||
// Add one entity to memory repository for update
|
||||
ApiDefinitionEntity addEntity = new ApiDefinitionEntity();
|
||||
addEntity.setApp(TEST_APP);
|
||||
addEntity.setIp(TEST_IP);
|
||||
addEntity.setPort(TEST_PORT);
|
||||
addEntity.setApiName("bbb");
|
||||
Date date = new Date();
|
||||
// To make the gmtModified different when do update
|
||||
date = DateUtils.addSeconds(date, -1);
|
||||
addEntity.setGmtCreate(date);
|
||||
addEntity.setGmtModified(date);
|
||||
Set<ApiPredicateItemEntity> addRedicateItemEntities = new HashSet<>();
|
||||
addEntity.setPredicateItems(addRedicateItemEntities);
|
||||
ApiPredicateItemEntity addPredicateItemEntity = new ApiPredicateItemEntity();
|
||||
addPredicateItemEntity.setMatchStrategy(URL_MATCH_STRATEGY_EXACT);
|
||||
addPredicateItemEntity.setPattern("/order");
|
||||
addEntity = repository.save(addEntity);
|
||||
|
||||
UpdateApiReqVo reqVo = new UpdateApiReqVo();
|
||||
reqVo.setId(addEntity.getId());
|
||||
reqVo.setApp(TEST_APP);
|
||||
List<ApiPredicateItemVo> itemVos = new ArrayList<>();
|
||||
ApiPredicateItemVo itemVo = new ApiPredicateItemVo();
|
||||
itemVo.setMatchStrategy(URL_MATCH_STRATEGY_PREFIX);
|
||||
itemVo.setPattern("/my_order");
|
||||
itemVos.add(itemVo);
|
||||
reqVo.setPredicateItems(itemVos);
|
||||
|
||||
given(sentinelApiClient.modifyApis(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any())).willReturn(true);
|
||||
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(path);
|
||||
requestBuilder.content(JSON.toJSONString(reqVo)).contentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
// Do controller logic
|
||||
MvcResult mvcResult = mockMvc.perform(requestBuilder)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andDo(MockMvcResultHandlers.print()).andReturn();
|
||||
|
||||
// Verify the modifyApis method has been called
|
||||
verify(sentinelApiClient).modifyApis(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any());
|
||||
|
||||
Result<ApiDefinitionEntity> result = JSONObject.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<ApiDefinitionEntity>>() {});
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
ApiDefinitionEntity entity = result.getData();
|
||||
assertNotNull(entity);
|
||||
assertEquals("bbb", entity.getApiName());
|
||||
assertEquals(date, entity.getGmtCreate());
|
||||
// To make sure gmtModified has been set and it's different from gmtCreate
|
||||
assertNotNull(entity.getGmtModified());
|
||||
assertNotEquals(entity.getGmtCreate(), entity.getGmtModified());
|
||||
|
||||
Set<ApiPredicateItemEntity> predicateItemEntities = entity.getPredicateItems();
|
||||
assertEquals(1, predicateItemEntities.size());
|
||||
ApiPredicateItemEntity predicateItemEntity = predicateItemEntities.iterator().next();
|
||||
assertEquals(URL_MATCH_STRATEGY_PREFIX, predicateItemEntity.getMatchStrategy().intValue());
|
||||
assertEquals("/my_order", predicateItemEntity.getPattern());
|
||||
|
||||
// Verify the entity which is update in memory repository
|
||||
List<ApiDefinitionEntity> entitiesInMem = repository.findAllByApp(TEST_APP);
|
||||
assertEquals(1, entitiesInMem.size());
|
||||
assertEquals(entity, entitiesInMem.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteApi() throws Exception {
|
||||
String path = "/gateway/api/delete.json";
|
||||
|
||||
// Add one entity into memory repository for delete
|
||||
ApiDefinitionEntity addEntity = new ApiDefinitionEntity();
|
||||
addEntity.setApp(TEST_APP);
|
||||
addEntity.setIp(TEST_IP);
|
||||
addEntity.setPort(TEST_PORT);
|
||||
addEntity.setApiName("ccc");
|
||||
Date date = new Date();
|
||||
addEntity.setGmtCreate(date);
|
||||
addEntity.setGmtModified(date);
|
||||
Set<ApiPredicateItemEntity> addRedicateItemEntities = new HashSet<>();
|
||||
addEntity.setPredicateItems(addRedicateItemEntities);
|
||||
ApiPredicateItemEntity addPredicateItemEntity = new ApiPredicateItemEntity();
|
||||
addPredicateItemEntity.setMatchStrategy(URL_MATCH_STRATEGY_EXACT);
|
||||
addPredicateItemEntity.setPattern("/user/add");
|
||||
addEntity = repository.save(addEntity);
|
||||
|
||||
given(sentinelApiClient.modifyApis(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any())).willReturn(true);
|
||||
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(path);
|
||||
requestBuilder.param("id", String.valueOf(addEntity.getId()));
|
||||
|
||||
// Do controller logic
|
||||
MvcResult mvcResult = mockMvc.perform(requestBuilder)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
|
||||
|
||||
// Verify the modifyApis method has been called
|
||||
verify(sentinelApiClient).modifyApis(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any());
|
||||
|
||||
// Verify the result
|
||||
Result<Long> result = JSONObject.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<Long>>() {});
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
assertEquals(addEntity.getId(), result.getData());
|
||||
|
||||
// Now no entities in memory
|
||||
List<ApiDefinitionEntity> entitiesInMem = repository.findAllByApp(TEST_APP);
|
||||
assertEquals(0, entitiesInMem.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.controller.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
|
||||
import com.alibaba.csp.sentinel.dashboard.config.NoAuthConfigurationTest;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayParamFlowItemEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.SimpleMachineDiscovery;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.AddFlowRuleReqVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.GatewayParamFlowItemVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.UpdateFlowRuleReqVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemGatewayFlowRuleStore;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP;
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM;
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME;
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID;
|
||||
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.CONTROL_BEHAVIOR_DEFAULT;
|
||||
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER;
|
||||
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.FLOW_GRADE_QPS;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.any;
|
||||
import static org.mockito.BDDMockito.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.mock;
|
||||
import static org.mockito.BDDMockito.verify;
|
||||
|
||||
/**
|
||||
* Test cases for {@link GatewayFlowRuleController}.
|
||||
*
|
||||
* @author cdfive
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(GatewayFlowRuleController.class)
|
||||
@Import({NoAuthConfigurationTest.class, InMemGatewayFlowRuleStore.class, AppManagement.class, SimpleMachineDiscovery.class})
|
||||
public class GatewayFlowRuleControllerTest {
|
||||
|
||||
private static final String TEST_APP = "test_app";
|
||||
|
||||
private static final String TEST_IP = "localhost";
|
||||
|
||||
private static final Integer TEST_PORT = 8719;
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private InMemGatewayFlowRuleStore repository;
|
||||
|
||||
@MockBean
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
repository.clearAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryFlowRules() throws Exception {
|
||||
String path = "/gateway/flow/list.json";
|
||||
|
||||
List<GatewayFlowRuleEntity> entities = new ArrayList<>();
|
||||
|
||||
// Mock two entities
|
||||
GatewayFlowRuleEntity entity = new GatewayFlowRuleEntity();
|
||||
entity.setId(1L);
|
||||
entity.setApp(TEST_APP);
|
||||
entity.setIp(TEST_IP);
|
||||
entity.setPort(TEST_PORT);
|
||||
entity.setResource("httpbin_route");
|
||||
entity.setResourceMode(RESOURCE_MODE_ROUTE_ID);
|
||||
entity.setGrade(FLOW_GRADE_QPS);
|
||||
entity.setCount(5D);
|
||||
entity.setInterval(30L);
|
||||
entity.setIntervalUnit(GatewayFlowRuleEntity.INTERVAL_UNIT_SECOND);
|
||||
entity.setControlBehavior(CONTROL_BEHAVIOR_DEFAULT);
|
||||
entity.setBurst(0);
|
||||
entity.setMaxQueueingTimeoutMs(0);
|
||||
|
||||
GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity();
|
||||
entity.setParamItem(itemEntity);
|
||||
itemEntity.setParseStrategy(PARAM_PARSE_STRATEGY_CLIENT_IP);
|
||||
entities.add(entity);
|
||||
|
||||
GatewayFlowRuleEntity entity2 = new GatewayFlowRuleEntity();
|
||||
entity2.setId(2L);
|
||||
entity2.setApp(TEST_APP);
|
||||
entity2.setIp(TEST_IP);
|
||||
entity2.setPort(TEST_PORT);
|
||||
entity2.setResource("some_customized_api");
|
||||
entity2.setResourceMode(RESOURCE_MODE_CUSTOM_API_NAME);
|
||||
entity2.setCount(30D);
|
||||
entity2.setInterval(2L);
|
||||
entity2.setIntervalUnit(GatewayFlowRuleEntity.INTERVAL_UNIT_MINUTE);
|
||||
entity2.setControlBehavior(CONTROL_BEHAVIOR_DEFAULT);
|
||||
entity2.setBurst(0);
|
||||
entity2.setMaxQueueingTimeoutMs(0);
|
||||
|
||||
GatewayParamFlowItemEntity itemEntity2 = new GatewayParamFlowItemEntity();
|
||||
entity2.setParamItem(itemEntity2);
|
||||
itemEntity2.setParseStrategy(PARAM_PARSE_STRATEGY_CLIENT_IP);
|
||||
entities.add(entity2);
|
||||
|
||||
CompletableFuture<List<GatewayFlowRuleEntity>> completableFuture = mock(CompletableFuture.class);
|
||||
given(completableFuture.get()).willReturn(entities);
|
||||
given(sentinelApiClient.fetchGatewayFlowRules(TEST_APP, TEST_IP, TEST_PORT)).willReturn(completableFuture);
|
||||
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(path);
|
||||
requestBuilder.param("app", TEST_APP);
|
||||
requestBuilder.param("ip", TEST_IP);
|
||||
requestBuilder.param("port", String.valueOf(TEST_PORT));
|
||||
|
||||
// Do controller logic
|
||||
MvcResult mvcResult = mockMvc.perform(requestBuilder)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
|
||||
|
||||
// Verify the fetchGatewayFlowRules method has been called
|
||||
verify(sentinelApiClient).fetchGatewayFlowRules(TEST_APP, TEST_IP, TEST_PORT);
|
||||
|
||||
// Verify if two same entities are got
|
||||
Result<List<GatewayFlowRuleEntity>> result = JSONObject.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<List<GatewayFlowRuleEntity>>>(){});
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
List<GatewayFlowRuleEntity> data = result.getData();
|
||||
assertEquals(2, data.size());
|
||||
assertEquals(entities, data);
|
||||
|
||||
// Verify the entities are add into memory repository
|
||||
List<GatewayFlowRuleEntity> entitiesInMem = repository.findAllByApp(TEST_APP);
|
||||
assertEquals(2, entitiesInMem.size());
|
||||
assertEquals(entities, entitiesInMem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddFlowRule() throws Exception {
|
||||
String path = "/gateway/flow/new.json";
|
||||
|
||||
AddFlowRuleReqVo reqVo = new AddFlowRuleReqVo();
|
||||
reqVo.setApp(TEST_APP);
|
||||
reqVo.setIp(TEST_IP);
|
||||
reqVo.setPort(TEST_PORT);
|
||||
|
||||
reqVo.setResourceMode(RESOURCE_MODE_ROUTE_ID);
|
||||
reqVo.setResource("httpbin_route");
|
||||
|
||||
reqVo.setGrade(FLOW_GRADE_QPS);
|
||||
reqVo.setCount(5D);
|
||||
reqVo.setInterval(30L);
|
||||
reqVo.setIntervalUnit(GatewayFlowRuleEntity.INTERVAL_UNIT_SECOND);
|
||||
reqVo.setControlBehavior(CONTROL_BEHAVIOR_DEFAULT);
|
||||
reqVo.setBurst(0);
|
||||
reqVo.setMaxQueueingTimeoutMs(0);
|
||||
|
||||
given(sentinelApiClient.modifyGatewayFlowRules(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any())).willReturn(true);
|
||||
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(path);
|
||||
requestBuilder.content(JSON.toJSONString(reqVo)).contentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
// Do controller logic
|
||||
MvcResult mvcResult = mockMvc.perform(requestBuilder)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andDo(MockMvcResultHandlers.print()).andReturn();
|
||||
|
||||
// Verify the modifyGatewayFlowRules method has been called
|
||||
verify(sentinelApiClient).modifyGatewayFlowRules(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any());
|
||||
|
||||
Result<GatewayFlowRuleEntity> result = JSONObject.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<GatewayFlowRuleEntity>>() {});
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
// Verify the result
|
||||
GatewayFlowRuleEntity entity = result.getData();
|
||||
assertNotNull(entity);
|
||||
assertEquals(TEST_APP, entity.getApp());
|
||||
assertEquals(TEST_IP, entity.getIp());
|
||||
assertEquals(TEST_PORT, entity.getPort());
|
||||
assertEquals(RESOURCE_MODE_ROUTE_ID, entity.getResourceMode().intValue());
|
||||
assertEquals("httpbin_route", entity.getResource());
|
||||
assertNotNull(entity.getId());
|
||||
assertNotNull(entity.getGmtCreate());
|
||||
assertNotNull(entity.getGmtModified());
|
||||
|
||||
// Verify the entity which is add in memory repository
|
||||
List<GatewayFlowRuleEntity> entitiesInMem = repository.findAllByApp(TEST_APP);
|
||||
assertEquals(1, entitiesInMem.size());
|
||||
assertEquals(entity, entitiesInMem.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateFlowRule() throws Exception {
|
||||
String path = "/gateway/flow/save.json";
|
||||
|
||||
// Add one entity into memory repository for update
|
||||
GatewayFlowRuleEntity addEntity = new GatewayFlowRuleEntity();
|
||||
addEntity.setId(1L);
|
||||
addEntity.setApp(TEST_APP);
|
||||
addEntity.setIp(TEST_IP);
|
||||
addEntity.setPort(TEST_PORT);
|
||||
addEntity.setResource("httpbin_route");
|
||||
addEntity.setResourceMode(RESOURCE_MODE_ROUTE_ID);
|
||||
addEntity.setGrade(FLOW_GRADE_QPS);
|
||||
addEntity.setCount(5D);
|
||||
addEntity.setInterval(30L);
|
||||
addEntity.setIntervalUnit(GatewayFlowRuleEntity.INTERVAL_UNIT_SECOND);
|
||||
addEntity.setControlBehavior(CONTROL_BEHAVIOR_DEFAULT);
|
||||
addEntity.setBurst(0);
|
||||
addEntity.setMaxQueueingTimeoutMs(0);
|
||||
Date date = new Date();
|
||||
// To make the gmtModified different when do update
|
||||
date = DateUtils.addSeconds(date, -1);
|
||||
addEntity.setGmtCreate(date);
|
||||
addEntity.setGmtModified(date);
|
||||
|
||||
GatewayParamFlowItemEntity addItemEntity = new GatewayParamFlowItemEntity();
|
||||
addEntity.setParamItem(addItemEntity);
|
||||
addItemEntity.setParseStrategy(PARAM_PARSE_STRATEGY_CLIENT_IP);
|
||||
|
||||
repository.save(addEntity);
|
||||
|
||||
UpdateFlowRuleReqVo reqVo = new UpdateFlowRuleReqVo();
|
||||
reqVo.setId(addEntity.getId());
|
||||
reqVo.setApp(TEST_APP);
|
||||
reqVo.setGrade(FLOW_GRADE_QPS);
|
||||
reqVo.setCount(6D);
|
||||
reqVo.setInterval(2L);
|
||||
reqVo.setIntervalUnit(GatewayFlowRuleEntity.INTERVAL_UNIT_MINUTE);
|
||||
reqVo.setControlBehavior(CONTROL_BEHAVIOR_RATE_LIMITER);
|
||||
reqVo.setMaxQueueingTimeoutMs(500);
|
||||
|
||||
GatewayParamFlowItemVo itemVo = new GatewayParamFlowItemVo();
|
||||
reqVo.setParamItem(itemVo);
|
||||
itemVo.setParseStrategy(PARAM_PARSE_STRATEGY_URL_PARAM);
|
||||
itemVo.setFieldName("pa");
|
||||
|
||||
given(sentinelApiClient.modifyGatewayFlowRules(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any())).willReturn(true);
|
||||
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(path);
|
||||
requestBuilder.content(JSON.toJSONString(reqVo)).contentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
// Do controller logic
|
||||
MvcResult mvcResult = mockMvc.perform(requestBuilder)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andDo(MockMvcResultHandlers.print()).andReturn();
|
||||
|
||||
// Verify the modifyGatewayFlowRules method has been called
|
||||
verify(sentinelApiClient).modifyGatewayFlowRules(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any());
|
||||
|
||||
Result<GatewayFlowRuleEntity> result = JSONObject.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<GatewayFlowRuleEntity>>() {
|
||||
});
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
GatewayFlowRuleEntity entity = result.getData();
|
||||
assertNotNull(entity);
|
||||
assertEquals(RESOURCE_MODE_ROUTE_ID, entity.getResourceMode().intValue());
|
||||
assertEquals("httpbin_route", entity.getResource());
|
||||
assertEquals(6D, entity.getCount().doubleValue(), 0);
|
||||
assertEquals(2L, entity.getInterval().longValue());
|
||||
assertEquals(GatewayFlowRuleEntity.INTERVAL_UNIT_MINUTE, entity.getIntervalUnit().intValue());
|
||||
assertEquals(CONTROL_BEHAVIOR_RATE_LIMITER, entity.getControlBehavior().intValue());
|
||||
assertEquals(0, entity.getBurst().intValue());
|
||||
assertEquals(500, entity.getMaxQueueingTimeoutMs().intValue());
|
||||
assertEquals(date, entity.getGmtCreate());
|
||||
// To make sure gmtModified has been set and it's different from gmtCreate
|
||||
assertNotNull(entity.getGmtModified());
|
||||
assertNotEquals(entity.getGmtCreate(), entity.getGmtModified());
|
||||
|
||||
// Verify the entity which is update in memory repository
|
||||
GatewayParamFlowItemEntity itemEntity = entity.getParamItem();
|
||||
assertEquals(PARAM_PARSE_STRATEGY_URL_PARAM, itemEntity.getParseStrategy().intValue());
|
||||
assertEquals("pa", itemEntity.getFieldName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteFlowRule() throws Exception {
|
||||
String path = "/gateway/flow/delete.json";
|
||||
|
||||
// Add one entity into memory repository for delete
|
||||
GatewayFlowRuleEntity addEntity = new GatewayFlowRuleEntity();
|
||||
addEntity.setId(1L);
|
||||
addEntity.setApp(TEST_APP);
|
||||
addEntity.setIp(TEST_IP);
|
||||
addEntity.setPort(TEST_PORT);
|
||||
addEntity.setResource("httpbin_route");
|
||||
addEntity.setResourceMode(RESOURCE_MODE_ROUTE_ID);
|
||||
addEntity.setGrade(FLOW_GRADE_QPS);
|
||||
addEntity.setCount(5D);
|
||||
addEntity.setInterval(30L);
|
||||
addEntity.setIntervalUnit(GatewayFlowRuleEntity.INTERVAL_UNIT_SECOND);
|
||||
addEntity.setControlBehavior(CONTROL_BEHAVIOR_DEFAULT);
|
||||
addEntity.setBurst(0);
|
||||
addEntity.setMaxQueueingTimeoutMs(0);
|
||||
Date date = new Date();
|
||||
date = DateUtils.addSeconds(date, -1);
|
||||
addEntity.setGmtCreate(date);
|
||||
addEntity.setGmtModified(date);
|
||||
|
||||
GatewayParamFlowItemEntity addItemEntity = new GatewayParamFlowItemEntity();
|
||||
addEntity.setParamItem(addItemEntity);
|
||||
addItemEntity.setParseStrategy(PARAM_PARSE_STRATEGY_CLIENT_IP);
|
||||
|
||||
repository.save(addEntity);
|
||||
|
||||
given(sentinelApiClient.modifyGatewayFlowRules(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any())).willReturn(true);
|
||||
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(path);
|
||||
requestBuilder.param("id", String.valueOf(addEntity.getId()));
|
||||
|
||||
// Do controller logic
|
||||
MvcResult mvcResult = mockMvc.perform(requestBuilder)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
|
||||
|
||||
// Verify the modifyGatewayFlowRules method has been called
|
||||
verify(sentinelApiClient).modifyGatewayFlowRules(eq(TEST_APP), eq(TEST_IP), eq(TEST_PORT), any());
|
||||
|
||||
// Verify the result
|
||||
Result<Long> result = JSONObject.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<Result<Long>>() {});
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
assertEquals(addEntity.getId(), result.getData());
|
||||
|
||||
// Now no entities in memory
|
||||
List<GatewayFlowRuleEntity> entitiesInMem = repository.findAllByApp(TEST_APP);
|
||||
assertEquals(0, entitiesInMem.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.datasource.entity;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowClusterConfig;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author lianglin
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class JsonSerializeTest {
|
||||
|
||||
@Test
|
||||
public void authorityRuleJsonSerializeTest() {
|
||||
AuthorityRuleEntity emptyRule = new AuthorityRuleEntity();
|
||||
Assert.assertTrue("{}".equals(JSON.toJSONString(emptyRule)));
|
||||
|
||||
AuthorityRuleEntity authorityRule = new AuthorityRuleEntity();
|
||||
AuthorityRule rule = new AuthorityRule();
|
||||
rule.setStrategy(0).setLimitApp("default").setResource("rs");
|
||||
authorityRule.setRule(rule);
|
||||
Assert.assertTrue("{\"rule\":{\"limitApp\":\"default\",\"resource\":\"rs\",\"strategy\":0}}".equals(JSON.toJSONString(authorityRule)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramFlowRuleSerializeTest() {
|
||||
ParamFlowRuleEntity emptyRule = new ParamFlowRuleEntity();
|
||||
Assert.assertTrue("{}".equals(JSON.toJSONString(emptyRule)));
|
||||
|
||||
ParamFlowRuleEntity paramFlowRule = new ParamFlowRuleEntity();
|
||||
ParamFlowRule rule = new ParamFlowRule();
|
||||
rule.setClusterConfig(new ParamFlowClusterConfig());
|
||||
rule.setResource("rs").setLimitApp("default");
|
||||
paramFlowRule.setRule(rule);
|
||||
Assert.assertTrue("{\"rule\":{\"burstCount\":0,\"clusterConfig\":{\"fallbackToLocalWhenFail\":false,\"sampleCount\":10,\"thresholdType\":0,\"windowIntervalMs\":1000},\"clusterMode\":false,\"controlBehavior\":0,\"count\":0.0,\"durationInSec\":1,\"grade\":1,\"limitApp\":\"default\",\"maxQueueingTimeMs\":0,\"paramFlowItemList\":[],\"resource\":\"rs\"}}"
|
||||
.equals(JSON.toJSONString(paramFlowRule)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.alibaba.csp.sentinel.dashboard.datasource.entity;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class SentinelVersionTest {
|
||||
@Test
|
||||
public void testEqual() {
|
||||
assertEquals(new SentinelVersion(1, 0, 0), new SentinelVersion(1, 0, 0));
|
||||
assertNotEquals(new SentinelVersion(1, 0, 0), new SentinelVersion(1, 2, 3));
|
||||
assertNotEquals(new SentinelVersion(1, 0, 0), new SentinelVersion(1, 0, 0, ""));
|
||||
assertEquals(new SentinelVersion(1, 0, 0, ""), new SentinelVersion(1, 0, 0, ""));
|
||||
assertNotEquals(new SentinelVersion(1, 0, 0, ""), new SentinelVersion(1, 0, 0, null));
|
||||
assertEquals(new SentinelVersion(1, 0, 0, null), new SentinelVersion(1, 0, 0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreater() {
|
||||
assertTrue(new SentinelVersion(2, 0, 0).greaterThan(new SentinelVersion(1, 0, 0)));
|
||||
assertTrue(new SentinelVersion(1, 1, 0).greaterThan(new SentinelVersion(1, 0, 0)));
|
||||
assertTrue(new SentinelVersion(1, 1, 2).greaterThan(new SentinelVersion(1, 1, 0)));
|
||||
assertTrue(new SentinelVersion(1, 1, 4).greaterThan(new SentinelVersion(1, 1, 3)));
|
||||
assertFalse(new SentinelVersion(1, 0, 0).greaterThan(new SentinelVersion(1, 0, 0)));
|
||||
assertFalse(new SentinelVersion(1, 0, 0).greaterThan(new SentinelVersion(1, 1, 0)));
|
||||
assertFalse(new SentinelVersion(1, 1, 3).greaterThan(new SentinelVersion(1, 1, 3)));
|
||||
assertFalse(new SentinelVersion(1, 1, 2).greaterThan(new SentinelVersion(1, 1, 3)));
|
||||
assertFalse(new SentinelVersion(1, 0, 0, "").greaterThan(new SentinelVersion(1, 0, 0)));
|
||||
assertTrue(new SentinelVersion(1, 0, 1).greaterThan(new SentinelVersion(1, 0, 0)));
|
||||
assertTrue(new SentinelVersion(1, 0, 1, "a").greaterThan(new SentinelVersion(1, 0, 0, "b")));
|
||||
assertFalse(new SentinelVersion(1, 0, 0, "b").greaterThan(new SentinelVersion(1, 0, 0, "a")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.discovery;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class AppInfoTest {
|
||||
|
||||
@Test
|
||||
public void testConcurrentGetMachines() throws Exception {
|
||||
AppInfo appInfo = new AppInfo("testApp");
|
||||
appInfo.addMachine(genMachineInfo("hostName1", "10.18.129.91"));
|
||||
appInfo.addMachine(genMachineInfo("hostName2", "10.18.129.92"));
|
||||
Set<MachineInfo> machines = appInfo.getMachines();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
for (MachineInfo m : machines) {
|
||||
System.out.println(m);
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
} catch (ConcurrentModificationException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
}).start();
|
||||
Thread.sleep(100);
|
||||
try {
|
||||
appInfo.addMachine(genMachineInfo("hostName3", "10.18.129.93"));
|
||||
} catch (ConcurrentModificationException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
private MachineInfo genMachineInfo(String hostName, String ip) {
|
||||
MachineInfo machine = new MachineInfo();
|
||||
machine.setApp("testApp");
|
||||
machine.setHostname(hostName);
|
||||
machine.setIp(ip);
|
||||
machine.setPort(8719);
|
||||
machine.setVersion(String.valueOf(System.currentTimeMillis()));
|
||||
return machine;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRemoveMachineTest() {
|
||||
AppInfo appInfo = new AppInfo("default");
|
||||
assertEquals("default", appInfo.getApp());
|
||||
assertEquals(0, appInfo.getMachines().size());
|
||||
//add one
|
||||
{
|
||||
MachineInfo machineInfo = new MachineInfo();
|
||||
machineInfo.setApp("default");
|
||||
machineInfo.setHostname("bogon");
|
||||
machineInfo.setIp("127.0.0.1");
|
||||
machineInfo.setPort(3389);
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis());
|
||||
machineInfo.setHeartbeatVersion(1);
|
||||
machineInfo.setVersion("0.4.1");
|
||||
appInfo.addMachine(machineInfo);
|
||||
}
|
||||
assertEquals(1, appInfo.getMachines().size());
|
||||
//add duplicated one
|
||||
{
|
||||
MachineInfo machineInfo = new MachineInfo();
|
||||
machineInfo.setApp("default");
|
||||
machineInfo.setHostname("bogon");
|
||||
machineInfo.setIp("127.0.0.1");
|
||||
machineInfo.setPort(3389);
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis());
|
||||
machineInfo.setHeartbeatVersion(1);
|
||||
machineInfo.setVersion("0.4.2");
|
||||
appInfo.addMachine(machineInfo);
|
||||
}
|
||||
assertEquals(1, appInfo.getMachines().size());
|
||||
//add different one
|
||||
{
|
||||
MachineInfo machineInfo = new MachineInfo();
|
||||
machineInfo.setApp("default");
|
||||
machineInfo.setHostname("bogon");
|
||||
machineInfo.setIp("127.0.0.1");
|
||||
machineInfo.setPort(3390);
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis());
|
||||
machineInfo.setHeartbeatVersion(1);
|
||||
machineInfo.setVersion("0.4.3");
|
||||
appInfo.addMachine(machineInfo);
|
||||
}
|
||||
assertEquals(2, appInfo.getMachines().size());
|
||||
appInfo.removeMachine("127.0.0.1", 3389);
|
||||
assertEquals(1, appInfo.getMachines().size());
|
||||
appInfo.removeMachine("127.0.0.1", 3390);
|
||||
assertEquals(0, appInfo.getMachines().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHealthyAndDead() {
|
||||
System.setProperty(DashboardConfig.CONFIG_HIDE_APP_NO_MACHINE_MILLIS, "60000");
|
||||
System.setProperty(DashboardConfig.CONFIG_REMOVE_APP_NO_MACHINE_MILLIS, "600000");
|
||||
DashboardConfig.clearCache();
|
||||
String appName = "default";
|
||||
AppInfo appInfo = new AppInfo();
|
||||
appInfo.setApp(appName);
|
||||
{
|
||||
MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801);
|
||||
machineInfo.setHeartbeatVersion(1);
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis());
|
||||
appInfo.addMachine(machineInfo);
|
||||
}
|
||||
assertTrue(appInfo.isShown());
|
||||
assertFalse(appInfo.isDead());
|
||||
|
||||
{
|
||||
MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801);
|
||||
machineInfo.setHeartbeatVersion(1);
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 70000);
|
||||
appInfo.addMachine(machineInfo);
|
||||
}
|
||||
assertFalse(appInfo.isShown());
|
||||
assertFalse(appInfo.isDead());
|
||||
|
||||
{
|
||||
MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801);
|
||||
machineInfo.setHeartbeatVersion(1);
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 700000);
|
||||
appInfo.addMachine(machineInfo);
|
||||
}
|
||||
assertFalse(appInfo.isShown());
|
||||
assertTrue(appInfo.isDead());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.discovery;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig;
|
||||
|
||||
/**
|
||||
* @author Jason Joo
|
||||
*/
|
||||
public class MachineInfoTest {
|
||||
|
||||
@Test
|
||||
public void testHealthyAndDead() {
|
||||
System.setProperty(DashboardConfig.CONFIG_UNHEALTHY_MACHINE_MILLIS, "60000");
|
||||
System.setProperty(DashboardConfig.CONFIG_AUTO_REMOVE_MACHINE_MILLIS, "600000");
|
||||
DashboardConfig.clearCache();
|
||||
MachineInfo machineInfo = new MachineInfo();
|
||||
machineInfo.setHeartbeatVersion(1);
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 10000);
|
||||
assertTrue(machineInfo.isHealthy());
|
||||
assertFalse(machineInfo.isDead());
|
||||
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 100000);
|
||||
assertFalse(machineInfo.isHealthy());
|
||||
assertFalse(machineInfo.isDead());
|
||||
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 1000000);
|
||||
assertFalse(machineInfo.isHealthy());
|
||||
assertTrue(machineInfo.isDead());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.repository.metric;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test cases for {@link InMemoryMetricsRepository}.
|
||||
*
|
||||
* @author Nick Tan
|
||||
*/
|
||||
public class InMemoryMetricsRepositoryTest {
|
||||
|
||||
private final static String DEFAULT_APP = "defaultApp";
|
||||
private final static String DEFAULT_RESOURCE = "defaultResource";
|
||||
private static final long EXPIRE_TIME = 1000 * 60 * 5L;
|
||||
|
||||
private InMemoryMetricsRepository inMemoryMetricsRepository;
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
inMemoryMetricsRepository = new InMemoryMetricsRepository();
|
||||
executorService = Executors.newFixedThreadPool(8);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
executorService.shutdownNow();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSave() {
|
||||
MetricEntity entry = new MetricEntity();
|
||||
entry.setApp("testSave");
|
||||
entry.setResource("testResource");
|
||||
entry.setTimestamp(new Date(System.currentTimeMillis()));
|
||||
entry.setPassQps(1L);
|
||||
entry.setExceptionQps(1L);
|
||||
entry.setBlockQps(0L);
|
||||
entry.setSuccessQps(1L);
|
||||
inMemoryMetricsRepository.save(entry);
|
||||
List<String> resources = inMemoryMetricsRepository.listResourcesOfApp("testSave");
|
||||
Assert.assertTrue(resources.size() == 1 && "testResource".equals(resources.get(0)));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSaveAll() {
|
||||
List<MetricEntity> entities = new ArrayList<>(10000);
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
MetricEntity entry = new MetricEntity();
|
||||
entry.setApp("testSaveAll");
|
||||
entry.setResource("testResource" + i);
|
||||
entry.setTimestamp(new Date(System.currentTimeMillis()));
|
||||
entry.setPassQps(1L);
|
||||
entry.setExceptionQps(1L);
|
||||
entry.setBlockQps(0L);
|
||||
entry.setSuccessQps(1L);
|
||||
entities.add(entry);
|
||||
}
|
||||
inMemoryMetricsRepository.saveAll(entities);
|
||||
List<String> result = inMemoryMetricsRepository.listResourcesOfApp("testSaveAll");
|
||||
Assert.assertTrue(result.size() == entities.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExpireMetric() {
|
||||
long now = System.currentTimeMillis();
|
||||
MetricEntity expireEntry = new MetricEntity();
|
||||
expireEntry.setApp(DEFAULT_APP);
|
||||
expireEntry.setResource(DEFAULT_RESOURCE);
|
||||
expireEntry.setTimestamp(new Date(now - EXPIRE_TIME - 1L));
|
||||
expireEntry.setPassQps(1L);
|
||||
expireEntry.setExceptionQps(1L);
|
||||
expireEntry.setBlockQps(0L);
|
||||
expireEntry.setSuccessQps(1L);
|
||||
inMemoryMetricsRepository.save(expireEntry);
|
||||
|
||||
MetricEntity entry = new MetricEntity();
|
||||
entry.setApp(DEFAULT_APP);
|
||||
entry.setResource(DEFAULT_RESOURCE);
|
||||
entry.setTimestamp(new Date(now));
|
||||
entry.setPassQps(1L);
|
||||
entry.setExceptionQps(1L);
|
||||
entry.setBlockQps(0L);
|
||||
entry.setSuccessQps(1L);
|
||||
inMemoryMetricsRepository.save(entry);
|
||||
|
||||
List<MetricEntity> list = inMemoryMetricsRepository.queryByAppAndResourceBetween(
|
||||
DEFAULT_APP, DEFAULT_RESOURCE, now - EXPIRE_TIME, now);
|
||||
|
||||
assertFalse(CollectionUtils.isEmpty(list));
|
||||
assertEquals(1, list.size());
|
||||
assertTrue(list.get(0).getTimestamp().getTime() >= now - EXPIRE_TIME && list.get(0).getTimestamp().getTime() <= now);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testConcurrentPutAndGet() {
|
||||
|
||||
List<CompletableFuture> futures = new ArrayList<>(10000);
|
||||
final CyclicBarrier cyclicBarrier = new CyclicBarrier(8);
|
||||
|
||||
for (int j = 0; j < 10000; j++) {
|
||||
final int finalJ = j;
|
||||
futures.add(CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
cyclicBarrier.await();
|
||||
if (finalJ % 2 == 0) {
|
||||
batchSave();
|
||||
} else {
|
||||
inMemoryMetricsRepository.listResourcesOfApp(DEFAULT_APP);
|
||||
}
|
||||
|
||||
} catch (InterruptedException | BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}, executorService)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
CompletableFuture all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||
|
||||
try {
|
||||
all.get(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.getCause().printStackTrace();
|
||||
if (e.getCause() instanceof ConcurrentModificationException) {
|
||||
fail("concurrent error occurred");
|
||||
} else {
|
||||
fail("unexpected exception");
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
fail("allOf future timeout");
|
||||
}
|
||||
}
|
||||
|
||||
private void batchSave() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
MetricEntity entry = new MetricEntity();
|
||||
entry.setApp(DEFAULT_APP);
|
||||
entry.setResource(DEFAULT_RESOURCE);
|
||||
entry.setTimestamp(new Date(System.currentTimeMillis()));
|
||||
entry.setPassQps(1L);
|
||||
entry.setExceptionQps(1L);
|
||||
entry.setBlockQps(0L);
|
||||
entry.setSuccessQps(1L);
|
||||
inMemoryMetricsRepository.save(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.apollo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient;
|
||||
|
||||
/**
|
||||
* @author hantianwei@gmail.com
|
||||
* @since 1.5.0
|
||||
*/
|
||||
@Configuration
|
||||
public class ApolloConfig {
|
||||
|
||||
@Bean
|
||||
public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
|
||||
return JSON::toJSONString;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
|
||||
return s -> JSON.parseArray(s, FlowRuleEntity.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApolloOpenApiClient apolloOpenApiClient() {
|
||||
ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder()
|
||||
.withPortalUrl("http://localhost:10034")
|
||||
.withToken("token")
|
||||
.build();
|
||||
return client;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.apollo;
|
||||
|
||||
/**
|
||||
* @author hantianwei@gmail.com
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public final class ApolloConfigUtil {
|
||||
|
||||
public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";
|
||||
|
||||
private ApolloConfigUtil() {
|
||||
}
|
||||
|
||||
public static String getFlowDataId(String appName) {
|
||||
return String.format("%s%s", appName, FLOW_DATA_ID_POSTFIX);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.apollo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient;
|
||||
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
|
||||
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
|
||||
|
||||
/**
|
||||
* @author hantianwei@gmail.com
|
||||
* @since 1.5.0
|
||||
*/
|
||||
@Component("flowRuleApolloProvider")
|
||||
public class FlowRuleApolloProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
|
||||
|
||||
@Autowired
|
||||
private ApolloOpenApiClient apolloOpenApiClient;
|
||||
@Autowired
|
||||
private Converter<String, List<FlowRuleEntity>> converter;
|
||||
|
||||
@Override
|
||||
public List<FlowRuleEntity> getRules(String appName) throws Exception {
|
||||
String appId = "appId";
|
||||
String flowDataId = ApolloConfigUtil.getFlowDataId(appName);
|
||||
OpenNamespaceDTO openNamespaceDTO = apolloOpenApiClient.getNamespace(appId, "DEV", "default", "application");
|
||||
String rules = openNamespaceDTO
|
||||
.getItems()
|
||||
.stream()
|
||||
.filter(p -> p.getKey().equals(flowDataId))
|
||||
.map(OpenItemDTO::getValue)
|
||||
.findFirst()
|
||||
.orElse("");
|
||||
|
||||
if (StringUtil.isEmpty(rules)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return converter.convert(rules);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.apollo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
|
||||
import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient;
|
||||
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
|
||||
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
|
||||
|
||||
/**
|
||||
* @author hantianwei@gmail.com
|
||||
* @since 1.5.0
|
||||
*/
|
||||
@Component("flowRuleApolloPublisher")
|
||||
public class FlowRuleApolloPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
|
||||
|
||||
@Autowired
|
||||
private ApolloOpenApiClient apolloOpenApiClient;
|
||||
@Autowired
|
||||
private Converter<List<FlowRuleEntity>, String> converter;
|
||||
|
||||
@Override
|
||||
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
|
||||
AssertUtil.notEmpty(app, "app name cannot be empty");
|
||||
if (rules == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Increase the configuration
|
||||
String appId = "appId";
|
||||
String flowDataId = ApolloConfigUtil.getFlowDataId(app);
|
||||
OpenItemDTO openItemDTO = new OpenItemDTO();
|
||||
openItemDTO.setKey(flowDataId);
|
||||
openItemDTO.setValue(converter.convert(rules));
|
||||
openItemDTO.setComment("Program auto-join");
|
||||
openItemDTO.setDataChangeCreatedBy("some-operator");
|
||||
apolloOpenApiClient.createOrUpdateItem(appId, "DEV", "default", "application", openItemDTO);
|
||||
|
||||
// Release configuration
|
||||
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
|
||||
namespaceReleaseDTO.setEmergencyPublish(true);
|
||||
namespaceReleaseDTO.setReleaseComment("Modify or add configurations");
|
||||
namespaceReleaseDTO.setReleasedBy("some-operator");
|
||||
namespaceReleaseDTO.setReleaseTitle("Modify or add configurations");
|
||||
apolloOpenApiClient.publishNamespace(appId, "DEV", "default", "application", namespaceReleaseDTO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.nacos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@Component("flowRuleNacosProvider")
|
||||
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
@Autowired
|
||||
private Converter<String, List<FlowRuleEntity>> converter;
|
||||
|
||||
@Override
|
||||
public List<FlowRuleEntity> getRules(String appName) throws Exception {
|
||||
String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
|
||||
NacosConfigUtil.GROUP_ID, 3000);
|
||||
if (StringUtil.isEmpty(rules)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return converter.convert(rules);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.nacos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@Component("flowRuleNacosPublisher")
|
||||
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
@Autowired
|
||||
private Converter<List<FlowRuleEntity>, String> converter;
|
||||
|
||||
@Override
|
||||
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
|
||||
AssertUtil.notEmpty(app, "app name cannot be empty");
|
||||
if (rules == null) {
|
||||
return;
|
||||
}
|
||||
configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
|
||||
NacosConfigUtil.GROUP_ID, converter.convert(rules));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.nacos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.nacos.api.config.ConfigFactory;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@Configuration
|
||||
public class NacosConfig {
|
||||
|
||||
@Bean
|
||||
public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
|
||||
return JSON::toJSONString;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
|
||||
return s -> JSON.parseArray(s, FlowRuleEntity.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConfigService nacosConfigService() throws Exception {
|
||||
return ConfigFactory.createConfigService("localhost");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.nacos;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public final class NacosConfigUtil {
|
||||
|
||||
public static final String GROUP_ID = "SENTINEL_GROUP";
|
||||
|
||||
public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";
|
||||
public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules";
|
||||
public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map";
|
||||
|
||||
/**
|
||||
* cc for `cluster-client`
|
||||
*/
|
||||
public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config";
|
||||
/**
|
||||
* cs for `cluster-server`
|
||||
*/
|
||||
public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config";
|
||||
public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config";
|
||||
public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set";
|
||||
|
||||
private NacosConfigUtil() {}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.zookeeper;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.zookeeper.data.Stat;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component("flowRuleZookeeperProvider")
|
||||
public class FlowRuleZookeeperProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
|
||||
|
||||
@Autowired
|
||||
private CuratorFramework zkClient;
|
||||
@Autowired
|
||||
private Converter<String, List<FlowRuleEntity>> converter;
|
||||
|
||||
@Override
|
||||
public List<FlowRuleEntity> getRules(String appName) throws Exception {
|
||||
String zkPath = ZookeeperConfigUtil.getPath(appName);
|
||||
Stat stat = zkClient.checkExists().forPath(zkPath);
|
||||
if(stat == null){
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
byte[] bytes = zkClient.getData().forPath(zkPath);
|
||||
if (null == bytes || bytes.length == 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
String s = new String(bytes);
|
||||
|
||||
return converter.convert(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.zookeeper;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.zookeeper.CreateMode;
|
||||
import org.apache.zookeeper.data.Stat;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component("flowRuleZookeeperPublisher")
|
||||
public class FlowRuleZookeeperPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
|
||||
@Autowired
|
||||
private CuratorFramework zkClient;
|
||||
@Autowired
|
||||
private Converter<List<FlowRuleEntity>, String> converter;
|
||||
|
||||
@Override
|
||||
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
|
||||
AssertUtil.notEmpty(app, "app name cannot be empty");
|
||||
|
||||
String path = ZookeeperConfigUtil.getPath(app);
|
||||
Stat stat = zkClient.checkExists().forPath(path);
|
||||
if (stat == null) {
|
||||
zkClient.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, null);
|
||||
}
|
||||
byte[] data = CollectionUtils.isEmpty(rules) ? "[]".getBytes() : converter.convert(rules).getBytes();
|
||||
zkClient.setData().forPath(path, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.zookeeper;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||
import org.apache.curator.retry.ExponentialBackoffRetry;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class ZookeeperConfig {
|
||||
|
||||
@Bean
|
||||
public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
|
||||
return JSON::toJSONString;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
|
||||
return s -> JSON.parseArray(s, FlowRuleEntity.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CuratorFramework zkClient() {
|
||||
CuratorFramework zkClient =
|
||||
CuratorFrameworkFactory.newClient("127.0.0.1:2181",
|
||||
new ExponentialBackoffRetry(ZookeeperConfigUtil.SLEEP_TIME, ZookeeperConfigUtil.RETRY_TIMES));
|
||||
zkClient.start();
|
||||
|
||||
return zkClient;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.dashboard.rule.zookeeper;
|
||||
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
public class ZookeeperConfigUtil {
|
||||
public static final String RULE_ROOT_PATH = "/sentinel_rule_config";
|
||||
|
||||
public static final int RETRY_TIMES = 3;
|
||||
public static final int SLEEP_TIME = 1000;
|
||||
|
||||
public static String getPath(String appName) {
|
||||
StringBuilder stringBuilder = new StringBuilder(RULE_ROOT_PATH);
|
||||
|
||||
if (StringUtils.isBlank(appName)) {
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
if (appName.startsWith("/")) {
|
||||
stringBuilder.append(appName);
|
||||
} else {
|
||||
stringBuilder.append("/")
|
||||
.append(appName);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.alibaba.csp.sentinel.dashboard.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.SentinelVersion;
|
||||
|
||||
public class VersionUtilsTest {
|
||||
@Test
|
||||
public void test() {
|
||||
Optional<SentinelVersion> version = VersionUtils.parseVersion("1.2.3");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(2, version.get().getMinorVersion());
|
||||
assertEquals(3, version.get().getFixVersion());
|
||||
assertNull(version.get().getPostfix());
|
||||
|
||||
version = VersionUtils.parseVersion("1.2");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(2, version.get().getMinorVersion());
|
||||
assertEquals(0, version.get().getFixVersion());
|
||||
assertNull(version.get().getPostfix());
|
||||
|
||||
version = VersionUtils.parseVersion("1.");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(0, version.get().getMinorVersion());
|
||||
assertEquals(0, version.get().getFixVersion());
|
||||
assertNull(version.get().getPostfix());
|
||||
|
||||
version = VersionUtils.parseVersion("1.2.");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(2, version.get().getMinorVersion());
|
||||
assertEquals(0, version.get().getFixVersion());
|
||||
assertNull(version.get().getPostfix());
|
||||
|
||||
version = VersionUtils.parseVersion("1.2.3.");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(2, version.get().getMinorVersion());
|
||||
assertEquals(3, version.get().getFixVersion());
|
||||
assertNull(version.get().getPostfix());
|
||||
|
||||
version = VersionUtils.parseVersion("1.2.3.4");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(2, version.get().getMinorVersion());
|
||||
assertEquals(3, version.get().getFixVersion());
|
||||
assertNull(version.get().getPostfix());
|
||||
|
||||
version = VersionUtils.parseVersion("1");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(0, version.get().getMinorVersion());
|
||||
assertEquals(0, version.get().getFixVersion());
|
||||
assertNull(version.get().getPostfix());
|
||||
|
||||
version = VersionUtils.parseVersion("1.2.3-");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(2, version.get().getMinorVersion());
|
||||
assertEquals(3, version.get().getFixVersion());
|
||||
assertNull(version.get().getPostfix());
|
||||
|
||||
version = VersionUtils.parseVersion("-");
|
||||
assertFalse(version.isPresent());
|
||||
|
||||
version = VersionUtils.parseVersion("-t");
|
||||
assertFalse(version.isPresent());
|
||||
|
||||
version = VersionUtils.parseVersion("");
|
||||
assertFalse(version.isPresent());
|
||||
|
||||
version = VersionUtils.parseVersion(null);
|
||||
assertFalse(version.isPresent());
|
||||
|
||||
version = VersionUtils.parseVersion("1.2.3-SNAPSHOTS");
|
||||
assertTrue(version.isPresent());
|
||||
assertEquals(1, version.get().getMajorVersion());
|
||||
assertEquals(2, version.get().getMinorVersion());
|
||||
assertEquals(3, version.get().getFixVersion());
|
||||
assertEquals("SNAPSHOTS", version.get().getPostfix());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user