Skip to content

Commit

Permalink
test: create test scenarios
Browse files Browse the repository at this point in the history
Signed-off-by: Otavio Santana <otaviopolianasantana@gmail.com>
  • Loading branch information
otaviojava committed Mar 10, 2024
1 parent e9525ed commit 7160b05
Show file tree
Hide file tree
Showing 12 changed files with 1,445 additions and 29 deletions.
Expand Up @@ -71,6 +71,7 @@ public CommunicationEntity insert(CommunicationEntity entity) {
entity.elements().forEach(e -> vertex.property(e.name(), ValueUtil.convert(e.value())));
entity.add(ID_PROPERTY, vertex.id());
vertex.property(ID_PROPERTY, vertex.id());
GraphTransactionUtil.transaction(graph);
return entity;
}

Expand Down Expand Up @@ -102,6 +103,7 @@ public CommunicationEntity update(CommunicationEntity entity) {
Vertex vertex = vertices.next();
entity.elements().forEach(e -> vertex.property(e.name(), ValueUtil.convert(e.value())));
});
GraphTransactionUtil.transaction(graph);
return entity;
}

Expand All @@ -122,6 +124,7 @@ public void delete(DeleteQuery query) {
});

traversal.drop().iterate();
GraphTransactionUtil.transaction(graph);
}

@Override
Expand Down
Expand Up @@ -12,7 +12,7 @@
*
* Otavio Santana
*/
package org.eclipse.jnosql.mapping.graph;
package org.eclipse.jnosql.communication.graph;

import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Transaction;
Expand All @@ -24,9 +24,10 @@
import static org.eclipse.jnosql.mapping.core.config.MappingConfigurations.GRAPH_TRANSACTION_AUTOMATIC;

/**
* Utilitarian to {@link Transaction}
* Utility class providing methods to manage transactions in a graph database.
* This class offers functionality to lock and unlock transactions, as well as automatic transaction management.
*/
final class GraphTransactionUtil {
public final class GraphTransactionUtil {

private static final Logger LOGGER = Logger.getLogger(GraphTransactionUtil.class.getName());
private static final ThreadLocal<Transaction> THREAD_LOCAL = new ThreadLocal<>();
Expand All @@ -35,53 +36,60 @@ private GraphTransactionUtil() {
}

/**
* Holds the current transaction to don't allow a {@link Transaction#commit()}
* Locks the current transaction, preventing it from being committed.
*
* @param transaction the {@link Transaction}
* @param transaction the transaction to lock
*/
static void lock(Transaction transaction) {
public static void lock(Transaction transaction) {
THREAD_LOCAL.set(transaction);
}

/**
* Unlocks the {@link Transaction} of the current thread
* Unlocks the current transaction.
* Allows the transaction to be committed.
*/
static void unlock() {
public static void unlock() {
THREAD_LOCAL.remove();
}

/**
* Checks if possible to {@link Transaction#commit()},
* if checks it the {@link Transaction} holds and if it is defined as an automatic transaction.
* Automatically commits a transaction if enabled and not locked.
*
* @param graph the graph
* @param graph the graph instance
*/
static void transaction(Graph graph) {
if (isAutomatic() && isNotLock() && Objects.nonNull(graph)) {
try {
Transaction transaction = graph.tx();
if (transaction != null) {
transaction.commit();
public static void transaction(Graph graph) {
synchronized (graph) {
if (isAutomatic() && isNotLock() && Objects.nonNull(graph)) {
try {
Transaction transaction = graph.tx();
if (transaction != null) {
transaction.commit();
}
} catch (Exception exception) {
LOGGER.info("Unable to do transaction automatically in the graph, reason: " +
exception.getMessage());
}
} catch (Exception exception) {
LOGGER.info("Unable to do transaction automatically in the graph, reason: " +
exception.getMessage());
}

}
}
}

/**
* Check if the transaction is enabled
* Checks if automatic transaction management is enabled.
*
* @return Check if the transaction is enabled
* @return true if automatic transaction management is enabled, false otherwise
*/
static boolean isAutomatic() {
public static boolean isAutomatic() {
return MicroProfileSettings.INSTANCE.get(GRAPH_TRANSACTION_AUTOMATIC, String.class)
.map(Boolean::valueOf)
.orElse(true);
}

/**
* Checks if the current transaction is not locked.
*
* @return true if the current transaction is not locked, false otherwise
*/
private static boolean isNotLock() {
return THREAD_LOCAL.get() == null;
}
Expand Down
Expand Up @@ -11,9 +11,9 @@
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Transaction;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.eclipse.jnosql.communication.CommunicationException;
import org.eclipse.jnosql.communication.graph.CommunicationEntityConverter;
import org.eclipse.jnosql.communication.graph.GraphDatabaseManager;
import org.eclipse.jnosql.communication.graph.GraphTransactionUtil;
import org.eclipse.jnosql.mapping.IdNotFoundException;
import org.eclipse.jnosql.mapping.metadata.EntityMetadata;
import org.eclipse.jnosql.mapping.metadata.FieldMetadata;
Expand Down Expand Up @@ -198,7 +198,7 @@ public EdgeTraversal traversalEdge(Object... edgeIds) {
if (Stream.of(edgeIds).anyMatch(Objects::isNull)) {
throw new IllegalStateException("No one edgeId element cannot be null");
}
return null;
return new DefaultEdgeTraversal(() -> traversal().E(edgeIds), INITIAL_EDGE, converter());
}

@Override
Expand Down
Expand Up @@ -131,7 +131,7 @@ public EdgeTraversal dedup(String... labels) {
@Override
public Optional<EdgeEntity> next() {
Optional<Edge> edgeOptional = flow.apply(supplier.get()).tryNext();
return edgeOptional.map(edge ->EdgeEntity.of(converter, edge));
return edgeOptional.map(edge -> EdgeEntity.of(converter, edge));
}

@Override
Expand Down
Expand Up @@ -145,8 +145,8 @@ static EdgeEntity of(EntityConverter converter, Edge edge) {
Objects.requireNonNull(converter, "converter is required");
Objects.requireNonNull(edge, "edge is required");
var entityConverter = CommunicationEntityConverter.INSTANCE;
return new DefaultEdgeEntity<>(edge, converter.toEntity(entityConverter.apply(edge.outVertex())),
converter.toEntity(entityConverter.apply(edge.inVertex())));
return new DefaultEdgeEntity<>(edge, converter.toEntity(entityConverter.apply(edge.inVertex())),
converter.toEntity(entityConverter.apply(edge.outVertex())));
}

}
Expand Up @@ -24,6 +24,7 @@
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;
import org.eclipse.jnosql.communication.graph.GraphTransactionUtil;


@Transactional
Expand Down
@@ -0,0 +1,96 @@
/*
*
* Copyright (c) 2022 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*
*/
package org.eclipse.jnosql.mapping.graph;

import jakarta.inject.Inject;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.eclipse.jnosql.mapping.graph.entities.Book;
import org.eclipse.jnosql.mapping.graph.entities.Person;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

public abstract class AbstractTraversalTest {

static final String READS = "reads";

@Inject
protected GraphTemplate graphTemplate;

@Inject
protected Graph graph;


protected Person otavio;
protected Person poliana;
protected Person paulo;

protected Book shack;
protected Book license;
protected Book effectiveJava;

protected EdgeEntity reads;
protected EdgeEntity reads2;
protected EdgeEntity reads3;

@BeforeEach
public void setUp() {

graph.traversal().V().toList().forEach(Vertex::remove);
graph.traversal().E().toList().forEach(Edge::remove);

otavio = graphTemplate.insert(Person.builder().withAge(27)
.withName("Otavio").build());
poliana = graphTemplate.insert(Person.builder().withAge(26)
.withName("Poliana").build());
paulo = graphTemplate.insert(Person.builder().withAge(50)
.withName("Paulo").build());

shack = graphTemplate.insert(Book.builder().withAge(2007).withName("The Shack").build());
license = graphTemplate.insert(Book.builder().withAge(2013).withName("Software License").build());
effectiveJava = graphTemplate.insert(Book.builder().withAge(2001).withName("Effective Java").build());


reads = graphTemplate.edge(otavio, READS, effectiveJava);
reads2 = graphTemplate.edge(poliana, READS, shack);
reads3 = graphTemplate.edge(paulo, READS, license);

reads.add("motivation", "hobby");
reads.add("language", "Java");
reads2.add("motivation", "love");
reads3.add("motivation", "job");
}

@AfterEach
public void after() {
graphTemplate.delete(otavio.getId());
graphTemplate.delete(poliana.getId());
graphTemplate.delete(paulo.getId());

graphTemplate.deleteEdge(shack.getId());
graphTemplate.deleteEdge(license.getId());
graphTemplate.deleteEdge(effectiveJava.getId());

reads.delete();
reads2.delete();
reads3.delete();

graph.traversal().V().toList().forEach(Vertex::remove);
graph.traversal().E().toList().forEach(Edge::remove);
}
}
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2022 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*/
package org.eclipse.jnosql.mapping.graph;

import jakarta.inject.Inject;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Transaction;
import org.apache.tinkerpop.gremlin.structure.Transaction.Status;
import org.eclipse.jnosql.mapping.core.Converters;
import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension;
import org.eclipse.jnosql.mapping.graph.entities.Book;
import org.eclipse.jnosql.mapping.graph.entities.BookTemplate;
import org.eclipse.jnosql.mapping.graph.spi.GraphExtension;
import org.eclipse.jnosql.mapping.reflection.Reflections;
import org.eclipse.jnosql.mapping.semistructured.EntityConverter;
import org.jboss.weld.junit5.auto.AddExtensions;
import org.jboss.weld.junit5.auto.AddPackages;
import org.jboss.weld.junit5.auto.EnableAutoWeld;
import org.junit.jupiter.api.Test;

import java.util.concurrent.atomic.AtomicReference;

import static org.apache.tinkerpop.gremlin.structure.Transaction.Status.COMMIT;
import static org.apache.tinkerpop.gremlin.structure.Transaction.Status.ROLLBACK;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

@EnableAutoWeld
@AddPackages(value = {Converters.class, EntityConverter.class, GraphTemplate.class})
@AddPackages(GraphProducer.class)
@AddPackages(Reflections.class)
@AddExtensions({EntityMetadataExtension.class, GraphExtension.class})
class BookTemplateTest {

@Inject
private BookTemplate template;

@Inject
private Graph graph;

@Test
void shouldSaveWithTransaction() {
AtomicReference<Status> status = new AtomicReference<>();

Book book = Book.builder().withName("The Book").build();
Transaction transaction = graph.tx();
transaction.addTransactionListener(status::set);
template.insert(book);
assertFalse(transaction.isOpen());
assertEquals(COMMIT, status.get());
}

@Test
void shouldSaveWithRollback() {
AtomicReference<Status> status = new AtomicReference<>();

Book book = Book.builder().withName("The Book").build();
Transaction transaction = graph.tx();
transaction.addTransactionListener(status::set);
try {
template.insertException(book);
assert false;
}catch (Exception ignored){

}

assertFalse(transaction.isOpen());
assertEquals(ROLLBACK, status.get());
}

@Test
void shouldUseAutomaticNormalTransaction() {
AtomicReference<Status> status = new AtomicReference<>();

Book book = Book.builder().withName("The Book").build();
Transaction transaction = graph.tx();
transaction.addTransactionListener(status::set);
assertNull(status.get());
template.normalInsertion(book);
assertEquals(COMMIT, status.get());
assertFalse(transaction.isOpen());
}
}

0 comments on commit 7160b05

Please sign in to comment.