/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.usergrid.management.importer; import java.util.List; import java.util.UUID; import org.apache.usergrid.corepersistence.util.CpNamingUtils; import org.apache.usergrid.persistence.EntityManagerFactory; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.apache.usergrid.persistence.EntityManager; import org.apache.usergrid.persistence.entities.FailedImport; import org.apache.usergrid.persistence.entities.FailedImportConnection; import org.apache.usergrid.persistence.entities.FailedImportEntity; import org.apache.usergrid.persistence.entities.FileImport; import org.apache.usergrid.persistence.model.util.UUIDGenerator; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class FileImportTrackerTest { @Test public void testSuccess() throws Exception { final EntityManagerFactory emf = mock( EntityManagerFactory.class ); final EntityManager em = mock( EntityManager.class ); when( emf.getEntityManager( emf.getManagementAppId() ) ).thenReturn( em ); final UUID importFileId = UUIDGenerator.newTimeUUID(); final FileImport fileImport = new FileImport(); fileImport.setUuid( importFileId ); when( em.get( importFileId, FileImport.class ) ).thenReturn( fileImport ); final FileImportTracker fileImportTracker = new FileImportTracker( emf, fileImport, 1000 ); final long expectedCount = 100; for ( long i = 0; i < expectedCount; i++ ) { fileImportTracker.entityWritten(); } fileImportTracker.complete(); ArgumentCaptor<FileImport> savedFileImport = ArgumentCaptor.forClass( FileImport.class ); verify( em ).update( savedFileImport.capture() ); final FileImport updated = savedFileImport.getValue(); assertSame( "Same instance should be updated", fileImport, updated ); assertEquals( "Same count expected", expectedCount, updated.getImportedEntityCount() ); assertNull( updated.getErrorMessage() ); } @Test public void testBoth() throws Exception { // create mock em and emf final EntityManagerFactory emf = mock( EntityManagerFactory.class ); final EntityManager em = mock( EntityManager.class ); when( emf.getEntityManager( emf.getManagementAppId() ) ).thenReturn( em ); // create tracker and call its entityWritten() and entityFailed() methods some number of times final long expectedSuccess = 100; final int expectedFails = 10; final FileImport fileImport = new FileImport(); final UUID importFileId = UUIDGenerator.newTimeUUID(); fileImport.setUuid(importFileId); // when tracker tries to create a FailedImportEntity, give it a mock when(em.create(any(FailedImportEntity.class))).thenAnswer(new Answer<FailedImportEntity>() { @Override public FailedImportEntity answer(final InvocationOnMock invocation) throws Throwable { return (FailedImportEntity) invocation.getArguments()[0]; } }); final FileImportTracker fileImportTracker = new FileImportTracker(emf, fileImport, 1000); for (long i = 0; i < expectedSuccess; i++) { fileImportTracker.entityWritten(); } for (int i = 0; i < expectedFails; i++) { fileImportTracker.entityFailed("Failed to write entity " + i); } fileImportTracker.complete(); ArgumentCaptor<FileImport> savedFileImport = ArgumentCaptor.forClass( FileImport.class ); verify( em ).update( savedFileImport.capture() ); final FileImport updated = savedFileImport.getValue(); assertSame( "Same instance should be updated", fileImport, updated ); assertEquals( "Same count expected", expectedSuccess, updated.getImportedEntityCount() ); assertEquals( "Same fail expected", expectedFails, updated.getFailedEntityCount() ); // TODO why is error message not being set here? // assertEquals( "Correct error message", // "Failed to import some data. See the import counters and errors.", // updated.getErrorMessage() ); // TODO get the connections from the file import ArgumentCaptor<FailedImportEntity> failedEntities = ArgumentCaptor.forClass( FailedImportEntity.class ); verify( em, times( expectedFails ) ) .createConnection( same( fileImport ), eq( "errors" ), failedEntities.capture() ); // now check all our arguments final List<FailedImportEntity> args = failedEntities.getAllValues(); assertEquals( "Same number of error connections created", expectedFails, args.size() ); for ( int i = 0; i < expectedFails; i++ ) { final FailedImportEntity failedImport = args.get( i ); assertEquals( "Same message expected", "Failed to write entity " + i, failedImport.getErrorMessage() ); } } @Test public void explicitFail() throws Exception { final EntityManagerFactory emf = mock( EntityManagerFactory.class ); final EntityManager em = mock( EntityManager.class ); when( emf.getEntityManager( emf.getManagementAppId() ) ).thenReturn( em ); final UUID importFileId = UUIDGenerator.newTimeUUID(); final FileImport fileImport = new FileImport(); fileImport.setUuid( importFileId ); when( em.get( importFileId, FileImport.class ) ).thenReturn( fileImport ); final FileImportTracker fileImportTracker = new FileImportTracker( emf, fileImport, 1000 ); final long expectedCount = 100; for ( long i = 0; i < expectedCount; i++ ) { fileImportTracker.entityWritten(); } fileImportTracker.fatal( "Something bad happened" ); ArgumentCaptor<FileImport> savedFileImport = ArgumentCaptor.forClass( FileImport.class ); verify( em ).update( savedFileImport.capture() ); final FileImport updated = savedFileImport.getValue(); assertSame( "Same instance should be updated", fileImport, updated ); assertEquals( "Same count expected", expectedCount, updated.getImportedEntityCount() ); assertEquals( "Fail count is 0", 0, updated.getFailedEntityCount() ); assertEquals( "Correct expected message", "Something bad happened", updated.getErrorMessage() ); assertEquals( "Expected failed state", FileImport.State.FAILED, updated.getState() ); } @Test public void testAutoFlushSuccess() throws Exception { final EntityManagerFactory emf = mock( EntityManagerFactory.class ); final EntityManager em = mock( EntityManager.class ); when( emf.getEntityManager( emf.getManagementAppId() ) ).thenReturn( em ); final UUID importFileId = UUIDGenerator.newTimeUUID(); final FileImport fileImport = new FileImport(); fileImport.setUuid( importFileId ); when( em.get( importFileId, FileImport.class ) ).thenReturn( fileImport ); //mock up returning the FailedEntityImport instance after save is invoked. when( em.create( any( FailedImportConnection.class ) ) ).thenAnswer( new Answer<Object>() { @Override public Object answer( final InvocationOnMock invocation ) throws Throwable { return invocation.getArguments()[0]; } } ); final int expectedSuccess = 100; final int expectedFails = 100; final int expectedConnectionSuccess = 100; final int expectedConnectionFails = 100; final int expectedFlushCount = 2; final int flushSize = ( expectedFails + expectedFails + expectedConnectionSuccess + expectedConnectionFails ) / expectedFlushCount; //set this to 1/2, so that we get saved twice final FileImportTracker fileImportTracker = new FileImportTracker( emf, fileImport, flushSize ); for ( long i = 0; i < expectedSuccess; i++ ) { fileImportTracker.entityWritten(); } for ( int i = 0; i < expectedFails; i++ ) { fileImportTracker.entityFailed( "Failed to write entity " + i ); } for ( long i = 0; i < expectedConnectionSuccess; i++ ) { fileImportTracker.connectionWritten(); } for ( int i = 0; i < expectedConnectionFails; i++ ) { fileImportTracker.connectionFailed( "Failed to write connection " + i ); } fileImportTracker.complete(); ArgumentCaptor<FileImport> savedFileImport = ArgumentCaptor.forClass( FileImport.class ); verify( em, times( expectedFlushCount + 1 ) ).update( savedFileImport.capture() ); final FileImport updated = savedFileImport.getAllValues().get( 2 ); assertSame( "Same instance should be updated", fileImport, updated ); assertEquals( "Same count expected", expectedSuccess, updated.getImportedEntityCount() ); assertEquals( "Same fail expected", expectedFails, updated.getFailedEntityCount() ); assertEquals( "Same connection count expected", expectedConnectionSuccess, updated.getImportedConnectionCount() ); assertEquals( "Same connection error count expected", expectedConnectionFails, updated.getFailedConnectionCount() ); assertTrue(updated.getErrorMessage().startsWith("Failed to import") ); //TODO get the connections from the file import ArgumentCaptor<FailedImport> failedEntities = ArgumentCaptor.forClass( FailedImport.class ); verify( em, times( expectedFails + expectedConnectionFails ) ) .createConnection( same( fileImport ), eq( "errors" ), failedEntities.capture() ); //now check all our arguments final List<FailedImport> args = failedEntities.getAllValues(); assertEquals( "Same number of error connections created", expectedFails + expectedConnectionFails, args.size() ); for ( int i = 0; i < expectedFails; i++ ) { final FailedImport failedImport = args.get( i ); assertEquals( "Same message expected", "Failed to write entity " + i, failedImport.getErrorMessage() ); } for ( int i = expectedFails; i < expectedConnectionFails; i++ ) { final FailedImport failedImport = args.get( i ); assertEquals( "Same message expected", "Failed to write connection " + i, failedImport.getErrorMessage() ); } } @Test public void loadingExistingState() throws Exception { final EntityManagerFactory emf = mock( EntityManagerFactory.class ); final EntityManager em = mock( EntityManager.class ); when( emf.getEntityManager( emf.getManagementAppId() ) ).thenReturn( em ); final UUID importFileId = UUIDGenerator.newTimeUUID(); final FileImport fileImport = new FileImport(); fileImport.setUuid( importFileId ); fileImport.setImportedEntityCount( 1 ); fileImport.setFailedEntityCount( 2 ); fileImport.setImportedConnectionCount( 3 ); fileImport.setFailedConnectionCount( 4 ); when( em.get( importFileId, FileImport.class ) ).thenReturn( fileImport ); //mock up returning the FailedEntityImport instance after save is invoked. FileImportTracker statistics = new FileImportTracker( emf, fileImport, 100 ); assertEquals( 1, statistics.getEntitiesWritten() ); assertEquals( 2, statistics.getEntitiesFailed() ); assertEquals( 3, statistics.getTotalEntityCount() ); assertEquals( 3, statistics.getConnectionsWritten() ); assertEquals( 4, statistics.getConnectionsFailed() ); assertEquals( 7, statistics.getTotalConnectionCount() ); } @Test public void failFast() throws Exception { final EntityManagerFactory emf = mock( EntityManagerFactory.class ); final EntityManager em = mock( EntityManager.class ); when( emf.getEntityManager( emf.getManagementAppId() ) ).thenReturn( em ); final UUID importFileId = UUIDGenerator.newTimeUUID(); final FileImport fileImport = new FileImport(); when( em.get( importFileId, FileImport.class ) ).thenReturn( fileImport ); //mock up returning the FailedEntityImport instance after save is invoked. FileImportTracker statistics = new FileImportTracker( emf, fileImport, 100 ); assertFalse( statistics.shouldStopProcessingEntities() ); assertFalse( statistics.shouldStopProcessingConnections() ); statistics.entityFailed( "test fail" ); assertTrue("We shouldn't process after a failure", statistics.shouldStopProcessingEntities()); statistics.connectionFailed( "test fail" ); assertTrue( "We shouldn't process after a failure", statistics.shouldStopProcessingConnections() ); } }