From 188353d39b600c17cd5a1921607a7968ef33e45a Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Tue, 22 Dec 2015 20:45:42 -0500 Subject: [PATCH] Provide an API for during runtime tests. [ADDED] masterpassword-tests provides an API for performing runtime tests of whether the master password algorithm performs as it should on the current platform. --- .../Java/masterpassword-algorithm/pom.xml | 12 --- .../lyndir/masterpassword/MasterKeyTest.java | 88 ----------------- .../Java/masterpassword-tests/pom.xml | 43 +++++++++ .../lyndir/masterpassword/MPTestSuite.java | 82 ++++++++++++++++ .../com/lyndir/masterpassword/MPTests.java} | 17 +++- .../src/main}/resources/mpw_tests.xml | 0 .../lyndir/masterpassword/MasterKeyTest.java | 96 +++++++++++++++++++ .../src/test/resources/logback.xml | 0 MasterPassword/Java/pom.xml | 1 + 9 files changed, 235 insertions(+), 104 deletions(-) delete mode 100644 MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java create mode 100644 MasterPassword/Java/masterpassword-tests/pom.xml create mode 100644 MasterPassword/Java/masterpassword-tests/src/main/java/com/lyndir/masterpassword/MPTestSuite.java rename MasterPassword/Java/{masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MPWTests.java => masterpassword-tests/src/main/java/com/lyndir/masterpassword/MPTests.java} (92%) rename MasterPassword/Java/{masterpassword-algorithm/src/test => masterpassword-tests/src/main}/resources/mpw_tests.xml (100%) create mode 100644 MasterPassword/Java/masterpassword-tests/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java rename MasterPassword/Java/{masterpassword-algorithm => masterpassword-tests}/src/test/resources/logback.xml (100%) diff --git a/MasterPassword/Java/masterpassword-algorithm/pom.xml b/MasterPassword/Java/masterpassword-algorithm/pom.xml index e3fcec4a..daee227c 100644 --- a/MasterPassword/Java/masterpassword-algorithm/pom.xml +++ b/MasterPassword/Java/masterpassword-algorithm/pom.xml @@ -39,18 +39,6 @@ 1.4.0 - - - org.testng - testng - test - - - ch.qos.logback - logback-classic - test - - diff --git a/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java b/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java deleted file mode 100644 index 55978452..00000000 --- a/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.lyndir.masterpassword; - -import static org.testng.Assert.*; - -import com.google.common.io.Resources; -import com.lyndir.lhunath.opal.system.CodeUtils; -import com.lyndir.lhunath.opal.system.logging.Logger; -import com.lyndir.lhunath.opal.system.util.StringUtils; -import java.net.URL; -import javax.xml.bind.JAXBContext; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - - -public class MasterKeyTest { - - @SuppressWarnings("UnusedDeclaration") - private static final Logger logger = Logger.get( MasterKeyTest.class ); - - private MPWTests tests; - private MPWTests.Case defaultCase; - - @BeforeMethod - public void setUp() - throws Exception { - - URL testCasesResource = Resources.getResource( "mpw_tests.xml" ); - tests = (MPWTests) JAXBContext.newInstance( MPWTests.class ).createUnmarshaller().unmarshal( testCasesResource ); - for (MPWTests.Case testCase : tests.getCases()) - testCase.initializeParentHierarchy( tests ); - defaultCase = tests.getCase( MPWTests.ID_DEFAULT ); - } - - @Test - public void testEncode() - throws Exception { - - for (MPWTests.Case testCase : tests.getCases()) { - if (testCase.getResult().isEmpty()) - continue; - - logger.inf( "Running test case: %s [testEncode]", testCase.getIdentifier() ); - MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() ); - assertEquals( - masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(), testCase.getSiteVariant(), - testCase.getSiteContext() ), testCase.getResult(), "Failed test case: " + testCase ); - logger.inf( "passed!" ); - } - } - - @Test - public void testGetUserName() - throws Exception { - - assertEquals( MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() ).getFullName(), - defaultCase.getFullName() ); - } - - @Test - public void testGetKeyID() - throws Exception { - - for (MPWTests.Case testCase : tests.getCases()) { - if (testCase.getResult().isEmpty()) - continue; - - logger.inf( "Running test case: %s [testGetKeyID]", testCase.getIdentifier() ); - MasterKey masterKey = MasterKey.create( testCase.getFullName(), testCase.getMasterPassword() ); - assertEquals( CodeUtils.encodeHex( masterKey.getKeyID() ), testCase.getKeyID(), "Failed test case: " + testCase ); - logger.inf( "passed!" ); - } - } - - @Test - public void testInvalidate() - throws Exception { - - try { - MasterKey masterKey = MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() ); - masterKey.invalidate(); - masterKey.encode( defaultCase.getSiteName(), defaultCase.getSiteType(), defaultCase.getSiteCounter(), - defaultCase.getSiteVariant(), defaultCase.getSiteContext() ); - assertTrue( false, "Master key should have been invalidated, but was still usable." ); - } - catch (IllegalStateException ignored) { - } - } -} diff --git a/MasterPassword/Java/masterpassword-tests/pom.xml b/MasterPassword/Java/masterpassword-tests/pom.xml new file mode 100644 index 00000000..cba8d8b8 --- /dev/null +++ b/MasterPassword/Java/masterpassword-tests/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + + + com.lyndir.masterpassword + masterpassword + GIT-SNAPSHOT + + + Master Password Test Suite + The standard test suite to ensure the Master Password algorithm is operating as it should + + masterpassword-tests + jar + + + + + + + com.lyndir.masterpassword + masterpassword-algorithm + GIT-SNAPSHOT + + + + + org.testng + testng + test + + + ch.qos.logback + logback-classic + test + + + + + diff --git a/MasterPassword/Java/masterpassword-tests/src/main/java/com/lyndir/masterpassword/MPTestSuite.java b/MasterPassword/Java/masterpassword-tests/src/main/java/com/lyndir/masterpassword/MPTestSuite.java new file mode 100644 index 00000000..690195c1 --- /dev/null +++ b/MasterPassword/Java/masterpassword-tests/src/main/java/com/lyndir/masterpassword/MPTestSuite.java @@ -0,0 +1,82 @@ +package com.lyndir.masterpassword; + +import com.google.common.io.Resources; +import com.lyndir.lhunath.opal.system.logging.Logger; +import com.lyndir.lhunath.opal.system.util.NNFunctionNN; +import java.net.URL; +import javax.annotation.Nonnull; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; + + +/** + * @author lhunath, 2015-12-22 + */ +public class MPTestSuite { + + @SuppressWarnings("UnusedDeclaration") + private static final Logger logger = Logger.get( MPTestSuite.class ); + private static final String DEFAULT_RESOURCE_NAME = "mpw_tests.xml"; + + private MPTests tests; + + public MPTestSuite() + throws UnavailableException { + this( DEFAULT_RESOURCE_NAME ); + } + + public MPTestSuite(String resourceName) + throws UnavailableException { + try { + URL testCasesResource = Resources.getResource( resourceName ); + tests = (MPTests) JAXBContext.newInstance( MPTests.class ).createUnmarshaller().unmarshal( testCasesResource ); + + for (MPTests.Case testCase : tests.getCases()) + testCase.initializeParentHierarchy( tests ); + } + catch (IllegalArgumentException | JAXBException e) { + throw new UnavailableException( e ); + } + } + + public MPTests getTests() { + return tests; + } + + public boolean forEach(String testName, NNFunctionNN testFunction) { + for (MPTests.Case testCase : tests.getCases()) { + if (testCase.getResult().isEmpty()) + continue; + + logger.inf( "[%s] on %s...", testName, testCase.getIdentifier() ); + if (!testFunction.apply( testCase )) { + logger.err( "[%s] on %s: FAILED!", testName, testCase.getIdentifier() ); + return false; + } + logger.inf( "[%s] on %s: passed!", testName, testCase.getIdentifier() ); + } + + return true; + } + + public boolean run() { + return forEach( "mpw", new NNFunctionNN() { + @Nonnull + @Override + public Boolean apply(@Nonnull final MPTests.Case testCase) { + MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() ); + String sitePassword = masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(), + testCase.getSiteVariant(), testCase.getSiteContext() ); + + return testCase.getResult().equals( sitePassword ); + } + } ); + } + + public static class UnavailableException extends Exception { + + public UnavailableException(final Throwable cause) { + super( cause ); + } + } +} diff --git a/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MPWTests.java b/MasterPassword/Java/masterpassword-tests/src/main/java/com/lyndir/masterpassword/MPTests.java similarity index 92% rename from MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MPWTests.java rename to MasterPassword/Java/masterpassword-tests/src/main/java/com/lyndir/masterpassword/MPTests.java index 5673bda6..151d49f7 100644 --- a/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MPWTests.java +++ b/MasterPassword/Java/masterpassword-tests/src/main/java/com/lyndir/masterpassword/MPTests.java @@ -15,12 +15,12 @@ import javax.xml.bind.annotation.*; * @author lhunath, 14-12-05 */ @XmlRootElement(name = "tests") -public class MPWTests { +public class MPTests { - public static final String ID_DEFAULT = "default"; + private static final String ID_DEFAULT = "default"; @SuppressWarnings("UnusedDeclaration") - private static final Logger logger = Logger.get( MPWTests.class ); + private static final Logger logger = Logger.get( MPTests.class ); @XmlElement(name = "case") private List cases; @@ -38,6 +38,15 @@ public class MPWTests { throw new IllegalArgumentException( "No case for identifier: " + identifier ); } + public Case getDefaultCase() { + try { + return getCase( ID_DEFAULT ); + } + catch (IllegalArgumentException e) { + throw new IllegalStateException( "Missing default case in test suite. Add a case with id: " + ID_DEFAULT, e ); + } + } + @XmlRootElement(name = "case") public static class Case { @@ -68,7 +77,7 @@ public class MPWTests { private transient Case parentCase; - public void initializeParentHierarchy(MPWTests tests) { + public void initializeParentHierarchy(MPTests tests) { if (parent != null) { parentCase = tests.getCase( parent ); diff --git a/MasterPassword/Java/masterpassword-algorithm/src/test/resources/mpw_tests.xml b/MasterPassword/Java/masterpassword-tests/src/main/resources/mpw_tests.xml similarity index 100% rename from MasterPassword/Java/masterpassword-algorithm/src/test/resources/mpw_tests.xml rename to MasterPassword/Java/masterpassword-tests/src/main/resources/mpw_tests.xml diff --git a/MasterPassword/Java/masterpassword-tests/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java b/MasterPassword/Java/masterpassword-tests/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java new file mode 100644 index 00000000..89b5bea1 --- /dev/null +++ b/MasterPassword/Java/masterpassword-tests/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java @@ -0,0 +1,96 @@ +package com.lyndir.masterpassword; + +import static org.testng.Assert.*; + +import com.google.common.io.Resources; +import com.lyndir.lhunath.opal.system.CodeUtils; +import com.lyndir.lhunath.opal.system.logging.Logger; +import com.lyndir.lhunath.opal.system.util.NNFunctionNN; +import com.lyndir.lhunath.opal.system.util.StringUtils; +import java.net.URL; +import javax.annotation.Nonnull; +import javax.xml.bind.JAXBContext; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + + +public class MasterKeyTest { + + @SuppressWarnings("UnusedDeclaration") + private static final Logger logger = Logger.get( MasterKeyTest.class ); + + private MPTestSuite testSuite; + + @BeforeMethod + public void setUp() + throws Exception { + + testSuite = new MPTestSuite(); + } + + @Test + public void testEncode() + throws Exception { + + testSuite.forEach( "testEncode", new NNFunctionNN() { + @Nonnull + @Override + public Boolean apply(@Nonnull final MPTests.Case testCase) { + MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() ); + + assertEquals( + masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(), + testCase.getSiteVariant(), testCase.getSiteContext() ), + testCase.getResult(), "[testEncode] Failed test case: " + testCase ); + + return true; + } + } ); + } + + @Test + public void testGetUserName() + throws Exception { + + MPTests.Case defaultCase = testSuite.getTests().getDefaultCase(); + + assertEquals( MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() ).getFullName(), + defaultCase.getFullName(), "[testGetUserName] Failed test case: " + defaultCase ); + } + + @Test + public void testGetKeyID() + throws Exception { + + testSuite.forEach( "testGetKeyID", new NNFunctionNN() { + @Nonnull + @Override + public Boolean apply(@Nonnull final MPTests.Case testCase) { + MasterKey masterKey = MasterKey.create( testCase.getFullName(), testCase.getMasterPassword() ); + + assertEquals( CodeUtils.encodeHex( masterKey.getKeyID() ), + testCase.getKeyID(), "[testGetKeyID] Failed test case: " + testCase ); + + return true; + } + } ); + } + + @Test + public void testInvalidate() + throws Exception { + + try { + MPTests.Case defaultCase = testSuite.getTests().getDefaultCase(); + + MasterKey masterKey = MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() ); + masterKey.invalidate(); + masterKey.encode( defaultCase.getSiteName(), defaultCase.getSiteType(), defaultCase.getSiteCounter(), + defaultCase.getSiteVariant(), defaultCase.getSiteContext() ); + + assertTrue( false, "[testInvalidate] Master key should have been invalidated, but was still usable." ); + } + catch (IllegalStateException ignored) { + } + } +} diff --git a/MasterPassword/Java/masterpassword-algorithm/src/test/resources/logback.xml b/MasterPassword/Java/masterpassword-tests/src/test/resources/logback.xml similarity index 100% rename from MasterPassword/Java/masterpassword-algorithm/src/test/resources/logback.xml rename to MasterPassword/Java/masterpassword-tests/src/test/resources/logback.xml diff --git a/MasterPassword/Java/pom.xml b/MasterPassword/Java/pom.xml index a1d99524..a4bbcf3e 100644 --- a/MasterPassword/Java/pom.xml +++ b/MasterPassword/Java/pom.xml @@ -19,6 +19,7 @@ pom + masterpassword-tests masterpassword-algorithm masterpassword-model masterpassword-cli