001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.integration.http.api;
019
020import java.io.IOException;
021import java.io.UncheckedIOException;
022import java.nio.file.Files;
023import java.util.concurrent.atomic.AtomicBoolean;
024
025import org.fcrepo.config.OcflPropsConfig;
026import org.fcrepo.persistence.ocfl.RepositoryInitializer;
027
028import org.apache.commons.io.FileUtils;
029import org.flywaydb.core.Flyway;
030import org.springframework.test.context.TestContext;
031
032import edu.wisc.library.ocfl.api.MutableOcflRepository;
033
034/**
035 * Listener that baselines the DB and OCFL repo between every test.
036 * It does not baseline on Windows due to difficulties associated with deleting and immediately recreating directories.
037 *
038 * @author pwinckles
039 */
040public class TestIsolationExecutionListener extends BaseTestExecutionListener {
041
042    @Override
043    public void afterTestMethod(final TestContext testContext) throws Exception {
044        final var ocflRepo = getBean(testContext, MutableOcflRepository.class);
045        final var ocflConfig = getBean(testContext, OcflPropsConfig.class);
046        final var flyway = getBean(testContext, Flyway.class);
047
048        flyway.clean();
049        flyway.migrate();
050
051        cleanDb(testContext);
052
053        final var hasError = new AtomicBoolean(false);
054
055        ocflRepo.listObjectIds().forEach(object -> {
056            try {
057                ocflRepo.purgeObject(object);
058            } catch (final RuntimeException e) {
059                // Recursive deletes don't behave well on Windows and it's possible for the above to error out.
060                hasError.set(true);
061            }
062        });
063
064        if (hasError.get()) {
065            // If one of the purge operations failed, attempt to nuke everything. Maybe it'll work second time round?
066            // We still need the purgeObject calls first so that objects are removed from the ocfl-java cache.
067            try (final var files = Files.list(ocflConfig.getOcflRepoRoot())) {
068                files.filter(Files::isDirectory).forEach(childDir -> {
069                    try {
070                        FileUtils.cleanDirectory(childDir.toFile());
071                    } catch (final IOException e) {
072                        throw new UncheckedIOException(e);
073                    }
074                });
075            }
076        }
077
078        final var initializer = getBean(testContext, RepositoryInitializer.class);
079        initializer.initialize();
080    }
081}