/* * Copyright 2013-2016 EMC Corporation. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * or in the "license" file accompanying this file. This file 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 com.emc.ecs.sync; import com.emc.ecs.sync.config.SyncConfig; import com.emc.ecs.sync.config.SyncOptions; import com.emc.ecs.sync.config.storage.TestConfig; import com.emc.ecs.sync.model.SyncObject; import com.emc.ecs.sync.service.DbService; import com.emc.ecs.sync.service.SqliteDbService; import com.emc.ecs.sync.storage.TestStorage; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; public class IterationTest { private static final Logger log = LoggerFactory.getLogger(IterationTest.class); private static Random random = new Random(); @Test public void testModify() throws Exception { TestConfig testConfig = new TestConfig().withObjectCount(100).withMaxSize(10 * 1024).withObjectOwner("foo") .withReadData(false).withDiscardData(false); EcsSync sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withSource(testConfig).withTarget(testConfig)); sync.run(); Assert.assertEquals(0, sync.getStats().getObjectsFailed()); Assert.assertEquals(sync.getEstimatedTotalObjects(), sync.getStats().getObjectsComplete()); long initialTime = System.currentTimeMillis(); TestStorage source = (TestStorage) sync.getSource(); modify(source, source.getRootObjects(), 25, (int) sync.getEstimatedTotalObjects()); Assert.assertEquals(25, countModified(source, source.getRootObjects(), initialTime)); } private int countModified(TestStorage storage, Collection<? extends SyncObject> objects, long sinceTime) { int modified = 0; for (SyncObject object : objects) { if (object.getMetadata().getModificationTime().getTime() > sinceTime) { modified++; log.info("{} is modified", object.getRelativePath()); } if (object.getMetadata().isDirectory()) modified += countModified(storage, storage.getChildren(storage.getIdentifier(object.getRelativePath(), true)), sinceTime); } return modified; } @Test public void testSkipProcessed() throws Exception { TestConfig testConfig = new TestConfig().withObjectCount(100).withMaxSize(10 * 1024).withObjectOwner("foo") .withDiscardData(false).withReadData(true); DbService dbService = new SqliteDbService(":memory:"); SyncOptions options = new SyncOptions().withThreadCount(Runtime.getRuntime().availableProcessors() * 2); // test sync-only EcsSync sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withSource(testConfig).withTarget(testConfig).withOptions(options)); sync.setDbService(dbService); sync.run(); Assert.assertEquals(sync.getEstimatedTotalObjects(), sync.getStats().getObjectsComplete()); Assert.assertEquals(sync.getEstimatedTotalBytes(), sync.getStats().getBytesComplete()); Assert.assertEquals(0, sync.getStats().getObjectsFailed()); long totalObjects = sync.getEstimatedTotalObjects(), totalBytes = sync.getEstimatedTotalBytes(); TestStorage source = (TestStorage) sync.getSource(); TestStorage target = new TestStorage(); target.setConfig(new TestConfig().withReadData(true).withDiscardData(false)); target.ingest(source, null); // test re-run sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withOptions(options)); sync.setSource(source); sync.setTarget(target); sync.setDbService(dbService); sync.run(); // none should be reprocessed Assert.assertEquals(0, sync.getStats().getObjectsComplete()); Assert.assertEquals(0, sync.getStats().getBytesComplete()); Assert.assertEquals(0, sync.getStats().getObjectsFailed()); // test verify from sync options.setVerify(true); sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withOptions(options)); sync.setSource(source); sync.setTarget(target); sync.setDbService(dbService); sync.run(); options.setVerify(false); // revert run-specific options // all should be reprocessed Assert.assertEquals(totalObjects, sync.getStats().getObjectsComplete()); Assert.assertEquals(totalBytes, sync.getStats().getBytesComplete()); Assert.assertEquals(0, sync.getStats().getObjectsFailed()); // test verify-only after verify options.setVerifyOnly(true); sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withOptions(options)); sync.setSource(source); sync.setTarget(target); sync.setDbService(dbService); sync.run(); options.setVerifyOnly(false); // revert run-specific options // none should be reprocessed Assert.assertEquals(0, sync.getStats().getObjectsComplete()); Assert.assertEquals(0, sync.getStats().getBytesComplete()); Assert.assertEquals(0, sync.getStats().getObjectsFailed()); } @Test public void testModifiedOnly() throws Exception { TestConfig testConfig = new TestConfig().withObjectCount(100).withMaxSize(10 * 1024).withObjectOwner("foo") .withDiscardData(false).withReadData(true); DbService dbService = new SqliteDbService(":memory:"); SyncOptions options = new SyncOptions().withThreadCount(Runtime.getRuntime().availableProcessors() * 2); // test sync-only EcsSync sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withSource(testConfig).withTarget(testConfig).withOptions(options)); sync.setDbService(dbService); sync.run(); Assert.assertEquals(sync.getEstimatedTotalObjects(), sync.getStats().getObjectsComplete()); Assert.assertEquals(sync.getEstimatedTotalBytes(), sync.getStats().getBytesComplete()); Assert.assertEquals(0, sync.getStats().getObjectsFailed()); long totalObjects = sync.getEstimatedTotalObjects(), totalBytes = sync.getEstimatedTotalBytes(); TestStorage source = (TestStorage) sync.getSource(); // make sure mtime is aged Thread.sleep(1000); modify(source, source.getRootObjects(), 25, (int) totalObjects); // 2nd sync with modifications sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withTarget(testConfig).withOptions(options)); sync.setSource(source); sync.setDbService(dbService); sync.run(); // only modified should be reprocessed Assert.assertEquals(25, sync.getStats().getObjectsComplete()); Assert.assertTrue(sync.getStats().getBytesComplete() > 0); Assert.assertEquals(0, sync.getStats().getObjectsFailed()); TestStorage target = new TestStorage(); target.setConfig(new TestConfig().withReadData(true).withDiscardData(false)); target.ingest(source, null); // test verify from sync options.setVerify(true); sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withOptions(options)); sync.setSource(source); sync.setTarget(target); sync.setDbService(dbService); sync.run(); options.setVerify(false); // revert run-specific options // all should be reprocessed Assert.assertEquals(totalObjects, sync.getStats().getObjectsComplete()); Assert.assertEquals(totalBytes, sync.getStats().getBytesComplete()); Assert.assertEquals(0, sync.getStats().getObjectsFailed()); // make sure mtime is aged Thread.sleep(500); // test verify-only after verify // this is a strange test since verify-only would likely fail for any objects that have // been updated in the source, but they will happily succeed here since no data was changed modify(source, source.getRootObjects(), 25, (int) totalObjects); options.setVerifyOnly(true); sync = new EcsSync(); sync.setSyncConfig(new SyncConfig().withOptions(options)); sync.setSource(source); sync.setTarget(target); sync.setDbService(dbService); sync.run(); options.setVerifyOnly(false); // revert run-specific options // only modified should be reprocessed Assert.assertEquals(0, sync.getStats().getObjectsFailed()); Assert.assertEquals(25, sync.getStats().getObjectsComplete()); Assert.assertTrue(sync.getStats().getBytesComplete() > 0); } private void modify(TestStorage storage, List<? extends SyncObject> objects, int toModify, int totalCount) throws InterruptedException { Thread.sleep(100); Set<Integer> modifiedIndexes = new HashSet<>(); List<String> modified = new ArrayList<>(); for (int i = 0; i < toModify; i++) { int index = random.nextInt(totalCount); while (modifiedIndexes.contains(index)) index = random.nextInt(totalCount); modifiedIndexes.add(index); log.info("modifying index {}", index); modifyAtCrawlIndex(storage, objects, new AtomicInteger(index), modified); } Collections.sort(modified); for (String path : modified) { log.info("modified {}", path); } } private void modifyAtCrawlIndex(TestStorage storage, Collection<? extends SyncObject> objects, AtomicInteger crawlIndex, List<String> modified) { for (SyncObject object : objects) { if (crawlIndex.decrementAndGet() == 0) { object.getMetadata().setModificationTime(new Date()); modified.add(object.getRelativePath()); return; } if (object.getMetadata().isDirectory()) modifyAtCrawlIndex(storage, storage.getChildren(storage.getIdentifier(object.getRelativePath(), true)), crawlIndex, modified); } } }