aafc05307f46f30779f854917e8452a045740326
[aai/champ.git] / champ-lib / champ-titan / src / test / java / org / onap / aai / champtitan / core / ChampTransactionTest.java
1 /**
2  * ============LICENSE_START==========================================
3  * org.onap.aai
4  * ===================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017 Amdocs
7  * ===================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *        http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END============================================
20  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  */
22 package org.onap.aai.champtitan.core;
23
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27
28 import java.util.Optional;
29 import java.util.concurrent.CountDownLatch;
30
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.onap.aai.champcore.ChampTransaction;
34 import org.onap.aai.champcore.exceptions.ChampMarshallingException;
35 import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
36 import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
37 import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
38 import org.onap.aai.champcore.exceptions.ChampTransactionException;
39 import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
40 import org.onap.aai.champcore.model.ChampObject;
41 import org.onap.aai.champcore.model.ChampRelationship;
42 import org.onap.aai.champtitan.graph.impl.TitanChampGraphImpl;
43
44 public class ChampTransactionTest {
45
46   public TitanChampGraphImpl graph = null;
47   public CountDownLatch latch = new CountDownLatch(2);
48   public ChampObject[] storedVertices = new ChampObject[2];
49
50   
51   @Before
52   public void setup() {
53     graph = new TitanChampGraphImpl.Builder("TransactionTestGraph")
54       .property("storage.backend", "inmemory")
55       .build();
56   }
57   
58   
59   /**
60    * This test validates that multiple CRUD operations can be performed against vertices within
61    * the same transactional context and that, once the transaction is committed, the final 
62    * state of the vertices reflects the sum of all of the operations performed within the
63    * transaction.
64    * 
65    * @throws ChampMarshallingException
66    * @throws ChampSchemaViolationException
67    * @throws ChampObjectNotExistsException
68    * @throws ChampUnmarshallingException
69    * @throws ChampTransactionException 
70    */
71   @Test
72   public void champObjectSingleTxTest() throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampUnmarshallingException, ChampTransactionException {
73
74     ChampObject v1 = ChampObject.create()
75         .ofType("foo")
76         .withoutKey()
77         .withProperty("property1", "value1")
78         .withProperty("property2", "value2")
79         .build();
80     
81     ChampObject v2 = ChampObject.create()
82         .ofType("foo")
83         .withoutKey()
84         .withProperty("property3", "value3")
85         .withProperty("property4", "value4")
86         .build();
87     
88     ChampObject v3 = ChampObject.create()
89         .ofType("foo")
90         .withoutKey()
91         .withProperty("property5", "value5")
92         .withProperty("property6", "value6")
93         .build();
94     
95     ChampObject v4 = ChampObject.create()
96         .ofType("foo")
97         .withoutKey()
98         .withProperty("property7", "value7")
99         .withProperty("property8", "value8")
100         .build();
101     
102     
103     // Open a transaction with the graph data store.
104     ChampTransaction tx = graph.openTransaction();
105     
106       // Create all of our vertices.
107       ChampObject storedV1 = graph.storeObject(v1, Optional.of(tx));
108       ChampObject storedV2 = graph.storeObject(v2, Optional.of(tx));
109       ChampObject storedV3 = graph.storeObject(v3, Optional.of(tx));
110       ChampObject storedV4 = graph.storeObject(v4, Optional.of(tx));
111     
112       // Now, within the same transactional context, do a replacement against one of the 
113       // vertices that we just created.
114       ChampObject replacedV2 = graph.replaceObject(ChampObject.create()
115                                                        .ofType("foo")
116                                                        .withKey(storedV2.getKey().get())
117                                                        .withProperty("replacedProperty3", "replacedValue3")
118                                                        .withProperty("replacedProperty4", "replacedValue4")
119                                                        .build(), 
120                                                    Optional.of(tx));
121       
122       // Within the same transactional context, do an update against one of the vertices
123       // that we just created.
124       final ChampObject updatedV3 = graph.storeObject(ChampObject.create()
125                                                         .from(storedV3)
126                                                         .withKey(storedV3.getKey().get())
127                                                         .withProperty("updatedProperty", "updatedValue")
128                                                         .build(), Optional.of(tx));
129       
130       // Within the same transactional context, delete one of the vertices that we just
131       // created.
132       graph.deleteObject(storedV4.getKey().get(), Optional.of(tx));
133       
134     // Finally, commit our transaction.
135     tx.commit();
136     
137     tx = graph.openTransaction();
138     
139       Optional<ChampObject> retrievedV1 = graph.retrieveObject(storedV1.getKey().get(), Optional.of(tx));
140       assertTrue(retrievedV1.isPresent());
141       assertTrue(retrievedV1.get().getProperty("property1").get().equals("value1"));
142       assertTrue(retrievedV1.get().getProperty("property2").get().equals("value2"));
143
144       
145       Optional<ChampObject> retrievedV2 = graph.retrieveObject(storedV2.getKey().get(), Optional.of(tx));
146       assertTrue(retrievedV2.isPresent());
147       assertTrue(retrievedV2.get().getProperty("replacedProperty3").get().equals("replacedValue3"));
148       assertTrue(retrievedV2.get().getProperty("replacedProperty4").get().equals("replacedValue4"));
149       assertFalse(retrievedV2.get().getProperty("value3").isPresent());
150       assertFalse(retrievedV2.get().getProperty("value4").isPresent());
151       
152       Optional<ChampObject> retrievedV3 = graph.retrieveObject(storedV3.getKey().get(), Optional.of(tx));
153       assertTrue(retrievedV3.isPresent());
154       assertTrue(retrievedV3.get().getProperty("property5").get().equals("value5"));
155       assertTrue(retrievedV3.get().getProperty("property6").get().equals("value6"));
156       assertTrue(retrievedV3.get().getProperty("updatedProperty").get().equals("updatedValue"));
157
158       
159       Optional<ChampObject> retrievedV4 = graph.retrieveObject(storedV4.getKey().get(), Optional.of(tx));
160       assertFalse("Deleted vertex should not be present in graph", retrievedV4.isPresent());
161       
162     tx.commit();
163   }
164   
165
166   /**
167    * This test validates that multiple threads can each open their own transactions with the 
168    * graph data store, and that there is no leakage between each thread's transactions.
169    * 
170    * @throws ChampMarshallingException
171    * @throws ChampSchemaViolationException
172    * @throws ChampObjectNotExistsException
173    * @throws ChampUnmarshallingException
174    * @throws ChampTransactionException 
175    */
176   @Test
177   public void multipleTransactionTest() throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampUnmarshallingException, ChampTransactionException {
178     
179     ChampObject v1 = ChampObject.create()
180         .ofType("foo")
181         .withoutKey()
182         .withProperty("property1", "value1")
183         .withProperty("property2", "value2")
184         .build();
185     
186     ChampObject v2 = ChampObject.create()
187         .ofType("bar")
188         .withoutKey()
189         .withProperty("property3", "value3")
190         .withProperty("property4", "value4")
191         .build();
192        
193     // Instantiate and start our two transactional worker threads...
194     Thread thread1 = new Thread(new VertexWriter(v1, 0));
195     Thread thread2 = new Thread(new VertexWriter(v2, 1));
196     thread1.start();
197     thread2.start();
198     
199     // and wait for the threads to complete.
200     try {
201       thread1.join();
202       thread2.join();
203       
204     } catch (InterruptedException e) { }
205         
206     // Now that all of our data has been committed, let's open a new transaction
207     // and verify that all of our vertices can be retrieved.
208     ChampTransaction tx3 = graph.openTransaction();
209
210     Optional<ChampObject> retrievedV1 = graph.retrieveObject(storedVertices[0].getKey().get(), Optional.of(tx3));
211     assertTrue(retrievedV1.isPresent());
212     Optional<ChampObject> retrievedV2 = graph.retrieveObject(storedVertices[1].getKey().get(), Optional.of(tx3));
213     assertTrue(retrievedV2.isPresent());
214     
215     tx3.commit();
216   }
217
218   
219   /**
220    * This method validates that edges can be successfully created within a single transaction.
221    * 
222    * @throws ChampMarshallingException
223    * @throws ChampSchemaViolationException
224    * @throws ChampObjectNotExistsException
225    * @throws ChampUnmarshallingException
226    * @throws ChampRelationshipNotExistsException
227    * @throws ChampTransactionException 
228    */
229   @Test
230   public void edgeTest() throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, ChampUnmarshallingException, ChampRelationshipNotExistsException, ChampTransactionException {
231     
232     // Create the source and target vertices for our edge.
233     final ChampObject source = ChampObject.create()
234         .ofType("foo")
235         .withoutKey()
236         .withProperty("property1", "value1")
237         .build();
238
239     final ChampObject target = ChampObject.create()
240         .ofType("foo")
241         .withoutKey()
242         .build();
243
244     // Open a transaction with the graph data store.
245     ChampTransaction tx = graph.openTransaction();
246     
247       // Now, create our vertices.
248       ChampObject storedSource = graph.storeObject(source, Optional.of(tx));
249       ChampObject storedTarget = graph.storeObject(target, Optional.of(tx));
250       
251       // Create the edge between the vertices.
252       ChampRelationship relationship = new ChampRelationship.Builder(storedSource, storedTarget, "relationship")
253           .property("property-1", "value-1")
254           .property("property-2", 3)
255           .build();
256       ChampRelationship storedRelationship = graph.storeRelationship(relationship, Optional.of(tx));
257       
258       // Validate that we can read back the edge within the transactional context.
259       Optional<ChampRelationship> retrievedRelationship = graph.retrieveRelationship(storedRelationship.getKey().get(), Optional.of(tx));
260       assertTrue("Failed to retrieve stored relationship", retrievedRelationship.isPresent());
261       
262     // Commit our transaction.
263     graph.commitTransaction(tx);
264     
265     // Now, open a new transaction.
266     tx = graph.openTransaction();
267     
268       // Now, read back the edge that we just created again, validating that it was
269       // successfully committed to the graph.
270       retrievedRelationship = graph.retrieveRelationship(storedRelationship.getKey().get(), Optional.of(tx));
271       assertTrue("Failed to retrieve stored relationship", retrievedRelationship.isPresent());
272
273     graph.commitTransaction(tx);
274   }
275   
276   private class VertexWriter implements Runnable {
277     
278     ChampObject vertex;
279     int         index;
280     
281     public VertexWriter(ChampObject vertex, int index) {
282       this.vertex = vertex;
283       this.index  = index;
284     }
285     
286     public void run() {
287       
288       ChampTransaction tx=null;
289       try {
290         
291         // Open a threaded transaction to do some work in.
292         tx = graph.openTransaction();
293         
294         // Now store one of our two vertices within the context of this transaction.
295         storedVertices[index] = graph.storeObject(vertex, Optional.of(tx));
296         
297         // Use our latch to indicate that we are done creating vertices, and wait for
298         // the other thread to do the same.          
299         latch.countDown();
300         latch.await();
301         
302         // Validate that the vertex we created is visible to us in the graph, but the
303         // one that the other thread created is not.          
304         Optional<ChampObject> retrievedV2 = graph.retrieveObject(storedVertices[index].getKey().get(), Optional.of(tx));
305         assertTrue(retrievedV2.isPresent());
306         Optional<ChampObject> retrievedV1 = graph.retrieveObject(storedVertices[(index+1)%2].getKey().get(), Optional.of(tx));
307         assertFalse(retrievedV1.isPresent());
308                 
309       } catch (InterruptedException | 
310                ChampUnmarshallingException | 
311                ChampMarshallingException | 
312                ChampSchemaViolationException | 
313                ChampObjectNotExistsException | ChampTransactionException e) {
314         
315         fail("Thread failed to interact with graph due to " + e.getMessage());
316       
317       } finally {
318         
319         try {
320           Thread.sleep(index * 500);
321         } catch (InterruptedException e) {
322           // TODO Auto-generated catch block
323           e.printStackTrace();
324         }
325         // Now, commit our transaction and bail...          
326         try {
327           graph.commitTransaction(tx);
328         } catch (ChampTransactionException e) {
329
330         }
331       }
332     }
333   };
334 }
335