Skip to content

Commit

Permalink
[type:feat] divide plugin adapt discovery (apache#5185)
Browse files Browse the repository at this point in the history
* discover-mode adapt divide plugin

* add test

---------

Co-authored-by: ‘xcsnx’ <‘[email protected]’>
  • Loading branch information
xcsnx and ‘xcsnx’ authored Sep 27, 2023
1 parent 4b0025a commit a9ca7fd
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,164 @@ public Timestamp getDateUpdated() {
public void setDateUpdated(final Timestamp dateUpdated) {
this.dateUpdated = dateUpdated;
}

/**
* class builder.
*
* @return Builder
*/
public static DiscoveryUpstreamData.Builder builder() {
return new DiscoveryUpstreamData.Builder();
}

public static final class Builder {

private String id;

private Timestamp dateCreated;

private Timestamp dateUpdated;

private String discoveryHandlerId;

private String protocol;

private String url;

private int status;

private int weight;

private String props;

private Builder() {
}

/**
* build new Object.
*
* @return Builder
*/
public static Builder builder() {
return new Builder();
}

/**
* build id.
*
* @param id id
* @return this
*/
public Builder id(final String id) {
this.id = id;
return this;
}

/**
* build dateCreated.
*
* @param dateCreated dateCreated
* @return this
*/
public Builder dateCreated(final Timestamp dateCreated) {
this.dateCreated = dateCreated;
return this;
}

/**
* build dateUpdated.
*
* @param dateUpdated dateUpdated
* @return this
*/
public Builder dateUpdated(final Timestamp dateUpdated) {
this.dateUpdated = dateUpdated;
return this;
}

/**
* build discoveryHandlerId.
*
* @param discoveryHandlerId discoveryHandlerId
* @return this
*/
public Builder discoveryHandlerId(final String discoveryHandlerId) {
this.discoveryHandlerId = discoveryHandlerId;
return this;
}

/**
* build protocol.
*
* @param protocol protocol
* @return this
*/
public Builder protocol(final String protocol) {
this.protocol = protocol;
return this;
}

/**
* build url.
*
* @param url url
* @return this
*/
public Builder url(final String url) {
this.url = url;
return this;
}

/**
* build status.
*
* @param status status
* @return this
*/
public Builder status(final int status) {
this.status = status;
return this;
}

/**
* build weight.
*
* @param weight weight
* @return this
*/
public Builder weight(final int weight) {
this.weight = weight;
return this;
}

/**
* build props.
*
* @param props props
* @return this
*/
public Builder props(final String props) {
this.props = props;
return this;
}

/**
* build new Object.
*
* @return DiscoveryUpstreamData
*/
public DiscoveryUpstreamData build() {
DiscoveryUpstreamData discoveryUpstreamData = new DiscoveryUpstreamData();
discoveryUpstreamData.setId(id);
discoveryUpstreamData.setDateCreated(dateCreated);
discoveryUpstreamData.setDateUpdated(dateUpdated);
discoveryUpstreamData.setDiscoveryHandlerId(discoveryHandlerId);
discoveryUpstreamData.setProtocol(protocol);
discoveryUpstreamData.setUrl(url);
discoveryUpstreamData.setStatus(status);
discoveryUpstreamData.setWeight(weight);
discoveryUpstreamData.setProps(props);
return discoveryUpstreamData;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shenyu.plugin.divide.handler;

import org.apache.shenyu.common.dto.DiscoverySyncData;
import org.apache.shenyu.common.dto.DiscoveryUpstreamData;
import org.apache.shenyu.common.enums.PluginEnum;
import org.apache.shenyu.loadbalancer.cache.UpstreamCacheManager;
import org.apache.shenyu.loadbalancer.entity.Upstream;
import org.apache.shenyu.plugin.base.cache.MetaDataCache;
import org.apache.shenyu.plugin.base.handler.DiscoveryUpstreamDataHandler;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* upstreamList data change.
*/
public class DivideUpstreamDataHandler implements DiscoveryUpstreamDataHandler {

@Override
public void handlerDiscoveryUpstreamData(final DiscoverySyncData discoverySyncData) {
if (Objects.isNull(discoverySyncData) || Objects.isNull(discoverySyncData.getSelectorId())) {
return;
}
List<DiscoveryUpstreamData> upstreamList = discoverySyncData.getUpstreamDataList();
UpstreamCacheManager.getInstance().submit(discoverySyncData.getSelectorId(), convertUpstreamList(upstreamList));
// the update is also need to clean, but there is no way to
// distinguish between crate and update, so it is always clean
MetaDataCache.getInstance().clean();
}

@Override
public String pluginName() {
return PluginEnum.DIVIDE.getName();
}

private List<Upstream> convertUpstreamList(final List<DiscoveryUpstreamData> upstreamList) {
if (ObjectUtils.isEmpty(upstreamList)) {
return Collections.emptyList();
}
return upstreamList.stream().map(u -> Upstream.builder()
.protocol(u.getProtocol())
.url(u.getUrl())
.weight(u.getWeight())
.status(0 == u.getStatus())
.timestamp(u.getDateUpdated().getTime())
.build()).collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shenyu.plugin.divide.handler;

import org.apache.shenyu.common.dto.DiscoverySyncData;
import org.apache.shenyu.common.dto.DiscoveryUpstreamData;
import org.apache.shenyu.common.enums.PluginEnum;
import org.apache.shenyu.common.utils.UpstreamCheckUtils;
import org.apache.shenyu.loadbalancer.cache.UpstreamCacheManager;
import org.apache.shenyu.loadbalancer.entity.Upstream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

import java.sql.Timestamp;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class DivideUpstreamDataHandlerTest {

private DiscoverySyncData discoverySyncData;

private DivideUpstreamDataHandler divideUpstreamDataHandler;

private MockedStatic<UpstreamCheckUtils> mockCheckUtils;

@BeforeEach
public void setUp() {
this.divideUpstreamDataHandler = new DivideUpstreamDataHandler();
List<DiscoveryUpstreamData> divideUpstreamList = Stream.of(3)
.map(weight -> DiscoveryUpstreamData.builder()
.url("mock-" + weight)
.dateUpdated(new Timestamp(System.currentTimeMillis()))
.build())
.collect(Collectors.toList());
this.discoverySyncData = mock(DiscoverySyncData.class);
when(discoverySyncData.getSelectorId()).thenReturn("handler");
when(discoverySyncData.getUpstreamDataList()).thenReturn(divideUpstreamList);

// mock static
mockCheckUtils = mockStatic(UpstreamCheckUtils.class);
mockCheckUtils.when(() -> UpstreamCheckUtils.checkUrl(anyString(), anyInt())).thenReturn(true);
}

@AfterEach
public void tearDown() {
mockCheckUtils.close();
}

/**
* Handler selector test.
*/
@Test
public void handlerDiscoveryUpstreamDataTest() {
divideUpstreamDataHandler.handlerDiscoveryUpstreamData(discoverySyncData);
List<Upstream> result = UpstreamCacheManager.getInstance().findUpstreamListBySelectorId("handler");
assertEquals(discoverySyncData.getUpstreamDataList().get(0).getUrl(), result.get(0).getUrl());
DiscoverySyncData discoverySyncData = new DiscoverySyncData();
discoverySyncData.setSelectorId(null);
divideUpstreamDataHandler.handlerDiscoveryUpstreamData(discoverySyncData);
}

/**
* Plugin named test.
*/
@Test
public void pluginNamedTest() {
assertEquals(divideUpstreamDataHandler.pluginName(), PluginEnum.DIVIDE.getName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private String getIp(final SocketAddress socketAddress) {
throw new NullPointerException("remoteAddress is null");
}
String address = socketAddress.toString();
return address.substring(2, address.indexOf(':'));
return address.substring(1, address.indexOf(':'));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.shenyu.plugin.divide.context.DivideShenyuContextDecorator;
import org.apache.shenyu.plugin.divide.handler.DividePluginDataHandler;
import org.apache.shenyu.plugin.divide.handler.DivideMetaDataHandler;
import org.apache.shenyu.plugin.divide.handler.DivideUpstreamDataHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -66,6 +67,17 @@ public MetaDataHandler divideMetaDataHandler() {
return new DivideMetaDataHandler();
}


/**
* divide discovery upstream data handler.
*
* @return the discovery upstream data handler
*/
@Bean
public DivideUpstreamDataHandler divideUpstreamDataHandler() {
return new DivideUpstreamDataHandler();
}

/**
* Divide shenyu context decorator.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.apache.shenyu.plugin.api.context.ShenyuContextDecorator;
import org.apache.shenyu.plugin.base.handler.MetaDataHandler;
import org.apache.shenyu.plugin.base.handler.PluginDataHandler;
import org.apache.shenyu.plugin.divide.handler.DivideUpstreamDataHandler;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
Expand Down Expand Up @@ -74,6 +75,15 @@ public void testDivideMetaDataHandler() {
);
}

@Test
public void testDivideUpstreamDataHandler() {
applicationContextRunner.run(context -> {
DivideUpstreamDataHandler handler = context.getBean("divideUpstreamDataHandler", DivideUpstreamDataHandler.class);
assertNotNull(handler);
}
);
}

@Test
public void testDivideShenyuContextDecorator() {
applicationContextRunner.run(context -> {
Expand Down

0 comments on commit a9ca7fd

Please sign in to comment.