Skip to content

Commit

Permalink
Fixes neo4j-contrib#4207: Integration Tests for Load Procedures with …
Browse files Browse the repository at this point in the history
…Cloud Object Storage
  • Loading branch information
vga91 committed Nov 11, 2024
1 parent 7c6254a commit 1342ac1
Show file tree
Hide file tree
Showing 20 changed files with 803 additions and 283 deletions.
3 changes: 2 additions & 1 deletion extended-it/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ dependencies {
testImplementation group: 'org.testcontainers', name: 'chromadb', version: '1.20.2'
testImplementation group: 'org.testcontainers', name: 'weaviate', version: '1.20.2'
testImplementation group: 'org.testcontainers', name: 'milvus', version: '1.20.2'

testImplementation group: 'org.apache.poi', name: 'poi', version: '5.1.0'
testImplementation group: 'org.apache.poi', name: 'poi-ooxml', version: '5.1.0'
configurations.all {
exclude group: 'org.slf4j', module: 'slf4j-nop'
exclude group: 'ch.qos.logback', module: 'logback-classic'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package apoc.export;

import apoc.export.arrow.ExportArrow;
import apoc.export.arrow.ImportArrow;
import apoc.load.Gexf;
import apoc.meta.Meta;
import apoc.util.GoogleCloudStorageContainerExtension;
import apoc.util.TestUtil;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;

import static apoc.ApocConfig.APOC_EXPORT_FILE_ENABLED;
import static apoc.ApocConfig.APOC_IMPORT_FILE_ENABLED;
import static apoc.ApocConfig.apocConfig;
import static apoc.export.arrow.ImportArrowTestUtil.MAPPING_ALL;
import static apoc.export.arrow.ImportArrowTestUtil.prepareDbForArrow;
import static apoc.export.arrow.ImportArrowTestUtil.testImportCommon;
import static apoc.util.ExtendedTestUtil.clearDb;
import static apoc.util.GexfTestUtil.testImportGexfCommon;
import static apoc.util.GoogleCloudStorageContainerExtension.gcsUrl;

public class ImportGoogleCloudStorageTest {
public static GoogleCloudStorageContainerExtension gcs = new GoogleCloudStorageContainerExtension()
.withMountedResourceFile("test_all.arrow", "/folder/test_all.arrow")
.withMountedResourceFile("gexf/data.gexf", "/folder/data.gexf");

@ClassRule
public static DbmsRule db = new ImpermanentDbmsRule();

@BeforeClass
public static void setUp() throws Exception {
gcs.start();
TestUtil.registerProcedure(db, ExportArrow.class, ImportArrow.class, Meta.class, Gexf.class);
prepareDbForArrow(db);
apocConfig().setProperty(APOC_IMPORT_FILE_ENABLED, true);
apocConfig().setProperty(APOC_EXPORT_FILE_ENABLED, true);
}

@Test
public void testImportArrow() {
String url = gcsUrl(gcs, "b/folder/o/test_all.arrow?alt=media");
testImportCommon(db, url, MAPPING_ALL);
}

@Test
public void testImportGexf() {
clearDb(db);
String url = gcsUrl(gcs, "b/folder/o/data.gexf?alt=media");
testImportGexfCommon(db, url);
}

}
120 changes: 120 additions & 0 deletions extended-it/src/test/java/apoc/load/LoadGoogleCloudStorageTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package apoc.load;

import apoc.load.xls.LoadXls;
import apoc.util.GoogleCloudStorageContainerExtension;
import apoc.util.TestUtil;
import apoc.util.Util;
import apoc.xml.XmlTestUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.neo4j.driver.internal.util.Iterables;
import org.neo4j.graphdb.Result;
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static apoc.load.LoadCsvTest.assertRow;
import static apoc.util.GoogleCloudStorageContainerExtension.gcsUrl;
import static apoc.util.MapUtil.map;
import static apoc.util.TestUtil.testCall;
import static apoc.util.TestUtil.testResult;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class LoadGoogleCloudStorageTest {

public static GoogleCloudStorageContainerExtension gcs = new GoogleCloudStorageContainerExtension()
.withMountedResourceFile("test.csv", "/folder/test.csv")
.withMountedResourceFile("map.json", "/folder/map.json")
.withMountedResourceFile("xml/books.xml", "/folder/books.xml")
.withMountedResourceFile("load_test.xlsx", "/folder/load_test.xlsx")
.withMountedResourceFile("wikipedia.html", "/folder/wikipedia.html");

@ClassRule
public static DbmsRule db = new ImpermanentDbmsRule();

@BeforeClass
public static void setUp() throws Exception {
gcs.start();
TestUtil.registerProcedure(db, LoadCsv.class, LoadJson.class, LoadHtml.class, LoadXls.class, Xml.class);
}

@AfterClass
public static void tearDown() {
gcs.close();
db.shutdown();
}

@Test
public void testLoadCsv() {
String url = gcsUrl(gcs, "b/folder/o/test.csv?alt=media");

testResult(db, "CALL apoc.load.csv($url)", map("url", url), (r) -> {
assertRow(r, "Selma", "8", 0L);
assertRow(r, "Rana", "11", 1L);
assertRow(r, "Selina", "18", 2L);
assertFalse("It should be the last record", r.hasNext());
});
}

@Test
public void testLoadJSON() {
String url = gcsUrl(gcs, "b/folder/o/map.json?alt=media");
testCall(db, "CALL apoc.load.jsonArray($url, '$.foo')", map("url", url), (r) -> {
assertEquals(asList(1L,2L,3L), r.get("value"));
});
}

@Test
public void testLoadXml() {
String url = gcsUrl(gcs, "b/folder/o/books.xml?alt=media");
testCall(db, "CALL apoc.load.xml($url,'/catalog/book[title=\"Maeve Ascendant\"]/.',{failOnError:false}) yield value as result", Util.map("url", url), (r) -> {
Object value = Iterables.single(r.values());
Assert.assertEquals(XmlTestUtils.XML_XPATH_AS_NESTED_MAP, value);
});
}

@Test
public void testLoadXls() {
String url = gcsUrl(gcs, "b/folder/o/load_test.xlsx?alt=media");
testResult(db, "CALL apoc.load.xls($url,'Full',{mapping:{Integer:{type:'int'}, Array:{type:'int',array:true,arraySep:';'}}})", map("url",url), // 'file:load_test.xlsx'
(r) -> {
assertXlsRow(r,0L,"String","Test","Boolean",true,"Integer",2L,"Float",1.5d,"Array",asList(1L,2L,3L));
assertFalse("Should not have another row",r.hasNext());
});
}

@Test
public void testLoadHtml() {
String url = gcsUrl(gcs, "b/folder/o/wikipedia.html?alt=media");

Map<String, Object> query = map("links", "a[href]");

testCall(db, "CALL apoc.load.html($url,$query)",
map("url", url, "query", query),
row -> {
final List<Map<String, Object>> actual = (List) ((Map) row.get("value")).get("links");
assertEquals(106, actual.size());
assertTrue(actual.stream().allMatch(i -> i.get("tagName").equals("a")));
});
}

static void assertXlsRow(Result r, long lineNo, Object...data) {
Map<String, Object> row = r.next();
Map<String, Object> map = map(data);
assertEquals(map, row.get("map"));
Map<Object, Object> stringMap = new LinkedHashMap<>(map.size());
map.forEach((k,v) -> stringMap.put(k,v == null ? null : v.toString()));
assertEquals(new ArrayList<>(map.values()), row.get("list"));
assertEquals(lineNo, row.get("lineNo"));
}
}
88 changes: 70 additions & 18 deletions extended-it/src/test/java/apoc/s3/LoadS3Test.java
Original file line number Diff line number Diff line change
@@ -1,44 +1,55 @@
package apoc.s3;

import apoc.load.LoadCsv;
import apoc.load.LoadDirectory;
import apoc.load.LoadHtml;
import apoc.load.LoadJson;
import apoc.load.Xml;
import apoc.load.xls.LoadXls;
import apoc.util.TestUtil;
import apoc.util.Util;
import apoc.util.s3.S3BaseTest;
import apoc.xml.XmlTestUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.jupiter.api.AfterAll;

import org.neo4j.driver.internal.util.Iterables;
import org.neo4j.graphdb.Result;
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static apoc.ApocConfig.APOC_IMPORT_FILE_ENABLED;
import static apoc.ApocConfig.APOC_IMPORT_FILE_USE_NEO4J_CONFIG;
import static apoc.ApocConfig.apocConfig;
import static apoc.load.LoadCsvTest.assertRow;
import static apoc.util.ExtendedITUtil.EXTENDED_PATH;
import static apoc.util.MapUtil.map;
import static apoc.util.S3ExtendedUtil.putToS3AndGetUrl;
import static apoc.util.TestUtil.testCall;
import static apoc.util.TestUtil.testResult;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class LoadS3Test extends S3BaseTest {
public class LoadS3Test extends S3BaseExtendedTest {

@Rule
public DbmsRule db = new ImpermanentDbmsRule();

@Before
public void setUp() throws Exception {
TestUtil.registerProcedure(db, LoadCsv.class, LoadJson.class, Xml.class);
TestUtil.registerProcedure(db, LoadCsv.class, LoadDirectory.class, LoadJson.class, LoadHtml.class, LoadXls.class, Xml.class);
apocConfig().setProperty(APOC_IMPORT_FILE_ENABLED, true);
apocConfig().setProperty(APOC_IMPORT_FILE_USE_NEO4J_CONFIG, false);
putFolderToS3();
}

@AfterAll
Expand All @@ -47,10 +58,8 @@ public void tearDownAll() {
}

@Test
public void testLoadCsvS3() {
String url = s3Container.putFile(EXTENDED_PATH + "src/test/resources/test.csv");
url = removeRegionFromUrl(url);

public void testLoadCsv() {
String url = putToS3AndGetUrl(s3ExtendedContainer, EXTENDED_PATH + "src/test/resources/test.csv");
testResult(db, "CALL apoc.load.csv($url,{failOnError:false})", map("url", url), (r) -> {
assertRow(r, "Selma", "8", 0L);
assertRow(r, "Rana", "11", 1L);
Expand All @@ -59,29 +68,72 @@ public void testLoadCsvS3() {
});
}

@Test public void testLoadJsonS3() {
String url = s3Container.putFile(EXTENDED_PATH + "src/test/resources/map.json");
url = removeRegionFromUrl(url);

@Test public void testLoadJson() {
String url = putToS3AndGetUrl(s3ExtendedContainer, EXTENDED_PATH + "src/test/resources/map.json");
testCall(db, "CALL apoc.load.json($url,'')",map("url", url),
(row) -> {
assertEquals(map("foo",asList(1L,2L,3L)), row.get("value"));
});
}

@Test public void testLoadXmlS3() {
String url = s3Container.putFile(EXTENDED_PATH + "src/test/resources/xml/books.xml");
url = removeRegionFromUrl(url);

@Test public void testLoadXml() {
String url = putToS3AndGetUrl(s3ExtendedContainer, EXTENDED_PATH + "src/test/resources/xml/books.xml");
testCall(db, "CALL apoc.load.xml($url,'/catalog/book[title=\"Maeve Ascendant\"]/.',{failOnError:false}) yield value as result", Util.map("url", url), (r) -> {
Object value = Iterables.single(r.values());
Assert.assertEquals(XmlTestUtils.XML_XPATH_AS_NESTED_MAP, value);
});
}

private String removeRegionFromUrl(String url) {
return url.replace(s3Container.getEndpointConfiguration().getSigningRegion() + ".", "");
@Test public void testLoadXls() {
String url = putToS3AndGetUrl(s3ExtendedContainer, EXTENDED_PATH + "src/test/resources/load_test.xlsx");
testResult(db, "CALL apoc.load.xls($url,'Full',{mapping:{Integer:{type:'int'}, Array:{type:'int',array:true,arraySep:';'}}})", map("url",url), // 'file:load_test.xlsx'
(r) -> {
assertXlsRow(r,0L,"String","Test","Boolean",true,"Integer",2L,"Float",1.5d,"Array",asList(1L,2L,3L));
assertFalse("Should not have another row",r.hasNext());
});
}

@Test
public void testLoadHtml() {
String url = putToS3AndGetUrl(s3ExtendedContainer, EXTENDED_PATH + "src/test/resources/wikipedia.html");

Map<String, Object> query = map("links", "a[href]");

testCall(db, "CALL apoc.load.html($url,$query)",
map("url", url, "query", query),
row -> {
final List<Map<String, Object>> actual = (List) ((Map) row.get("value")).get("links");
assertEquals(106, actual.size());
assertTrue(actual.stream().allMatch(i -> i.get("tagName").equals("a")));
});
}

private void putFolderToS3() {
StringBuilder csv= new StringBuilder(); // Faster
csv.append("name,age\r\n");
csv.append("Bonzo,20\r\n");
csv.append("Oronzo,45\r\n");
byte[] data = csv.toString().getBytes(StandardCharsets.UTF_8);

s3ExtendedContainer.putObjectToS3("test_folder/test.csv", data);

csv = new StringBuilder();
csv.append("name,age\r\n");
csv.append("Bobby,18\r\n");
csv.append("Maruccio,90\r\n");
data = csv.toString().getBytes(StandardCharsets.UTF_8);

s3ExtendedContainer.putObjectToS3("test_folder/test_1.csv", data);
}

static void assertXlsRow(Result r, long lineNo, Object...data) {
Map<String, Object> row = r.next();
Map<String, Object> map = map(data);
assertEquals(map, row.get("map"));
Map<Object, Object> stringMap = new LinkedHashMap<>(map.size());
map.forEach((k,v) -> stringMap.put(k,v == null ? null : v.toString()));
assertEquals(new ArrayList<>(map.values()), row.get("list"));
assertEquals(lineNo, row.get("lineNo"));
}

}
Loading

0 comments on commit 1342ac1

Please sign in to comment.