committed by
GitHub
320 changed files with 3347 additions and 1682 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,110 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.service.edge; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.http.HttpHost; |
|||
import org.apache.http.conn.ssl.DefaultHostnameVerifier; |
|||
import org.apache.http.impl.client.CloseableHttpClient; |
|||
import org.apache.http.impl.client.HttpClients; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; |
|||
import org.springframework.http.client.SimpleClientHttpRequestFactory; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.web.client.RestTemplate; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import java.net.InetSocketAddress; |
|||
import java.net.Proxy; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
import static org.apache.commons.lang3.StringUtils.isNotEmpty; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
@Slf4j |
|||
public class DefaultEdgeLicenseService implements EdgeLicenseService { |
|||
|
|||
private RestTemplate restTemplate; |
|||
|
|||
private static final String EDGE_LICENSE_SERVER_ENDPOINT = "https://license.thingsboard.io"; |
|||
|
|||
@Value("${edges.enabled:false}") |
|||
private boolean edgesEnabled; |
|||
|
|||
@PostConstruct |
|||
public void init() { |
|||
if (edgesEnabled) { |
|||
initRestTemplate(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ResponseEntity<JsonNode> checkInstance(JsonNode request) { |
|||
return this.restTemplate.postForEntity(EDGE_LICENSE_SERVER_ENDPOINT + "/api/license/checkInstance", request, JsonNode.class); |
|||
} |
|||
|
|||
@Override |
|||
public ResponseEntity<JsonNode> activateInstance(String edgeLicenseSecret, String releaseDate) { |
|||
Map<String, String> params = new HashMap<>(); |
|||
params.put("licenseSecret", edgeLicenseSecret); |
|||
params.put("releaseDate", releaseDate); |
|||
return this.restTemplate.postForEntity(EDGE_LICENSE_SERVER_ENDPOINT + "/api/license/activateInstance?licenseSecret={licenseSecret}&releaseDate={releaseDate}", null, JsonNode.class, params); |
|||
} |
|||
|
|||
private void initRestTemplate() { |
|||
boolean jdkHttpClientEnabled = isNotEmpty(System.getProperty("tb.proxy.jdk")) && System.getProperty("tb.proxy.jdk").equalsIgnoreCase("true"); |
|||
boolean systemProxyEnabled = isNotEmpty(System.getProperty("tb.proxy.system")) && System.getProperty("tb.proxy.system").equalsIgnoreCase("true"); |
|||
boolean proxyEnabled = isNotEmpty(System.getProperty("tb.proxy.host")) && isNotEmpty(System.getProperty("tb.proxy.port")); |
|||
if (jdkHttpClientEnabled) { |
|||
log.warn("Going to use plain JDK Http Client!"); |
|||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); |
|||
if (proxyEnabled) { |
|||
log.warn("Going to use Proxy Server: [{}:{}]", System.getProperty("tb.proxy.host"), System.getProperty("tb.proxy.port")); |
|||
factory.setProxy(new Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved(System.getProperty("tb.proxy.host"), Integer.parseInt(System.getProperty("tb.proxy.port"))))); |
|||
} |
|||
|
|||
this.restTemplate = new RestTemplate(new SimpleClientHttpRequestFactory()); |
|||
} else { |
|||
CloseableHttpClient httpClient; |
|||
HttpComponentsClientHttpRequestFactory requestFactory; |
|||
if (systemProxyEnabled) { |
|||
log.warn("Going to use System Proxy Server!"); |
|||
httpClient = HttpClients.createSystem(); |
|||
requestFactory = new HttpComponentsClientHttpRequestFactory(); |
|||
requestFactory.setHttpClient(httpClient); |
|||
this.restTemplate = new RestTemplate(requestFactory); |
|||
} else if (proxyEnabled) { |
|||
log.warn("Going to use Proxy Server: [{}:{}]", System.getProperty("tb.proxy.host"), System.getProperty("tb.proxy.port")); |
|||
httpClient = HttpClients.custom().setSSLHostnameVerifier(new DefaultHostnameVerifier()).setProxy(new HttpHost(System.getProperty("tb.proxy.host"), Integer.parseInt(System.getProperty("tb.proxy.port")), "https")).build(); |
|||
requestFactory = new HttpComponentsClientHttpRequestFactory(); |
|||
requestFactory.setHttpClient(httpClient); |
|||
this.restTemplate = new RestTemplate(requestFactory); |
|||
} else { |
|||
httpClient = HttpClients.custom().setSSLHostnameVerifier(new DefaultHostnameVerifier()).build(); |
|||
requestFactory = new HttpComponentsClientHttpRequestFactory(); |
|||
requestFactory.setHttpClient(httpClient); |
|||
this.restTemplate = new RestTemplate(requestFactory); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.service.edge; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.springframework.http.ResponseEntity; |
|||
|
|||
public interface EdgeLicenseService { |
|||
|
|||
ResponseEntity<JsonNode> checkInstance(JsonNode request); |
|||
|
|||
ResponseEntity<JsonNode> activateInstance(String licenseSecret, String releaseDate); |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.service.edge.rpc; |
|||
|
|||
import com.google.protobuf.BoolValue; |
|||
import com.google.protobuf.ByteString; |
|||
import com.google.protobuf.BytesValue; |
|||
import com.google.protobuf.Int64Value; |
|||
import com.google.protobuf.StringValue; |
|||
|
|||
public class EdgeProtoUtils { |
|||
|
|||
private EdgeProtoUtils() { |
|||
} |
|||
|
|||
public static BoolValue getBoolValue(Boolean value) { |
|||
BoolValue.Builder builder = BoolValue.newBuilder(); |
|||
builder.setValue(value); |
|||
return builder.build(); |
|||
} |
|||
|
|||
public static StringValue getStringValue(String value) { |
|||
StringValue.Builder builder = StringValue.newBuilder(); |
|||
builder.setValue(value); |
|||
return builder.build(); |
|||
} |
|||
|
|||
public static Int64Value getInt64Value(Long value) { |
|||
Int64Value.Builder builder = Int64Value.newBuilder(); |
|||
builder.setValue(value); |
|||
return builder.build(); |
|||
} |
|||
|
|||
public static BytesValue getBytesValue(ByteString value) { |
|||
BytesValue.Builder builder = BytesValue.newBuilder(); |
|||
builder.setValue(value); |
|||
return builder.build(); |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.service.rpc; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.ToString; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.MsgType; |
|||
import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@ToString |
|||
@RequiredArgsConstructor |
|||
public class RemoveRpcActorMsg implements ToDeviceActorNotificationMsg { |
|||
|
|||
@Getter |
|||
private final TenantId tenantId; |
|||
@Getter |
|||
private final DeviceId deviceId; |
|||
|
|||
@Getter |
|||
private final UUID requestId; |
|||
|
|||
@Override |
|||
public MsgType getMsgType() { |
|||
return MsgType.REMOVE_RPC_TO_DEVICE_ACTOR_MSG; |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.cache; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.assertj.core.api.SoftAssertions; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.junit.jupiter.api.extension.ExtendWith; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
|||
import org.springframework.boot.test.context.SpringBootContextLoader; |
|||
import org.springframework.context.annotation.ComponentScan; |
|||
import org.springframework.test.context.ContextConfiguration; |
|||
import org.springframework.test.context.junit.jupiter.SpringExtension; |
|||
|
|||
import static org.assertj.core.api.Assertions.assertThat; |
|||
|
|||
@ExtendWith(SpringExtension.class) |
|||
@ContextConfiguration(classes = CaffeineCacheDefaultConfigurationTestSuite.class, loader = SpringBootContextLoader.class) |
|||
@ComponentScan({"org.thingsboard.server.cache"}) |
|||
@EnableConfigurationProperties |
|||
@Slf4j |
|||
public class CaffeineCacheDefaultConfigurationTestSuite { |
|||
|
|||
@Autowired |
|||
CaffeineCacheConfiguration caffeineCacheConfiguration; |
|||
|
|||
@Test |
|||
public void verifyTransactionAwareCacheManagerProxy() { |
|||
assertThat(caffeineCacheConfiguration.getSpecs()).as("specs").isNotNull(); |
|||
caffeineCacheConfiguration.getSpecs().forEach((name, cacheSpecs)->assertThat(cacheSpecs).as("cache %s specs", name).isNotNull()); |
|||
|
|||
SoftAssertions softly = new SoftAssertions(); |
|||
caffeineCacheConfiguration.getSpecs().forEach((name, cacheSpecs)->{ |
|||
softly.assertThat(name).as("cache name").isNotEmpty(); |
|||
softly.assertThat(cacheSpecs.getTimeToLiveInMinutes()).as("cache %s time to live", name).isGreaterThan(0); |
|||
softly.assertThat(cacheSpecs.getMaxSize()).as("cache %s max size", name).isGreaterThan(0); |
|||
}); |
|||
softly.assertAll(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,129 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.transport.lwm2m.server; |
|||
|
|||
import org.junit.jupiter.api.BeforeEach; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
import java.util.List; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ConcurrentMap; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.concurrent.atomic.AtomicLong; |
|||
|
|||
import static java.util.Collections.emptyList; |
|||
import static org.assertj.core.api.Assertions.assertThat; |
|||
import static org.mockito.ArgumentMatchers.any; |
|||
import static org.mockito.ArgumentMatchers.anyLong; |
|||
import static org.mockito.ArgumentMatchers.anyString; |
|||
import static org.mockito.BDDMockito.willReturn; |
|||
import static org.mockito.Mockito.mock; |
|||
import static org.mockito.Mockito.never; |
|||
import static org.mockito.Mockito.spy; |
|||
import static org.mockito.Mockito.times; |
|||
import static org.mockito.Mockito.verify; |
|||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; |
|||
|
|||
class LwM2mTransportServerHelperTest { |
|||
|
|||
public static final String KEY_SW_STATE = "sw_state"; |
|||
public static final String DOWNLOADING = "DOWNLOADING"; |
|||
|
|||
long now; |
|||
List<TransportProtos.KeyValueProto> kvList; |
|||
ConcurrentMap<String, AtomicLong> keyTsLatestMap; |
|||
LwM2mTransportServerHelper helper; |
|||
LwM2mTransportContext context; |
|||
|
|||
|
|||
@BeforeEach |
|||
void setUp() { |
|||
now = System.currentTimeMillis(); |
|||
context = mock(LwM2mTransportContext.class); |
|||
helper = spy(new LwM2mTransportServerHelper(context)); |
|||
willReturn(now).given(helper).getCurrentTimeMillis(); |
|||
kvList = List.of( |
|||
TransportProtos.KeyValueProto.newBuilder().setKey(KEY_SW_STATE).setStringV(DOWNLOADING).build(), |
|||
TransportProtos.KeyValueProto.newBuilder().setKey(LOG_LWM2M_TELEMETRY).setStringV("Transport log example").build() |
|||
); |
|||
keyTsLatestMap = new ConcurrentHashMap<>(); |
|||
} |
|||
|
|||
@Test |
|||
void givenKeyAndLatestTsMapAndCurrentTs_whenGetTs_thenVerifyNoGetTsByKeyCall() { |
|||
assertThat(helper.getTs(null, null)).isEqualTo(now); |
|||
assertThat(helper.getTs(null, keyTsLatestMap)).isEqualTo(now); |
|||
assertThat(helper.getTs(emptyList(), null)).isEqualTo(now); |
|||
assertThat(helper.getTs(emptyList(), keyTsLatestMap)).isEqualTo(now); |
|||
assertThat(helper.getTs(kvList, null)).isEqualTo(now); |
|||
|
|||
verify(helper, never()).getTsByKey(anyString(), any(ConcurrentMap.class), anyLong()); |
|||
verify(helper, times(5)).getCurrentTimeMillis(); |
|||
} |
|||
|
|||
@Test |
|||
void givenKeyAndLatestTsMapAndCurrentTs_whenGetTs_thenVerifyGetTsByKeyCallByFirstKey() { |
|||
assertThat(helper.getTs(kvList, keyTsLatestMap)).isEqualTo(now); |
|||
|
|||
verify(helper, times(1)).getTsByKey(kvList.get(0).getKey(), keyTsLatestMap, now); |
|||
verify(helper, times(1)).getTsByKey(anyString(), any(ConcurrentMap.class), anyLong()); |
|||
} |
|||
|
|||
@Test |
|||
void givenKeyAndEmptyLatestTsMap_whenGetTsByKey_thenAddToMapAndReturnNow() { |
|||
assertThat(keyTsLatestMap).as("ts latest map before").isEmpty(); |
|||
|
|||
assertThat(helper.getTsByKey(KEY_SW_STATE, keyTsLatestMap, now)).as("getTsByKey").isEqualTo(now); |
|||
|
|||
assertThat(keyTsLatestMap).as("ts latest map after").hasSize(1); |
|||
assertThat(keyTsLatestMap.get(KEY_SW_STATE)).as("key present").isNotNull(); |
|||
assertThat(keyTsLatestMap.get(KEY_SW_STATE).get()).as("ts in map by key").isEqualTo(now); |
|||
} |
|||
|
|||
@Test |
|||
void givenKeyAndLatestTsMapWithExistedKey_whenGetTsByKey_thenCallSwapOrIncrementMethod() { |
|||
keyTsLatestMap.put(KEY_SW_STATE, new AtomicLong()); |
|||
keyTsLatestMap.put("other", new AtomicLong()); |
|||
assertThat(keyTsLatestMap).as("ts latest map").hasSize(2); |
|||
willReturn(now).given(helper).compareAndSwapOrIncrementTsAtomically(any(AtomicLong.class), anyLong()); |
|||
|
|||
assertThat(helper.getTsByKey(KEY_SW_STATE, keyTsLatestMap, now)).as("getTsByKey").isEqualTo(now); |
|||
|
|||
verify(helper, times(1)).compareAndSwapOrIncrementTsAtomically(keyTsLatestMap.get(KEY_SW_STATE), now); |
|||
verify(helper, times(1)).compareAndSwapOrIncrementTsAtomically(any(AtomicLong.class), anyLong()); |
|||
} |
|||
|
|||
@Test |
|||
void givenMapWithTsValueLessThanNow_whenCompareAndSwapOrIncrementTsAtomically_thenReturnNow() { |
|||
keyTsLatestMap.put(KEY_SW_STATE, new AtomicLong(now - 1)); |
|||
assertThat(helper.compareAndSwapOrIncrementTsAtomically(keyTsLatestMap.get(KEY_SW_STATE), now)).isEqualTo(now); |
|||
} |
|||
|
|||
@Test |
|||
void givenMapWithTsValueEqualsNow_whenCompareAndSwapOrIncrementTsAtomically_thenReturnNowIncremented() { |
|||
keyTsLatestMap.put(KEY_SW_STATE, new AtomicLong(now)); |
|||
assertThat(helper.compareAndSwapOrIncrementTsAtomically(keyTsLatestMap.get(KEY_SW_STATE), now)).isEqualTo(now + 1); |
|||
} |
|||
|
|||
@Test |
|||
void givenMapWithTsValueGreaterThanNow_whenCompareAndSwapOrIncrementTsAtomically_thenReturnGreaterThanNowIncremented() { |
|||
final long nextHourTs = now + TimeUnit.HOURS.toMillis(1); |
|||
keyTsLatestMap.put(KEY_SW_STATE, new AtomicLong(nextHourTs)); |
|||
assertThat(helper.compareAndSwapOrIncrementTsAtomically(keyTsLatestMap.get(KEY_SW_STATE), now)).isEqualTo(nextHourTs + 1); |
|||
} |
|||
|
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue