Skip to content

Commit

Permalink
Add some more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
colvinco committed Mar 1, 2025
1 parent 1e3f4af commit e8c0710
Showing 1 changed file with 150 additions and 49 deletions.
199 changes: 150 additions & 49 deletions solr/core/src/test/org/apache/solr/handler/admin/api/V2APISmokeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,54 @@

package org.apache.solr.handler.admin.api;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.*;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class V2APISmokeTest extends SolrCloudTestCase {

// TODO: How is this normally done in these tests?
private final ObjectMapper objectMapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
private URL baseUrl;
private String baseUrlV2;

@BeforeClass
public static void setupCluster() throws Exception {
configureCluster(1).addConfig("conf", configset("cloud-minimal")).configure();
System.setProperty("enable.packages", "true"); // for file upload
configureCluster(2).addConfig("conf", configset("cloud-minimal")).configure();
}

@Before
@Override
public void setUp() throws Exception {
super.setUp();

baseUrl = cluster.getJettySolrRunner(0).getBaseUrl();
baseUrlV2 = cluster.getJettySolrRunner(0).getBaseURLV2().toString();
}
Expand Down Expand Up @@ -175,10 +191,9 @@ public void testBackupsApi() throws Exception {

@Test
public void testClusterApi() throws Exception {
// TODO
// canPut("/cluster/files{filePath}");
// canDelete("/cluster/files{path}");

String tetFilePath = "/cluster/files/testFile-" + Instant.now().toEpochMilli();
canPut(tetFilePath, createTempFile().toFile());
// canDelete(tetFilePath); // TODO: 500 because delete cluster file calls delete local, which fails if file exists in cluster

canGet("/cluster/properties");
canPut("/cluster/properties", """
Expand All @@ -200,55 +215,79 @@ public void testClusterApi() throws Exception {
canGet("/cluster/zookeeper/data/security.json");

canPost("/cluster/replicas/balance", "{}");
// TODO: Node name?
// canPost("/cluster/nodes/{nodeName}/clear");
// canPost("/cluster/nodes/{sourceNodeName}/replace");
// canPost("/cluster/replicas/migrate", """
// {
// "sourceNodes": ["node1"]
// }
// """);
String nodeName = getNodeName();
canPost("/cluster/nodes/" + nodeName + "/clear", "");
canPost("/cluster/nodes/" + nodeName + "/replace", "");
canPost("/cluster/replicas/migrate", String.format(Locale.ROOT, """
{
"sourceNodes": ["%s"]
}
""", nodeName));
}

private String getNodeName() throws Exception {
NodesResponse nodesResponse = canGet("/cluster/nodes/", NodesResponse.class); // TODO: Missing from OA Spec
String nodeName = nodesResponse.nodes.get(0);
return nodeName;
}

@Test
public void testConfigSetsApi() throws Exception {
canGet("/configsets");
// TODO: need to add auth to clone _default
// canPost("/configsets", """
// {
// "name": "cfg123",
// "baseConfigSet": "_default"
// }
// """);
// TODO need data to upload
// canPut("/configsets/cfg123", """
// """);
// canPut("/configsets/cfg123/file345", """
// """);
// canDelete("/configsets/cfg123");
File zipFile = createTempZipFile("solr/configsets/upload/regular");
canPut("/configsets/cfg123", zipFile);
canPut("/configsets/cfg123/file345", """
""");
canPost("/configsets", """
{
"name": "cfg456",
"baseConfigSet": "cfg123"
}
""");
canDelete("/configsets/cfg123");
}

@Test
public void testCoresApi() throws Exception {
// TODO
// canPost("/cores/{coreName}/backups");
// canPost("/cores/{coreName}/install");
// canPost("/cores/{coreName}/merge-indices");
// canPost("/cores/{coreName}/reload");
// canPost("/cores/{coreName}/rename");
// canPost("/cores/{coreName}/replication/backups");
// canGet("/cores/{coreName}/replication/files");
// canGet("/cores/{coreName}/replication/files/{filePath}");
// canGet("/cores/{coreName}/replication/indexversion");
// canPost("/cores/{coreName}/restore");
// canGet("/cores/{coreName}/segments");
// canGet("/cores/{coreName}/snapshots");
// canPost("/cores/{coreName}/snapshots/{snapshotName}");
// canDelete("/cores/{coreName}/snapshots/{snapshotName}");
// canPost("/cores/{coreName}/swap");
// canPost("/cores/{coreName}/unload");

testCollectionsAndCoresApi("cores", "testCore");
// TODO /cores is missing from OA Spec
canPost("/collections", """
{
"name": "testCore",
"numShards": 1
}
""");
canGet("/cores");
// final String nodeNode = getNodeName();
// canPost("/cores", String.format(Locale.ROOT, """
// {
// "create": {
// "name": "testCore",
// "coreNodeName": "%s",
// "configSet": "_default"
// }
// }
// """, nodeNode));
// String corePath = "/cores/testCore";
// canGet(corePath);
// canPost(corePath + "/reload", """
// """);
// canPost(corePath + "/backups");
// canPost(corePath + "/install");
// canPost(corePath + "/merge-indices");
// canPost(corePath + "/rename");
// canPost(corePath + "/replication/backups");
// canGet(corePath + "/replication/files");
// canGet(corePath + "/replication/files/{filePath}");
// canGet(corePath + "/replication/indexversion");
// canPost(corePath + "/restore");
// canGet(corePath + "/segments");
// canGet(corePath + "/snapshots");
// canPost(corePath + "/snapshots/{snapshotName}");
// canDelete(corePath + "/snapshots/{snapshotName}");
// canPost(corePath + "/swap");
// canPost(corePath + "/unload");

// testCollectionsAndCoresApi("cores", "testCore");
}


Expand All @@ -274,11 +313,11 @@ private void testCollectionsAndCoresApi(String indexType, String indexName) thro
canGet(schemaPath);
canGet(schemaPath + "/copyfields");
canGet(schemaPath + "/dynamicfields");
// canGet(schemaPath + "/dynamicfields/field123"); // TODO: Need a valid id
canGet(schemaPath + "/dynamicfields/*_txt_en");
canGet(schemaPath + "/fields");
// canGet(schemaPath + "/fields/field123"); // TODO: Need a valid id
canGet(schemaPath + "/fields/id");
canGet(schemaPath + "/fieldtypes");
// canGet(schemaPath + "/fieldtypes/fieldType123"); // TODO: Need a valid id
canGet(schemaPath + "/fieldtypes/boolean");
canGet(schemaPath + "/name");
canGet(schemaPath + "/similarity");
canGet(schemaPath + "/uniquekey");
Expand Down Expand Up @@ -309,10 +348,28 @@ private void canPut(String url, String content) throws Exception {
}
}


private void canPut(String url, File content) throws Exception {
try (HttpSolrClient client = new HttpSolrClient.Builder(baseUrl.toString()).build()) {
HttpPut httpPut = new HttpPut(baseUrlV2 + url);
httpPut.setEntity(new FileEntity(content));
HttpResponse httpResponse = client.getHttpClient().execute(httpPut);
assertEquals(200, httpResponse.getStatusLine().getStatusCode());
}
}

private void canGet(String url) throws Exception {
canGet(url, null);
}

private <T> T canGet(String url, Class<T> responseType) throws Exception {
try (HttpSolrClient client = new HttpSolrClient.Builder(baseUrl.toString()).build()) {
HttpResponse httpResponse = client.getHttpClient().execute(new HttpGet(baseUrlV2 + url));
assertEquals(200, httpResponse.getStatusLine().getStatusCode());
if (responseType == null) {
return null;
}
return objectMapper.readValue(httpResponse.getEntity().getContent(), responseType);
}
}

Expand All @@ -322,4 +379,48 @@ private void canDelete(String url) throws Exception {
assertEquals(200, httpResponse.getStatusLine().getStatusCode());
}
}

private static class NodesResponse {
public List<String> nodes;
}


// TODO Duplicated from TestConfigSetsAPI... should the configset v2 tests be there instead?
private File createTempZipFile(String directoryPath) {
try {
final File zipFile = createTempFile("configset", "zip").toFile();
final File directory = SolrTestCaseJ4.getFile(directoryPath).toFile();
zip(directory, zipFile);
return zipFile;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void zip(File directory, File zipfile) throws IOException {
URI base = directory.toURI();
Deque<File> queue = new ArrayDeque<>();
queue.push(directory);
OutputStream out = new FileOutputStream(zipfile);
try (ZipOutputStream zout = new ZipOutputStream(out)) {
while (!queue.isEmpty()) {
directory = queue.pop();
for (File kid : directory.listFiles()) {
String name = base.relativize(kid.toURI()).getPath();
if (kid.isDirectory()) {
queue.push(kid);
name = name.endsWith("/") ? name : name + "/";
zout.putNextEntry(new ZipEntry(name));
} else {
zout.putNextEntry(new ZipEntry(name));

try (InputStream in = new FileInputStream(kid)) {
in.transferTo(zout);
}

zout.closeEntry();
}
}
}
}
}
}

0 comments on commit e8c0710

Please sign in to comment.