2
0

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.
This commit is contained in:
Maarten Billemont 2015-12-22 20:45:42 -05:00
parent acdb96cb6f
commit 188353d39b
9 changed files with 235 additions and 104 deletions

View File

@ -39,18 +39,6 @@
<version>1.4.0</version> <version>1.4.0</version>
</dependency> </dependency>
<!-- TESTING -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -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) {
}
}
}

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password Test Suite</name>
<description>The standard test suite to ensure the Master Password algorithm is operating as it should</description>
<artifactId>masterpassword-tests</artifactId>
<packaging>jar</packaging>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<!-- TESTING -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -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<MPTests.Case, Boolean> 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<MPTests.Case, Boolean>() {
@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 );
}
}
}

View File

@ -15,12 +15,12 @@ import javax.xml.bind.annotation.*;
* @author lhunath, 14-12-05 * @author lhunath, 14-12-05
*/ */
@XmlRootElement(name = "tests") @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") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPWTests.class ); private static final Logger logger = Logger.get( MPTests.class );
@XmlElement(name = "case") @XmlElement(name = "case")
private List<Case> cases; private List<Case> cases;
@ -38,6 +38,15 @@ public class MPWTests {
throw new IllegalArgumentException( "No case for identifier: " + identifier ); 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") @XmlRootElement(name = "case")
public static class Case { public static class Case {
@ -68,7 +77,7 @@ public class MPWTests {
private transient Case parentCase; private transient Case parentCase;
public void initializeParentHierarchy(MPWTests tests) { public void initializeParentHierarchy(MPTests tests) {
if (parent != null) { if (parent != null) {
parentCase = tests.getCase( parent ); parentCase = tests.getCase( parent );

View File

@ -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<MPTests.Case, Boolean>() {
@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<MPTests.Case, Boolean>() {
@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) {
}
}
}

View File

@ -19,6 +19,7 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>masterpassword-tests</module>
<module>masterpassword-algorithm</module> <module>masterpassword-algorithm</module>
<module>masterpassword-model</module> <module>masterpassword-model</module>
<module>masterpassword-cli</module> <module>masterpassword-cli</module>