http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/signature/BuiltinSignaturesTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/signature/BuiltinSignaturesTest.java b/sshd-common/src/test/java/org/apache/sshd/common/signature/BuiltinSignaturesTest.java new file mode 100644 index 0000000..0ea58f7 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/signature/BuiltinSignaturesTest.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.signature; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +import org.apache.sshd.common.NamedResource; +import org.apache.sshd.common.signature.BuiltinSignatures.ParseResult; +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class BuiltinSignaturesTest extends JUnitTestSupport { + public BuiltinSignaturesTest() { + super(); + } + + @Test + public void testFromName() { + for (BuiltinSignatures expected : BuiltinSignatures.VALUES) { + String name = expected.getName(); + BuiltinSignatures actual = BuiltinSignatures.fromFactoryName(name); + assertSame(name, expected, actual); + } + } + + @Test + public void testParseSignaturesList() { + List<String> builtin = NamedResource.getNameList(BuiltinSignatures.VALUES); + List<String> unknown = Arrays.asList(getClass().getPackage().getName(), getClass().getSimpleName(), getCurrentTestName()); + Random rnd = new Random(); + for (int index = 0; index < (builtin.size() + unknown.size()); index++) { + Collections.shuffle(builtin, rnd); + Collections.shuffle(unknown, rnd); + + List<String> weavedList = new ArrayList<>(builtin.size() + unknown.size()); + for (int bIndex = 0, uIndex = 0; (bIndex < builtin.size()) || (uIndex < unknown.size());) { + boolean useBuiltin = false; + if (bIndex < builtin.size()) { + useBuiltin = uIndex >= unknown.size() || rnd.nextBoolean(); + } + + if (useBuiltin) { + weavedList.add(builtin.get(bIndex)); + bIndex++; + } else if (uIndex < unknown.size()) { + weavedList.add(unknown.get(uIndex)); + uIndex++; + } + } + + String fullList = GenericUtils.join(weavedList, ','); + ParseResult result = BuiltinSignatures.parseSignatureList(fullList); + List<String> parsed = NamedResource.getNameList(result.getParsedFactories()); + List<String> missing = result.getUnsupportedFactories(); + + // makes sure not only that the contents are the same but also the order + assertListEquals(fullList + "[parsed]", builtin, parsed); + assertListEquals(fullList + "[unsupported]", unknown, missing); + } + } + + @Test + public void testResolveFactoryOnBuiltinValues() { + for (SignatureFactory expected : BuiltinSignatures.VALUES) { + String name = expected.getName(); + SignatureFactory actual = BuiltinSignatures.resolveFactory(name); + assertSame(name, expected, actual); + } + } + + @Test + public void testNotAllowedToRegisterBuiltinFactories() { + for (SignatureFactory expected : BuiltinSignatures.VALUES) { + try { + BuiltinSignatures.registerExtension(expected); + fail("Unexpected success for " + expected.getName()); + } catch (IllegalArgumentException e) { + // expected - ignored + } + } + } + + @Test(expected = IllegalArgumentException.class) + public void testNotAllowedToOverrideRegisteredFactories() { + SignatureFactory expected = Mockito.mock(SignatureFactory.class); + Mockito.when(expected.getName()).thenReturn(getCurrentTestName()); + + String name = expected.getName(); + try { + for (int index = 1; index <= Byte.SIZE; index++) { + BuiltinSignatures.registerExtension(expected); + assertEquals("Unexpected success at attempt #" + index, 1, index); + } + } finally { + BuiltinSignatures.unregisterExtension(name); + } + } + + @Test + public void testResolveFactoryOnRegisteredExtension() { + SignatureFactory expected = Mockito.mock(SignatureFactory.class); + Mockito.when(expected.getName()).thenReturn(getCurrentTestName()); + + String name = expected.getName(); + try { + assertNull("Extension already registered", BuiltinSignatures.resolveFactory(name)); + BuiltinSignatures.registerExtension(expected); + + SignatureFactory actual = BuiltinSignatures.resolveFactory(name); + assertSame("Mismatched resolved instance", expected, actual); + } finally { + SignatureFactory actual = BuiltinSignatures.unregisterExtension(name); + assertSame("Mismatched unregistered instance", expected, actual); + assertNull("Extension not un-registered", BuiltinSignatures.resolveFactory(name)); + } + } +}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/signature/SignatureDSATest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/signature/SignatureDSATest.java b/sshd-common/src/test/java/org/apache/sshd/common/signature/SignatureDSATest.java new file mode 100644 index 0000000..d9f507d --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/signature/SignatureDSATest.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.signature; + +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.spec.DSAPublicKeySpec; + +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class SignatureDSATest extends JUnitTestSupport { + public SignatureDSATest() { + super(); + } + + @Test + public void testTooShortSignature() throws Exception { + KeyFactory kf = SecurityUtils.getKeyFactory(KeyUtils.DSS_ALGORITHM); + SignatureDSA signatureDSA = new SignatureDSA(KeyUtils.DSS_ALGORITHM) { + @Override + protected java.security.Signature doInitSignature(String algo, boolean forSigning) throws GeneralSecurityException { + return java.security.Signature.getInstance(algo); + + } + }; + + byte[] y = new byte[] { + 0, -92, 59, 5, 72, 124, 101, 124, -18, 114, 7, 100, 98, -61, 73, -104, + 120, -98, 54, 118, 17, -62, 91, -110, 29, 98, 50, -101, -41, 99, -116, + 101, 107, -123, 124, -97, 62, 119, 88, -109, -110, -1, 109, 119, -51, + 69, -98, -105, 2, -69, -121, -82, -118, 23, -6, 96, -61, -65, 102, -58, + -74, 32, -104, 116, -6, -35, -83, -10, -88, -68, 106, -112, 72, -2, 35, + 38, 15, -11, -22, 30, -114, -46, -47, -18, -17, -71, 24, -25, 28, 13, 29, + -40, 101, 18, 81, 45, -120, -67, -53, -41, 11, 50, -89, -33, 50, 54, -14, + -91, -35, 12, -42, 13, -84, -19, 100, -3, -85, -18, 74, 99, -49, 64, -49, + 51, -83, -82, -127, 116, 64 }; + byte[] p = new byte[] { + 0, -3, 127, 83, -127, 29, 117, 18, 41, 82, -33, 74, -100, 46, -20, -28, + -25, -10, 17, -73, 82, 60, -17, 68, 0, -61, 30, 63, -128, -74, 81, 38, + 105, 69, 93, 64, 34, 81, -5, 89, 61, -115, 88, -6, -65, -59, -11, -70, + 48, -10, -53, -101, 85, 108, -41, -127, 59, -128, 29, 52, 111, -14, 102, + 96, -73, 107, -103, 80, -91, -92, -97, -97, -24, 4, 123, 16, 34, -62, 79, + -69, -87, -41, -2, -73, -58, 27, -8, 59, 87, -25, -58, -88, -90, 21, 15, 4, + -5, -125, -10, -45, -59, 30, -61, 2, 53, 84, 19, 90, 22, -111, 50, -10, 117, + -13, -82, 43, 97, -41, 42, -17, -14, 34, 3, 25, -99, -47, 72, 1, -57 }; + byte[] q = new byte[] { + 0, -105, 96, 80, -113, 21, 35, 11, -52, -78, -110, -71, -126, -94, -21, + -124, 11, -16, 88, 28, -11 }; + byte[] g = new byte[] { + 0, -9, -31, -96, -123, -42, -101, 61, -34, -53, -68, -85, 92, 54, -72, 87, + -71, 121, -108, -81, -69, -6, 58, -22, -126, -7, 87, 76, 11, 61, 7, -126, + 103, 81, 89, 87, -114, -70, -44, 89, 79, -26, 113, 7, 16, -127, -128, -76, + 73, 22, 113, 35, -24, 76, 40, 22, 19, -73, -49, 9, 50, -116, -56, -90, -31, + 60, 22, 122, -117, 84, 124, -115, 40, -32, -93, -82, 30, 43, -77, -90, 117, + -111, 110, -93, 127, 11, -6, 33, 53, 98, -15, -5, 98, 122, 1, 36, 59, -52, + -92, -15, -66, -88, 81, -112, -119, -88, -125, -33, -31, 90, -27, -97, 6, + -110, -117, 102, 94, -128, 123, 85, 37, 100, 1, 76, 59, -2, -49, 73, 42 }; + + BigInteger bigY = new BigInteger(y); + BigInteger bigP = new BigInteger(p); + BigInteger bigQ = new BigInteger(q); + BigInteger bigG = new BigInteger(g); + + DSAPublicKeySpec dsaPublicKey = new DSAPublicKeySpec(bigY, bigP, bigQ, bigG); + signatureDSA.initVerifier(kf.generatePublic(dsaPublicKey)); + byte[] h = new byte[] { + -4, 111, -103, 111, 72, -106, 105, -19, 81, -123, 84, -13, -40, -53, -3, + -97, -8, 43, -22, -2, -23, -15, 28, 116, -63, 96, -79, -127, -84, 63, -6, -94 }; + signatureDSA.update(h); + + byte[] sig_of_h = new byte[] { + 0, 0, 0, 7, 115, 115, 104, 45, 100, 115, 115, 0, 0, 0, 40, 0, 79, + 84, 118, -50, 11, -117, -112, 52, -25, -78, -50, -20, 6, -69, -26, + 7, 90, -34, -124, 80, 76, -32, -23, -8, 43, 38, -48, -89, -17, -60, + -1, -78, 112, -88, 14, -39, -78, -98, -80 }; + boolean verified = signatureDSA.verify(sig_of_h); + + assertTrue(verified); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/signature/SignatureRSATest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/signature/SignatureRSATest.java b/sshd-common/src/test/java/org/apache/sshd/common/signature/SignatureRSATest.java new file mode 100644 index 0000000..5671ac3 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/signature/SignatureRSATest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.signature; + +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.Provider; +import java.security.PublicKey; +import java.security.spec.RSAPublicKeySpec; +import java.util.Base64; +import java.util.Map; + +import org.apache.sshd.common.Factory; +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class SignatureRSATest extends JUnitTestSupport { + private static final Base64.Decoder B64_DECODER = Base64.getDecoder(); + @SuppressWarnings("checkstyle:linelength") + private static final byte[] TEST_MSG = + B64_DECODER.decode("AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/q1TGV1wHNtCg9fGFGVSKs0VxKF4cfVyrSLtgLjnlXQTn+Lm7xiYKGbBbsTQWOqEDaBVBsRbAkxIkpuvr6/EBxwrtDbKmSQYTJZVJSD2bZRYjGsR9gpZXPorOOKFd5EPCMHXsqnhp2hidTGH7cK6RuLk7MNnPISsY0Nbx8/ZvikiPROGcoTZ8bzUv4IaLr3veW6epSeQem8tJqhnrpTHhbLU99zf045M0Gsnk/azjjlBM+qrHZ5FNdC1kowJnLtf2Oy/rUQNpkGJtcBPT8xvreV0wLsn9t3hSxzsc0+VkDNTQRlfU+o3M="); + @SuppressWarnings("checkstyle:linelength") + private static final byte[] TEST_SIGNATURE = + B64_DECODER.decode("AAAAB3NzaC1yc2EAAAD/+Ntnf4qfr2J1voDS6I+u3VRjtMn+LdWJsAZfkLDxRkK1rQxP7QAjLdNqpT4CkWHp8dtoTGFlBFt6NieNJCMTA2KSOxJMZKsX7e/lHkh7C+vhQvJ9eLTKWjCxSFUrcM0NvFhmwbRCffwXSHvAKak4wbmofxQMpd+G4jZkNMz5kGpmeICBcNjRLPb7oXzuGr/g4x/3ge5Qaawqrg/gcZr/sKN6SdE8SszgKYO0SB320N4gcUoShVdLYr9uwdJ+kJoobfkUK6Or171JCctP/cu2nM79lDqVnJw/2jOG8OnTc8zRDXAh0RKoR5rOU8cOHm0Ls2MATsFdnyRU5FGUxqZ+"); + private static PublicKey testKey; + + public SignatureRSATest() { + super(); + } + + @BeforeClass + public static void initializeTestKey() throws GeneralSecurityException { + byte[] exp = B64_DECODER.decode("Iw=="); + @SuppressWarnings("checkstyle:linelength") + byte[] mod = B64_DECODER.decode("AMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/q1TGV1wHNtCg9fGFGVSKs0VxKF4cfVyrSLtgLjnlXQTn+Lm7xiYKGbBbsTQWOqEDaBVBsRbAkxIkpuvr6/EBxwrtDbKmSQYTJZVJSD2bZRYjGsR9gpZXPorOOKFd5EPCMHXsqnhp2hidTGH7cK6RuLk7MNnPISsY0Nbx8/ZvikiPROGcoTZ8bzUv4IaLr3veW6epSeQem8tJqhnrpTHhbLU99zf045M0Gsnk/azjjlBM+qrHZ5FNdC1kowJnLtf2Oy/rUQNpkGJtcBPT8xvreV0wLsn9t3hSxzsc0+VkDNTQRlfU+o3M="); + KeyFactory kf = SecurityUtils.getKeyFactory(KeyUtils.RSA_ALGORITHM); + testKey = kf.generatePublic(new RSAPublicKeySpec(new BigInteger(mod), new BigInteger(exp))); + } + + @Test // see SSHD-642 + public void testLeadingZeroesBC() throws Throwable { + testLeadingZeroes(new Factory<SignatureRSA>() { + @Override + public SignatureRSA create() { + return new SignatureRSA() { + @Override + protected java.security.Signature doInitSignature(String algo, boolean forSigning) throws GeneralSecurityException { + assertFalse("Signature not initialized for verification", forSigning); + java.security.Signature signature = super.doInitSignature(algo, forSigning); + if (SecurityUtils.isBouncyCastleRegistered()) { + Provider provider = signature.getProvider(); + String name = provider.getName(); + assertEquals("Mismatched BC provider name", SecurityUtils.BOUNCY_CASTLE, name); + } + return signature; + } + }; + } + }); + } + + @Test // see SSHD-642 + public void testLeadingZeroesJCE() throws Throwable { + testLeadingZeroes(() -> new SignatureRSA() { + @Override + protected java.security.Signature doInitSignature(String algo, boolean forSigning) throws GeneralSecurityException { + assertFalse("Signature not initialized for verification", forSigning); + java.security.Signature signature = java.security.Signature.getInstance(algo); + Provider provider = signature.getProvider(); + String name = provider.getName(); + assertNotEquals("BC provider used although not required", SecurityUtils.BOUNCY_CASTLE, name); + return signature; + } + }); + } + + private void testLeadingZeroes(Factory<? extends SignatureRSA> factory) throws Exception { + SignatureRSA rsa = factory.create(); + rsa.initVerifier(testKey); + + int vSize = rsa.getVerifierSignatureSize(); + assertTrue("Verifier signature size not initialized", vSize > 0); + + // make sure padding is required + Map.Entry<String, byte[]> encoding = rsa.extractEncodedSignature(TEST_SIGNATURE); + assertNotNull("Signature is not encoded", encoding); + byte[] data = encoding.getValue(); + assertTrue("Signature data size (" + data.length + ") not below verifier size (" + vSize + ")", data.length < vSize); + + rsa.update(TEST_MSG); + assertTrue("Failed to verify", rsa.verify(TEST_SIGNATURE)); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/signature/SignaturesDevelopment.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/signature/SignaturesDevelopment.java b/sshd-common/src/test/java/org/apache/sshd/common/signature/SignaturesDevelopment.java new file mode 100644 index 0000000..2e15341 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/signature/SignaturesDevelopment.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.signature; + +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.buffer.BufferUtils; +import org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.junit.Ignore; + +/** + * A "scratch-pad" class for testing signatures related code during development + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@Ignore("Used only for development") +public class SignaturesDevelopment extends JUnitTestSupport { + public SignaturesDevelopment() { + super(); + } + + public static void testSignatureFactory( + SignatureFactory factory, KeyPair kp, byte[] data, boolean generateSignature, byte[] signature) + throws Exception { + Signature signer = factory.create(); + if (generateSignature) { + signer.initSigner(kp.getPrivate()); + signer.update(data); + signature = signer.sign(); + System.out.append('\t').append("Signature: ").println(BufferUtils.toHex(':', signature)); + } else { + signer.initVerifier(kp.getPublic()); + signer.update(data); + if (signer.verify(signature)) { + System.out.append('\t').println("Valid signature"); + } else { + System.err.append('\t').println("Invalid signature"); + } + } + } + + ////////////////////////////////////////////////////////////////////////// + + // args[0]=signatureName, args[1]=publicKey, args[2]=privateKey, args[3]=sign/verify, args[4]=data, args[5]=signature(if verify required) + public static void main(String[] args) throws Exception { + SignatureFactory factory = BuiltinSignatures.resolveFactory(args[0]); + // TODO recover public/private keys according to factory name + byte[] publicKey = BufferUtils.decodeHex(':', args[1]); + PublicKey pubKey = EdDSASecurityProviderUtils.generateEDDSAPublicKey(publicKey); + byte[] privateKey = BufferUtils.decodeHex(':', args[2]); + PrivateKey prvKey = EdDSASecurityProviderUtils.generateEDDSAPrivateKey(privateKey); + String op = args[3]; + byte[] data = BufferUtils.decodeHex(':', args[4]); + byte[] signature = GenericUtils.EMPTY_BYTE_ARRAY; + if ("verify".equalsIgnoreCase(op)) { + signature = BufferUtils.decodeHex(':', args[5]); + } + + testSignatureFactory(factory, new KeyPair(pubKey, prvKey), data, "sign".equalsIgnoreCase(op), signature); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/EventListenerUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/EventListenerUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/EventListenerUtilsTest.java new file mode 100644 index 0000000..1619cd3 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/EventListenerUtilsTest.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.EventListener; +import java.util.List; +import java.util.Set; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class EventListenerUtilsTest extends JUnitTestSupport { + public EventListenerUtilsTest() { + super(); + } + + @Test + public void testProxyWrapper() { + List<ProxyListenerImpl> impls = new ArrayList<>(); + for (int index = 0; index < Byte.SIZE; index++) { + impls.add(new ProxyListenerImpl()); + } + + ProxyListener listener = EventListenerUtils.proxyWrapper(ProxyListener.class, impls); + String expStr = getCurrentTestName(); + Number expNum = System.currentTimeMillis(); + listener.callMeWithString(expStr); + listener.callMeWithNumber(expNum); + + for (int index = 0; index < impls.size(); index++) { + ProxyListenerImpl l = impls.get(index); + assertSame("Mismatched string at listener #" + index, expStr, l.getStringValue()); + assertSame("Mismatched number at listener #" + index, expNum, l.getNumberValue()); + } + } + + @Test + public void testListenerInstanceComparatorOnProxy() { + Comparator<? super EventListener> comparator = EventListenerUtils.LISTENER_INSTANCE_COMPARATOR; + ProxyListener p1 = EventListenerUtils.proxyWrapper(ProxyListener.class, Collections.singletonList(new ProxyListenerImpl())); + assertEquals("Mismatched self reference comparison", 0, comparator.compare(p1, p1)); + + EventListener l = new EventListener() { /* nothing extra */ }; + assertEquals("Mismatched proxy vs. non-proxy result", 1, Integer.signum(comparator.compare(p1, l))); + assertEquals("Mismatched non-proxy vs. proxy result", -1, Integer.signum(comparator.compare(l, p1))); + + ProxyListener p2 = EventListenerUtils.proxyWrapper(ProxyListener.class, Collections.singletonList(new ProxyListenerImpl())); + int p1vsp2 = Integer.signum(comparator.compare(p1, p2)); + assertNotEquals("Mismatched p1 vs. p2 comparison", 0, p1vsp2); + assertEquals("Mismatched p2 vs. p1 comparison result", 0 - p1vsp2, Integer.signum(comparator.compare(p2, p1))); + } + + @Test + public void testListenerInstanceComparatorOnNonProxy() { + Comparator<? super EventListener> comparator = EventListenerUtils.LISTENER_INSTANCE_COMPARATOR; + EventListener l1 = new EventListener() { /* nothing extra */ }; + assertEquals("Mismatched self reference comparison", 0, comparator.compare(l1, l1)); + + EventListener l2 = new EventListener() { /* nothing extra */ }; + int l1vsl2 = Integer.signum(comparator.compare(l1, l2)); + assertNotEquals("Mismatched l1 vs. l2 comparison result", 0, l1vsl2); + assertEquals("Mismatched l2 vs. l1 comparison result", 0 - l1vsl2, Integer.signum(comparator.compare(l2, l1))); + } + + @Test + public void testSynchronizedListenersSetOnProxies() { + ProxyListener p1 = EventListenerUtils.proxyWrapper(ProxyListener.class, Collections.singletonList(new ProxyListenerImpl())); + Set<ProxyListener> s = EventListenerUtils.synchronizedListenersSet(); + for (int index = 1; index <= Byte.SIZE; index++) { + boolean modified = s.add(p1); + assertEquals("Mismatched p1 modification indicator at attempt #" + index, index == 1, modified); + assertEquals("Mismatched p1 set size at attempt #" + index, 1, s.size()); + } + + ProxyListener p2 = EventListenerUtils.proxyWrapper(ProxyListener.class, Collections.singletonList(new ProxyListenerImpl())); + for (int index = 1; index <= Byte.SIZE; index++) { + boolean modified = s.add(p2); + assertEquals("Mismatched p2 modification indicator at attempt #" + index, index == 1, modified); + assertEquals("Mismatched p2 set size at attempt #" + index, 2, s.size()); + } + + assertTrue("Failed to remove p1", s.remove(p1)); + assertEquals("Mismatched post p1-remove size", 1, s.size()); + assertTrue("Failed to remove p2", s.remove(p2)); + assertEquals("Mismatched post p2-remove size", 0, s.size()); + } + + interface ProxyListener extends SshdEventListener { + void callMeWithString(String s); + + void callMeWithNumber(Number n); + } + + static class ProxyListenerImpl implements ProxyListener { + private String strValue; + private Number numValue; + + ProxyListenerImpl() { + super(); + } + + public String getStringValue() { + return strValue; + } + + @Override + public void callMeWithString(String s) { + strValue = s; + } + + public Number getNumberValue() { + return numValue; + } + + @Override + public void callMeWithNumber(Number n) { + numValue = n; + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java new file mode 100644 index 0000000..5727e88 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category(NoIoTestCase.class) +public class GenericUtilsTest extends JUnitTestSupport { + public GenericUtilsTest() { + super(); + } + + @Test + public void testSplitAndJoin() { + List<String> expected = Collections.unmodifiableList( + Arrays.asList(getClass().getPackage().getName().replace('.', '/'), getClass().getSimpleName(), getCurrentTestName())); + + // NOTE: we also test characters that have meaning in String.split(...) as regex ones + for (char ch : new char[]{',', '.', '*', '?'}) { + String sep = String.valueOf(ch); + String s = GenericUtils.join(expected, sep); + String[] actual = GenericUtils.split(s, ch); + assertEquals("Mismatched split length for separator=" + sep, expected.size(), GenericUtils.length((Object[]) actual)); + + for (int index = 0; index < actual.length; index++) { + String e = expected.get(index); + String a = actual[index]; + if (!e.endsWith(a)) { + fail("Mismatched value at index=" + index + " for separator=" + sep + ": expected=" + e + ", actual=" + a); + } + } + } + } + + @Test + public void testStripQuotes() { + String expected = getCurrentTestName(); + assertSame("Unexpected un-quoted stripping", expected, GenericUtils.stripQuotes(expected)); + + StringBuilder sb = new StringBuilder(2 + expected.length()).append('|').append(expected).append('|'); + for (int index = 0; index < GenericUtils.QUOTES.length(); index++) { + char delim = GenericUtils.QUOTES.charAt(index); + sb.setCharAt(0, delim); + sb.setCharAt(sb.length() - 1, delim); + + CharSequence actual = GenericUtils.stripQuotes(sb); + assertEquals("Mismatched result for delim (" + delim + ")", expected, actual.toString()); + } + } + + @Test + public void testStripOnlyFirstLayerQuotes() { + StringBuilder sb = new StringBuilder().append("||").append(getCurrentTestName()).append("||"); + char[] delims = {'\'', '"', '"', '\''}; + for (int index = 0; index < delims.length; index += 2) { + char topDelim = delims[index]; + char innerDelim = delims[index + 1]; + sb.setCharAt(0, topDelim); + sb.setCharAt(1, innerDelim); + sb.setCharAt(sb.length() - 2, innerDelim); + sb.setCharAt(sb.length() - 1, topDelim); + + CharSequence expected = sb.subSequence(1, sb.length() - 1); + CharSequence actual = GenericUtils.stripQuotes(sb); + assertEquals("Mismatched result for delim (" + topDelim + "/" + innerDelim + ")", expected.toString(), actual.toString()); + } + } + + @Test + public void testStripDelimiters() { + String expected = getCurrentTestName(); + final char delim = '|'; + assertSame("Unexpected un-delimited stripping", expected, GenericUtils.stripDelimiters(expected, delim)); + + CharSequence actual = GenericUtils.stripDelimiters( + new StringBuilder(2 + expected.length()).append(delim).append(expected).append(delim), delim); + assertEquals("Mismatched stripped values", expected, actual.toString()); + } + + @Test + public void testStripDelimitersOnlyIfOnBothEnds() { + final char delim = '$'; + StringBuilder expected = new StringBuilder().append(delim).append(getCurrentTestName()).append(delim); + for (int index : new int[]{0, expected.length() - 1}) { + // restore original delimiters + expected.setCharAt(0, delim); + expected.setCharAt(expected.length() - 1, delim); + // trash one end + expected.setCharAt(index, (char) (delim + 1)); + + assertSame("Mismatched result for delim at index=" + index, expected, GenericUtils.stripDelimiters(expected, delim)); + } + } + + @Test + public void testAccumulateExceptionOnNullValues() { + assertNull("Unexpected null/null result", GenericUtils.accumulateException(null, null)); + + Throwable expected = new NoSuchMethodException(getClass().getName() + "#" + getCurrentTestName()); + assertSame("Mismatched null/extra result", expected, GenericUtils.accumulateException(null, expected)); + assertSame("Mismatched current/null result", expected, GenericUtils.accumulateException(expected, null)); + } + + @Test + public void testAccumulateExceptionOnExistingCurrent() { + RuntimeException[] expected = new RuntimeException[]{ + new IllegalArgumentException(getCurrentTestName()), + new ClassCastException(getClass().getName()), + new NoSuchElementException(getClass().getPackage().getName()) + }; + RuntimeException current = new UnsupportedOperationException("top"); + for (RuntimeException extra : expected) { + RuntimeException actual = GenericUtils.accumulateException(current, extra); + assertSame("Mismatched returned actual exception", current, actual); + } + + Throwable[] actual = current.getSuppressed(); + assertArrayEquals("Suppressed", expected, actual); + } + + @Test + public void testNullOrEmptyCharArrayComparison() { + char[][] values = new char[][]{null, GenericUtils.EMPTY_CHAR_ARRAY}; + for (char[] c1 : values) { + for (char[] c2 : values) { + assertEquals(((c1 == null) ? "null" : "empty") + " vs. " + ((c2 == null) ? "null" : "empty"), 0, GenericUtils.compare(c1, c2)); + } + } + } + + @Test + public void testCharArrayComparison() { + String s1 = getClass().getSimpleName(); + char[] c1 = s1.toCharArray(); + assertEquals("Same value equality", 0, GenericUtils.compare(c1, s1.toCharArray())); + + String s2 = getCurrentTestName(); + char[] c2 = s2.toCharArray(); + assertEquals("s1 vs. s2", Integer.signum(s1.compareTo(s2)), Integer.signum(GenericUtils.compare(c1, c2))); + assertEquals("s2 vs. s1", Integer.signum(s2.compareTo(s1)), Integer.signum(GenericUtils.compare(c2, c1))); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/Int2IntFunctionTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/Int2IntFunctionTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/Int2IntFunctionTest.java new file mode 100644 index 0000000..b0c48ca --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/Int2IntFunctionTest.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import java.util.Random; +import java.util.function.IntUnaryOperator; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class Int2IntFunctionTest extends JUnitTestSupport { + public Int2IntFunctionTest() { + super(); + } + + @Test + public void testAdd() { + int factor = Byte.SIZE; + IntUnaryOperator func = Int2IntFunction.add(factor); + for (int index = 1, sum = 0; index <= Byte.SIZE; index++) { + sum = func.applyAsInt(sum); + assertEquals(factor * index, sum); + } + } + + @Test + public void testAddIdentity() { + IntUnaryOperator func = Int2IntFunction.add(0); + Random rnd = new Random(System.nanoTime()); + for (int index = 1; index <= Byte.SIZE; index++) { + int expected = rnd.nextInt(); + int actual = func.applyAsInt(expected); + assertEquals(expected, actual); + } + } + + @Test + public void testSub() { + int factor = Byte.SIZE; + IntUnaryOperator func = Int2IntFunction.sub(factor); + for (int index = 1, sum = 0; index <= Byte.SIZE; index++) { + sum = func.applyAsInt(sum); + assertEquals(factor * index * -1, sum); + } + } + + @Test + public void testSubIdentity() { + IntUnaryOperator func = Int2IntFunction.sub(0); + Random rnd = new Random(System.nanoTime()); + for (int index = 1; index <= Byte.SIZE; index++) { + int expected = rnd.nextInt(); + int actual = func.applyAsInt(expected); + assertEquals(expected, actual); + } + } + + @Test + public void testMul() { + int factor = 2; + IntUnaryOperator func = Int2IntFunction.mul(factor); + for (int index = 1, mul = 1, expected = factor; index <= Byte.SIZE; index++, expected *= factor) { + mul = func.applyAsInt(mul); + assertEquals(expected, mul); + } + } + + @Test + public void testMulIdentity() { + IntUnaryOperator func = Int2IntFunction.mul(1); + Random rnd = new Random(System.nanoTime()); + for (int index = 1; index <= Byte.SIZE; index++) { + int expected = rnd.nextInt(); + int actual = func.applyAsInt(expected); + assertEquals(expected, actual); + } + } + + @Test + public void testMulZero() { + IntUnaryOperator func = Int2IntFunction.mul(0); + Random rnd = new Random(System.nanoTime()); + for (int index = 1; index <= Byte.SIZE; index++) { + int value = rnd.nextInt(); + int actual = func.applyAsInt(value); + assertEquals(Integer.toString(value), 0, actual); + } + } + + @Test + public void testConstant() { + int expected = 377347; + IntUnaryOperator func = Int2IntFunction.constant(expected); + Random rnd = new Random(System.nanoTime()); + for (int index = 1; index <= Byte.SIZE; index++) { + int value = rnd.nextInt(); + int actual = func.applyAsInt(value); + assertEquals(Integer.toString(value), expected, actual); + } + } + + @Test + public void testDiv() { + int factor = 2; + IntUnaryOperator func = Int2IntFunction.div(factor); + for (int index = 1, quot = 65536, expected = quot / factor; index <= Byte.SIZE; index++, expected /= factor) { + quot = func.applyAsInt(quot); + assertEquals(expected, quot); + } + } + + @Test + public void testDivIdentity() { + IntUnaryOperator func = Int2IntFunction.div(1); + Random rnd = new Random(System.nanoTime()); + for (int index = 1; index <= Byte.SIZE; index++) { + int expected = rnd.nextInt(); + int actual = func.applyAsInt(expected); + assertEquals(expected, actual); + } + } + + @Test(expected = IllegalArgumentException.class) + public void testDivZeroFactor() { + IntUnaryOperator func = Int2IntFunction.div(0); + fail("Unexpected success: " + func); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/NumberUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/NumberUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/NumberUtilsTest.java new file mode 100644 index 0000000..927cecb --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/NumberUtilsTest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class NumberUtilsTest extends JUnitTestSupport { + public NumberUtilsTest() { + super(); + } + + @Test + public void testPowersOf2List() { + assertEquals("Mismatched values size for " + NumberUtils.POWERS_OF_TWO, Long.SIZE, GenericUtils.size(NumberUtils.POWERS_OF_TWO)); + long expected = 1L; + for (int index = 0; index < Long.SIZE; index++, expected <<= 1) { + Long actual = NumberUtils.POWERS_OF_TWO.get(index); + assertEquals("Mismatched value at index=" + index, Long.toHexString(expected), Long.toHexString(actual)); + } + } + + @Test + public void testNextPowerOf2() { + for (Long v : NumberUtils.POWERS_OF_TWO) { + long expected = v; + if (expected > 2L) { + assertEquals("Mismatched lower bound value", expected, NumberUtils.getNextPowerOf2(expected - 1L)); + } + + if (expected > 0L) { // avoid the negative value + assertEquals("Mismatched exact value", expected, NumberUtils.getNextPowerOf2(expected)); + } + } + } + + @Test + public void testToInteger() { + assertNull("Unexpected null value", NumberUtils.toInteger(null)); + for (Number n : new Number[]{ + Byte.valueOf(Byte.MAX_VALUE), Short.valueOf(Short.MIN_VALUE), + Integer.valueOf(Short.MAX_VALUE), Long.valueOf(82007160L)}) { + Integer i = NumberUtils.toInteger(n); + if (n instanceof Integer) { + assertSame("Unexpected conversion", n, i); + } else { + assertEquals("Mismatched values", n.intValue(), i.intValue()); + } + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/OsUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/OsUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/OsUtilsTest.java new file mode 100644 index 0000000..af78a11 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/OsUtilsTest.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import java.util.Objects; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class OsUtilsTest extends JUnitTestSupport { + public OsUtilsTest() { + super(); + } + + @Test + public void testSetOsTypeByProperty() { + try { + for (String osType : new String[]{"Some-Windows", "Some-Linux"}) { + OsUtils.setWin32(null); // force re-detection + + try { + boolean expected = osType.contains("Windows"); + System.setProperty(OsUtils.OS_TYPE_OVERRIDE_PROP, osType); + boolean actual = OsUtils.isWin32(); + assertEquals(osType, expected, actual); + } finally { + System.clearProperty(OsUtils.OS_TYPE_OVERRIDE_PROP); + } + } + } finally { + OsUtils.setWin32(null); // force re-detection + } + } + + @Test + public void testSetOsTypeProgrammatically() { + try { + for (boolean expected : new boolean[]{true, false}) { + OsUtils.setWin32(expected); // force value + assertEquals("Mismatched detection value", expected, OsUtils.isWin32()); + } + } finally { + OsUtils.setWin32(null); // force re-detection + } + } + + @Test + public void testSetCurrentUserByProperty() { + try { + for (String expected : new String[]{getClass().getSimpleName(), getCurrentTestName()}) { + OsUtils.setCurrentUser(null); // force re-detection + + try { + System.setProperty(OsUtils.CURRENT_USER_OVERRIDE_PROP, expected); + String actual = OsUtils.getCurrentUser(); + assertEquals("Mismatched reported current user", expected, actual); + } finally { + System.clearProperty(OsUtils.CURRENT_USER_OVERRIDE_PROP); + } + } + } finally { + OsUtils.setCurrentUser(null); // force re-detection + } + } + + @Test + public void testSetCurrentUserProgrammatically() { + try { + for (String expected : new String[]{getClass().getSimpleName(), getCurrentTestName()}) { + OsUtils.setCurrentUser(expected); // force value + assertEquals("Mismatched detection value", expected, OsUtils.getCurrentUser()); + } + } finally { + OsUtils.setCurrentUser(null); // force re-detection + } + } + + @Test + public void testSetJavaVersionByProperty() { + try { + for (String value : new String[]{"7.3.6_5", "37.77.34_7-" + getCurrentTestName()}) { + OsUtils.setJavaVersion(null); // force re-detection + + try { + System.setProperty(OsUtils.JAVA_VERSION_OVERRIDE_PROP, value); + String expected = value.replace('_', '.'); + String actual = Objects.toString(OsUtils.getJavaVersion(), null); + assertTrue("Mismatched reported version value: " + actual, expected.startsWith(actual)); + } finally { + System.clearProperty(OsUtils.JAVA_VERSION_OVERRIDE_PROP); + } + } + } finally { + OsUtils.setJavaVersion(null); // force re-detection + } + } + + @Test + public void testSetJavaVersionProgrammatically() { + try { + for (VersionInfo expected : new VersionInfo[]{VersionInfo.parse("7.3.6.5"), VersionInfo.parse("37.77.34.7")}) { + OsUtils.setJavaVersion(expected); // force value + assertEquals("Mismatched detection value", expected, OsUtils.getJavaVersion()); + } + } finally { + OsUtils.setJavaVersion(null); // force re-detection + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java new file mode 100644 index 0000000..3044699 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import java.io.File; +import java.util.Random; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.Assume; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class SelectorUtilsTest extends JUnitTestSupport { + public SelectorUtilsTest() { + super(); + } + + @Test + public void testApplyLinuxSeparatorSlashifyRules() { + testApplySlashifyRules('/'); + } + + @Test + public void testApplyWindowsSeparatorSlashifyRules() { + testApplySlashifyRules('\\'); + } + + private void testApplySlashifyRules(char slash) { + for (String expected : new String[]{ + null, "", getCurrentTestName(), + getClass().getSimpleName() + Character.toString(slash) + getCurrentTestName(), + Character.toString(slash) + getClass().getSimpleName(), + Character.toString(slash) + getClass().getSimpleName() + Character.toString(slash) + getCurrentTestName() + }) { + String actual = SelectorUtils.applySlashifyRules(expected, slash); + assertSame("Mismatched results for '" + expected + "'", expected, actual); + } + + String[] comps = {getClass().getSimpleName(), getCurrentTestName()}; + Random rnd = new Random(System.nanoTime()); + StringBuilder sb = new StringBuilder(Byte.MAX_VALUE); + for (int index = 0; index < Long.SIZE; index++) { + if (sb.length() > 0) { + sb.setLength(0); // start from scratch + } + + boolean prepend = rnd.nextBoolean(); + if (prepend) { + slashify(sb, rnd, slash); + } + + sb.append(comps[0]); + for (int j = 1; j < comps.length; j++) { + slashify(sb, rnd, slash); + sb.append(comps[j]); + } + + boolean append = rnd.nextBoolean(); + if (append) { + slashify(sb, rnd, slash); + } + + String path = sb.toString(); + sb.setLength(0); + if (prepend) { + sb.append(slash); + } + + sb.append(comps[0]); + for (int j = 1; j < comps.length; j++) { + sb.append(slash).append(comps[j]); + } + + if (append) { + sb.append(slash).append('.'); + } + + String expected = sb.toString(); + String actual = SelectorUtils.applySlashifyRules(path, slash); + assertEquals("Mismatched results for path=" + path, expected, actual); + } + } + + private static int slashify(StringBuilder sb, Random rnd, char slash) { + int slashes = 1 /* at least one slash */ + rnd.nextInt(Byte.SIZE); + for (int k = 0; k < slashes; k++) { + sb.append(slash); + } + + return slashes; + } + + @Test + public void testTranslateToFileSystemPath() { + String path = getClass().getPackage().getName().replace('.', File.separatorChar) + + File.separator + getClass().getSimpleName() + + File.separator + getCurrentTestName(); + for (String expected : new String[] {null, "", path}) { + String actual = SelectorUtils.translateToFileSystemPath(expected, File.separator, File.separator); + assertSame("Mismatched instance for translated result", expected, actual); + } + + for (String fsSeparator : new String[] {String.valueOf('.'), "##"}) { + String expected = path.replace(File.separator, fsSeparator); + String actual = SelectorUtils.translateToFileSystemPath(path, File.separator, fsSeparator); + assertEquals("Mismatched translation result for separator='" + fsSeparator + "'", expected, actual); + + actual = SelectorUtils.translateToFileSystemPath(actual, fsSeparator, File.separator); + assertEquals("Mismatched translation revert for separator='" + fsSeparator + "'", path, actual); + } + } + + @Test + public void testAbsoluteWindowsPathTranslation() { + Assume.assumeTrue("Not tested on Windows", OsUtils.isWin32()); + String expected = detectTargetFolder().toString(); + for (String prefix : new String[]{"", "/"}) { + String actual = SelectorUtils.translateToLocalPath(prefix + expected.replace('/', File.separatorChar)); + assertEquals("Mismatched result for prefix='" + prefix + "'", expected, actual); + } + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/ThreadUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/ThreadUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/ThreadUtilsTest.java new file mode 100644 index 0000000..10e6f5b --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/ThreadUtilsTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import java.util.Collection; + +import org.apache.sshd.common.util.threads.CloseableExecutorService; +import org.apache.sshd.common.util.threads.ThreadUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class ThreadUtilsTest extends JUnitTestSupport { + public ThreadUtilsTest() { + super(); + } + + @Test + public void testProtectExecutorServiceShutdown() { + for (boolean shutdownOnExit : new boolean[]{true, false}) { + assertNull("Unexpected instance for shutdown=" + shutdownOnExit, ThreadUtils.protectExecutorServiceShutdown(null, shutdownOnExit)); + } + + CloseableExecutorService service = ThreadUtils.newSingleThreadExecutor("pool"); + try { + assertSame("Unexpected wrapped instance", service, ThreadUtils.protectExecutorServiceShutdown(service, true)); + + CloseableExecutorService wrapped = ThreadUtils.protectExecutorServiceShutdown(service, false); + try { + assertNotSame("No wrapping occurred", service, wrapped); + + wrapped.shutdown(); + assertTrue("Wrapped service not shutdown", wrapped.isShutdown()); + assertFalse("Protected service is shutdown", service.isShutdown()); + + Collection<?> running = wrapped.shutdownNow(); + assertTrue("Non-empty runners list", running.isEmpty()); + assertTrue("Wrapped service not shutdownNow", wrapped.isShutdown()); + assertFalse("Protected service is shutdownNow", service.isShutdown()); + } finally { + wrapped.shutdownNow(); // just in case + } + } finally { + service.shutdownNow(); // just in case... + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/ValidateUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/ValidateUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/ValidateUtilsTest.java new file mode 100644 index 0000000..9efd5f9 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/ValidateUtilsTest.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category(NoIoTestCase.class) +public class ValidateUtilsTest extends JUnitTestSupport { + public ValidateUtilsTest() { + super(); + } + + @Test(expected = IllegalArgumentException.class) + public void checkNotNull() { + ValidateUtils.checkNotNull(getClass(), getCurrentTestName()); + ValidateUtils.checkNotNull(null, getCurrentTestName()); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/VersionInfoTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/VersionInfoTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/VersionInfoTest.java new file mode 100644 index 0000000..834be24 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/VersionInfoTest.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class VersionInfoTest extends JUnitTestSupport { + public VersionInfoTest() { + super(); + } + + @Test + public void testLessThan4Components() { + VersionInfo expected = new VersionInfo(73, 65); + VersionInfo actual = VersionInfo.parse(NumberUtils.join('.', expected.getMajorVersion(), expected.getMinorVersion())); + assertEquals("Mismatched result", expected, actual); + } + + @Test + public void testMoreThan4Components() { + VersionInfo expected = new VersionInfo(7, 3, 6, 5); + VersionInfo actual = VersionInfo.parse(expected.toString() + ".3.7.7.7.3.4.7"); + assertEquals("Mismatched result", expected, actual); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/buffer/BufferTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/buffer/BufferTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/buffer/BufferTest.java new file mode 100644 index 0000000..6f41b76 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/buffer/BufferTest.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util.buffer; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.nio.charset.StandardCharsets; + +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class BufferTest extends JUnitTestSupport { + public BufferTest() { + super(); + } + + @Test + public void testGetLong() throws Exception { + long expected = 1234567890123456789L; + + try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { + try (DataOutputStream ds = new DataOutputStream(stream)) { + ds.writeLong(expected); + } + + Buffer buffer = new ByteArrayBuffer(stream.toByteArray()); + assertEquals("Mismatched recovered value", expected, buffer.getLong()); + } + } + + @Test + public void testPutCharsWithNullOrEmptyValue() { + Buffer buffer = new ByteArrayBuffer(Integer.SIZE); + for (char[] chars : new char[][]{null, GenericUtils.EMPTY_CHAR_ARRAY}) { + buffer.putChars(chars); + + String value = buffer.getString(); + assertEquals("Mismatched value for " + ((chars == null) ? "null" : "empty") + " characters", "", value); + } + } + + @Test + public void testPutCharsOnNonEmptyValue() { + String expected = getCurrentTestName(); + Buffer buffer = new ByteArrayBuffer(expected.length() + Byte.SIZE); + buffer.putChars(expected.toCharArray()); + + String actual = buffer.getString(); + assertEquals("Mismatched recovered values", expected, actual); + } + + @Test + public void testPutAndWipeChars() { + String expected = getCurrentTestName(); + char[] chars = expected.toCharArray(); + Buffer buffer = new ByteArrayBuffer(chars.length + Byte.SIZE); + buffer.putAndWipeChars(chars); + + String actual = buffer.getString(); + assertEquals("Mismatched recovered values", expected, actual); + + for (int index = 0; index < chars.length; index++) { + assertEquals("Character not wiped at index=" + index, 0, chars[index]); + } + } + + @Test + public void testPutAndWipeBytes() { + String expected = getCurrentTestName(); + byte[] bytes = expected.getBytes(StandardCharsets.UTF_8); + Buffer buffer = new ByteArrayBuffer(bytes.length + Byte.SIZE); + buffer.putAndWipeBytes(bytes); + String actual = buffer.getString(); + assertEquals("Mismatched recovered values", expected, actual); + + for (int index = 0; index < bytes.length; index++) { + assertEquals("Value not wiped at index=" + index, 0, bytes[index]); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/buffer/BufferUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/buffer/BufferUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/buffer/BufferUtilsTest.java new file mode 100644 index 0000000..78122b7 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/buffer/BufferUtilsTest.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util.buffer; + +import java.nio.charset.StandardCharsets; +import java.util.Random; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class BufferUtilsTest extends JUnitTestSupport { + public BufferUtilsTest() { + super(); + } + + @Test + public void testHexEncodeDecode() { + String expValue = getClass().getName() + "#" + getCurrentTestName(); + byte[] expData = expValue.getBytes(StandardCharsets.UTF_8); + for (char sep : new char[]{BufferUtils.EMPTY_HEX_SEPARATOR, ':'}) { + String hexData = BufferUtils.toHex(sep, expData); + byte[] actData = BufferUtils.decodeHex(sep, hexData); + String actValue = new String(actData, StandardCharsets.UTF_8); + String sepName = (BufferUtils.EMPTY_HEX_SEPARATOR == sep) ? "EMPTY" : Character.toString(sep); + outputDebugMessage("Decode(sep=%s) expected=%s, actual=%s", sepName, expValue, actValue); + assertArrayEquals("Mismatched result for sep='" + sepName + "'", expData, actData); + } + } + + @Test + public void testGetCompactClone() { + byte[] expected = getCurrentTestName().getBytes(StandardCharsets.UTF_8); + final int testOffset = Byte.SIZE / 2; + byte[] data = new byte[expected.length + 2 * testOffset]; + Random rnd = new Random(System.nanoTime()); + rnd.nextBytes(data); + System.arraycopy(expected, 0, data, testOffset, expected.length); + + Buffer buf = ByteArrayBuffer.getCompactClone(data, testOffset, expected.length); + assertEquals("Mismatched cloned buffer read position", 0, buf.rpos()); + assertEquals("Mismatched cloned buffer available size", expected.length, buf.available()); + + byte[] actual = buf.array(); + assertNotSame("Original data not cloned", data, actual); + assertArrayEquals("Mismatched cloned contents", expected, actual); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/closeable/CloseableUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/closeable/CloseableUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/closeable/CloseableUtilsTest.java new file mode 100644 index 0000000..6ed1187 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/closeable/CloseableUtilsTest.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util.closeable; + +import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.sshd.common.Closeable; +import org.apache.sshd.common.future.CloseFuture; +import org.apache.sshd.common.future.DefaultCloseFuture; +import org.apache.sshd.common.future.SshFutureListener; +import org.apache.sshd.common.util.threads.ThreadUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class CloseableUtilsTest extends JUnitTestSupport { + public CloseableUtilsTest() { + super(); + } + + @Test + public void testCloseImmediateNotCalledIfAlreadyClosed() throws IOException { + Closeable closeable = new IoBaseCloseable() { + @Override + public CloseFuture close(boolean immediately) { + fail("Unexpected call to close(" + immediately + ")"); + return null; + } + + @Override + public void addCloseFutureListener(SshFutureListener<CloseFuture> listener) { + fail("Unexpected call to addCloseFutureListener"); + } + + @Override + public void removeCloseFutureListener(SshFutureListener<CloseFuture> listener) { + fail("Unexpected call to removeCloseFutureListener"); + } + + @Override + public boolean isClosed() { + return true; + } + + @Override + public boolean isClosing() { + return false; + } + }; + closeable.close(); + } + + @Test + public void testCloseImmediateNotCalledIfIsClosing() throws IOException { + Closeable closeable = new IoBaseCloseable() { + @Override + public CloseFuture close(boolean immediately) { + fail("Unexpected call to close(" + immediately + ")"); + return null; + } + + @Override + public void addCloseFutureListener(SshFutureListener<CloseFuture> listener) { + fail("Unexpected call to addCloseFutureListener"); + } + + @Override + public void removeCloseFutureListener(SshFutureListener<CloseFuture> listener) { + fail("Unexpected call to removeCloseFutureListener"); + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public boolean isClosing() { + return true; + } + }; + closeable.close(); + } + + @Test + public void testCloseImmediateCalledAndWait() throws Exception { + DefaultCloseFuture future = new DefaultCloseFuture(this, this); + AtomicInteger callsCount = new AtomicInteger(0); + Closeable closeable = new IoBaseCloseable() { + @Override + public CloseFuture close(boolean immediately) { + assertTrue("Closure is not immediate", immediately); + assertEquals("Multiple close immediate calls", 1, callsCount.incrementAndGet()); + return future; + } + + @Override + public void addCloseFutureListener(SshFutureListener<CloseFuture> listener) { + fail("Unexpected call to addCloseFutureListener"); + } + + @Override + public void removeCloseFutureListener(SshFutureListener<CloseFuture> listener) { + fail("Unexpected call to removeCloseFutureListener"); + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public boolean isClosing() { + return false; + } + }; + + ExecutorService service = ThreadUtils.newSingleThreadExecutor(getCurrentTestName()); + try { + Future<?> task = service.submit((Runnable) () -> { + try { + closeable.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + future.setClosed(); // signal close complete + task.get(5L, TimeUnit.SECONDS); // make sure #await call terminated + assertEquals("Close immediate not called", 1, callsCount.get()); + } finally { + service.shutdownNow(); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/EmptyInputStreamTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/EmptyInputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/EmptyInputStreamTest.java new file mode 100644 index 0000000..113758d --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/EmptyInputStreamTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.sshd.common.util.io; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.sshd.common.util.buffer.BufferUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class EmptyInputStreamTest extends JUnitTestSupport { + public EmptyInputStreamTest() { + super(); + } + + @Test + public void testEmptyInputStream() throws IOException { + try (EmptyInputStream in = new EmptyInputStream()) { + testEmptyInputStream(in, false); + } + } + + @Test + public void testCloseableEmptyInputStream() throws IOException { + try (EmptyInputStream in = new CloseableEmptyInputStream()) { + testEmptyInputStream(in, true); + } + } + + private void testEmptyInputStream(InputStream in, boolean failAfterClose) throws IOException { + testEmptyInputStream("open", in, false); + in.close(); + testEmptyInputStream("closed", in, failAfterClose); + } + + private void testEmptyInputStream(String message, InputStream in, boolean errorExpected) { + assertFalse(message + ": unexpected markSupported()", in.markSupported()); + try { + in.mark(Long.SIZE); + fail(message + ": unexpected mark success"); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + int len = in.available(); + assertFalse(message + ": Unexpected success in available(): " + len, errorExpected); + assertEquals(message + ": Mismatched available() result", 0, len); + } catch (IOException e) { + assertTrue(message + ": Unexpected error on available(): " + e.getMessage(), errorExpected); + } + + try { + int data = in.read(); + assertFalse(message + ": Unexpected success in read(): " + data, errorExpected); + assertEquals(message + ": Mismatched read() result", -1, data); + } catch (IOException e) { + assertTrue(message + ": Unexpected error on read(): " + e.getMessage(), errorExpected); + } + + byte[] bytes = new byte[Byte.SIZE]; + try { + int len = in.read(bytes); + assertFalse(message + ": Unexpected success in read([]): " + BufferUtils.toHex(':', bytes), errorExpected); + assertEquals(message + ": Mismatched read([]) result", -1, len); + } catch (IOException e) { + assertTrue(message + ": Unexpected error on read([]): " + e.getMessage(), errorExpected); + } + + try { + int len = in.read(bytes, 0, bytes.length); + assertFalse(message + ": Unexpected success in read([],int,int): " + BufferUtils.toHex(':', bytes), errorExpected); + assertEquals(message + ": Mismatched read([],int,int) result", -1, len); + } catch (IOException e) { + assertTrue(message + ": Unexpected error on read([],int,int): " + e.getMessage(), errorExpected); + } + + try { + long len = in.skip(Byte.MAX_VALUE); + assertFalse(message + ": Unexpected success in skip(): " + len, errorExpected); + assertEquals(message + ": Mismatched skip() result", 0L, len); + } catch (IOException e) { + assertTrue(message + ": Unexpected error on skip(): " + e.getMessage(), errorExpected); + } + + try { + in.reset(); + assertFalse(message + ": Unexpected success in reset()", errorExpected); + } catch (IOException e) { + assertTrue(message + ": Unexpected error on reset(): " + e.getMessage(), errorExpected); + } + } +}
