001/*
002 * #%L
003 * Netarchivesuite - common - test
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023package dk.netarkivet.testutils.preconfigured;
024
025import java.security.Permission;
026
027import dk.netarkivet.common.exceptions.UnknownID;
028
029/**
030 * Configures the test environment to block calls to System.exit(), throwing a PermissionDenied instead.
031 */
032public class PreventSystemExit implements TestConfigurationIF {
033    /** Saves the original security manager, so that it can be restored in tearDown() */
034    private SecurityManager originalManager;
035    /** Saves latest value given to System.exit() for inspection */
036    int exitValue;
037    /** Indicates whether System.exit() has been called after setUp(). */
038    boolean exitCalled = false;
039
040    /**
041     * Stores original SecurityManager and set a new one blocking System.exit() Calls reset().
042     */
043    public void setUp() {
044        originalManager = System.getSecurityManager();
045        SecurityManager manager = new DisallowSystemExitSecurityManager();
046        System.setSecurityManager(manager);
047    }
048
049    /**
050     * Resets internal state.
051     */
052    public void reset() {
053        exitCalled = false;
054    }
055
056    /**
057     * Restores original SecurityManager.
058     */
059    public void tearDown() {
060        System.setSecurityManager(originalManager);
061    }
062
063    /**
064     * Checks whether System.exit() has been called after reset().
065     *
066     * @return true if and only if System.exit() has been called after reset().
067     */
068    public boolean getExitCalled() {
069        return exitCalled;
070    }
071
072    /**
073     * Looks up the value given to the latest invocation of System.exit()
074     *
075     * @return The int value. Throws UnknownID if System.exit() has not been called after reset().
076     */
077    public int getExitValue() {
078        if (!exitCalled) {
079            throw new UnknownID("System.exit() was never called");
080        }
081        return exitValue;
082    }
083
084    /**
085     * A SecurityManager that makes System.exit() throw PermissionDenied. Also stores the value given to System.exit()
086     * for subsequent inspection.
087     */
088    private class DisallowSystemExitSecurityManager extends SecurityManager {
089        public void checkExit(int status) {
090            exitValue = status;
091            exitCalled = true;
092            super.checkExit(status);
093        }
094
095        public void checkPermission(Permission perm) {
096            if (perm.getName().startsWith("exitVM")) { // represents exitVM, exitVM.*
097                throw new SecurityException("System.exit() disallowed during this unit test.");
098            }
099
100        }
101    }
102}