Fix black box tests.

This commit is contained in:
Igor Kulikov 2025-07-18 13:54:32 +03:00
parent fba48ee9c5
commit 1330cd932e
4 changed files with 101 additions and 37 deletions

View File

@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AiModelId; import org.thingsboard.server.common.data.id.AiModelId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.config.annotations.ApiOperation; import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.ai.AiChatModelService; import org.thingsboard.server.service.ai.AiChatModelService;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
@ -59,6 +60,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHO
@Validated @Validated
@RestController @RestController
@TbCoreComponent
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("/api/ai/model") @RequestMapping("/api/ai/model")
class AiModelController extends BaseController { class AiModelController extends BaseController {

View File

@ -38,6 +38,7 @@ import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.testng.Assert.fail; import static org.testng.Assert.fail;
import static org.thingsboard.server.msa.TestUtils.addComposeVersion;
@Slf4j @Slf4j
public class ContainerTestSuite { public class ContainerTestSuite {
@ -53,7 +54,7 @@ public class ContainerTestSuite {
private static final String TB_JS_EXECUTOR_LOG_REGEXP = ".*template started.*"; private static final String TB_JS_EXECUTOR_LOG_REGEXP = ".*template started.*";
private static final Duration CONTAINER_STARTUP_TIMEOUT = Duration.ofSeconds(400); private static final Duration CONTAINER_STARTUP_TIMEOUT = Duration.ofSeconds(400);
private DockerComposeContainer<?> testContainer; private DockerComposeContainerImpl testContainer;
private ThingsBoardDbInstaller installTb; private ThingsBoardDbInstaller installTb;
private boolean isActive; private boolean isActive;
@ -78,8 +79,6 @@ public class ContainerTestSuite {
} }
public void start() { public void start() {
installTb = new ThingsBoardDbInstaller();
installTb.createVolumes();
log.info("System property of blackBoxTests.redisCluster is {}", IS_VALKEY_CLUSTER); log.info("System property of blackBoxTests.redisCluster is {}", IS_VALKEY_CLUSTER);
log.info("System property of blackBoxTests.redisSentinel is {}", IS_VALKEY_SENTINEL); log.info("System property of blackBoxTests.redisSentinel is {}", IS_VALKEY_SENTINEL);
log.info("System property of blackBoxTests.redisSsl is {}", IS_VALKEY_SSL); log.info("System property of blackBoxTests.redisSsl is {}", IS_VALKEY_SSL);
@ -93,17 +92,8 @@ public class ContainerTestSuite {
FileUtils.copyDirectory(new File("src/test/resources"), new File(targetDir)); FileUtils.copyDirectory(new File("src/test/resources"), new File(targetDir));
class DockerComposeContainerImpl<SELF extends DockerComposeContainer<SELF>> extends DockerComposeContainer<SELF> { installTb = new ThingsBoardDbInstaller(targetDir);
public DockerComposeContainerImpl(List<File> composeFiles) { installTb.createVolumes();
super(composeFiles);
}
@Override
public void stop() {
super.stop();
tryDeleteDir(targetDir);
}
}
if (IS_VALKEY_SSL) { if (IS_VALKEY_SSL) {
addToFile(targetDir, "cache-valkey.env", addToFile(targetDir, "cache-valkey.env",
@ -132,7 +122,9 @@ public class ContainerTestSuite {
composeFiles.add(new File(targetDir + "docker-compose.cassandra.volumes.yml")); composeFiles.add(new File(targetDir + "docker-compose.cassandra.volumes.yml"));
} }
testContainer = new DockerComposeContainerImpl<>(composeFiles) addComposeVersion(composeFiles, "3.0");
testContainer = new DockerComposeContainerImpl(targetDir, composeFiles)
.withPull(false) .withPull(false)
.withLocalCompose(true) .withLocalCompose(true)
.withOptions("--compatibility") .withOptions("--compatibility")
@ -194,7 +186,8 @@ public class ContainerTestSuite {
public void stop() { public void stop() {
if (isActive) { if (isActive) {
testContainer.stop(); testContainer.stop();
installTb.savaLogsAndRemoveVolumes(); installTb.saveLogsAndRemoveVolumes();
testContainer.cleanup();
setActive(false); setActive(false);
} }
} }
@ -261,4 +254,23 @@ public class ContainerTestSuite {
public DockerComposeContainer<?> getTestContainer() { public DockerComposeContainer<?> getTestContainer() {
return testContainer; return testContainer;
} }
static class DockerComposeContainerImpl extends DockerComposeContainer<DockerComposeContainerImpl> {
private final String targetDir;
public DockerComposeContainerImpl(String targetDir, List<File> composeFiles) {
super(composeFiles);
this.targetDir = targetDir;
}
@Override
public void stop() {
super.stop();
}
public void cleanup() {
tryDeleteDir(this.targetDir);
}
}
} }

View File

@ -0,0 +1,43 @@
/**
* Copyright © 2016-2025 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.msa;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class TestUtils {
public static void addComposeVersion(List<File> composeFiles, String version) throws IOException {
for (File composeFile : composeFiles) {
addComposeVersion(composeFile, version);
}
}
public static void addComposeVersion(File composeFile, String version) throws IOException {
Path composeFilePath = composeFile.toPath();
String data = Files.readString(composeFilePath);
String versionString = "version: '" + version + "'";
if (!data.contains(versionString)) {
data += "\n" + versionString + "\n";
}
Files.writeString(composeFilePath, data);
}
}

View File

@ -20,6 +20,7 @@ import org.testcontainers.utility.Base58;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -29,6 +30,8 @@ import java.util.StringJoiner;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import static org.thingsboard.server.msa.TestUtils.addComposeVersion;
@Slf4j @Slf4j
public class ThingsBoardDbInstaller { public class ThingsBoardDbInstaller {
@ -53,6 +56,7 @@ public class ThingsBoardDbInstaller {
private final DockerComposeExecutor dockerCompose; private final DockerComposeExecutor dockerCompose;
private final String targetDir;
private final String postgresDataVolume; private final String postgresDataVolume;
private final String cassandraDataVolume; private final String cassandraDataVolume;
@ -69,27 +73,30 @@ public class ThingsBoardDbInstaller {
private final String tbEdqsLogVolume; private final String tbEdqsLogVolume;
private final Map<String, String> env; private final Map<String, String> env;
public ThingsBoardDbInstaller() { public ThingsBoardDbInstaller(String targetDir) throws IOException {
this.targetDir = targetDir;
log.info("System property of blackBoxTests.redisCluster is {}", IS_VALKEY_CLUSTER); log.info("System property of blackBoxTests.redisCluster is {}", IS_VALKEY_CLUSTER);
log.info("System property of blackBoxTests.redisCluster is {}", IS_VALKEY_SENTINEL); log.info("System property of blackBoxTests.redisSentinel is {}", IS_VALKEY_SENTINEL);
log.info("System property of blackBoxTests.hybridMode is {}", IS_HYBRID_MODE); log.info("System property of blackBoxTests.hybridMode is {}", IS_HYBRID_MODE);
List<File> composeFiles = new ArrayList<>(Arrays.asList( List<File> composeFiles = new ArrayList<>(Arrays.asList(
new File("./../../docker/docker-compose.yml"), new File(targetDir + "docker-compose.yml"),
new File("./../../docker/docker-compose.volumes.yml"), new File(targetDir + "docker-compose.volumes.yml"),
IS_HYBRID_MODE IS_HYBRID_MODE
? new File("./../../docker/docker-compose.hybrid.yml") ? new File(targetDir + "docker-compose.hybrid.yml")
: new File("./../../docker/docker-compose.postgres.yml"), : new File(targetDir + "docker-compose.postgres.yml"),
new File("./../../docker/docker-compose.postgres.volumes.yml"), new File(targetDir + "docker-compose.postgres.volumes.yml"),
resolveValkeyComposeFile(), resolveValkeyComposeFile(targetDir),
resolveValkeyComposeVolumesFile() resolveValkeyComposeVolumesFile(targetDir)
)); ));
if (IS_HYBRID_MODE) { if (IS_HYBRID_MODE) {
composeFiles.add(new File("./../../docker/docker-compose.cassandra.volumes.yml")); composeFiles.add(new File(targetDir + "docker-compose.cassandra.volumes.yml"));
composeFiles.add(new File("src/test/resources/docker-compose.hybrid-test-extras.yml")); composeFiles.add(new File(targetDir + "docker-compose.hybrid-test-extras.yml"));
} else { } else {
composeFiles.add(new File("src/test/resources/docker-compose.postgres-test-extras.yml")); composeFiles.add(new File(targetDir + "docker-compose.postgres-test-extras.yml"));
} }
addComposeVersion(composeFiles, "3.0");
String identifier = Base58.randomString(6).toLowerCase(); String identifier = Base58.randomString(6).toLowerCase();
String project = identifier + Base58.randomString(6).toLowerCase(); String project = identifier + Base58.randomString(6).toLowerCase();
@ -137,24 +144,24 @@ public class ThingsBoardDbInstaller {
dockerCompose.withEnv(env); dockerCompose.withEnv(env);
} }
private static File resolveValkeyComposeVolumesFile() { private static File resolveValkeyComposeVolumesFile(String targetDir) {
if (IS_VALKEY_CLUSTER) { if (IS_VALKEY_CLUSTER) {
return new File("./../../docker/docker-compose.valkey-cluster.volumes.yml"); return new File(targetDir + "docker-compose.valkey-cluster.volumes.yml");
} }
if (IS_VALKEY_SENTINEL) { if (IS_VALKEY_SENTINEL) {
return new File("./../../docker/docker-compose.valkey-sentinel.volumes.yml"); return new File(targetDir + "docker-compose.valkey-sentinel.volumes.yml");
} }
return new File("./../../docker/docker-compose.valkey.volumes.yml"); return new File(targetDir + "docker-compose.valkey.volumes.yml");
} }
private static File resolveValkeyComposeFile() { private static File resolveValkeyComposeFile(String targetDir) {
if (IS_VALKEY_CLUSTER) { if (IS_VALKEY_CLUSTER) {
return new File("./../../docker/docker-compose.valkey-cluster.yml"); return new File(targetDir + "docker-compose.valkey-cluster.yml");
} }
if (IS_VALKEY_SENTINEL) { if (IS_VALKEY_SENTINEL) {
return new File("./../../docker/docker-compose.valkey-sentinel.yml"); return new File(targetDir + "docker-compose.valkey-sentinel.yml");
} }
return new File("./../../docker/docker-compose.valkey.yml"); return new File(targetDir + "docker-compose.valkey.yml");
} }
public Map<String, String> getEnv() { public Map<String, String> getEnv() {
@ -240,7 +247,7 @@ public class ThingsBoardDbInstaller {
} }
} }
public void savaLogsAndRemoveVolumes() { public void saveLogsAndRemoveVolumes() {
copyLogs(tbLogVolume, "./target/tb-logs/"); copyLogs(tbLogVolume, "./target/tb-logs/");
copyLogs(tbCoapTransportLogVolume, "./target/tb-coap-transport-logs/"); copyLogs(tbCoapTransportLogVolume, "./target/tb-coap-transport-logs/");
copyLogs(tbLwm2mTransportLogVolume, "./target/tb-lwm2m-transport-logs/"); copyLogs(tbLwm2mTransportLogVolume, "./target/tb-lwm2m-transport-logs/");