test: 添加两个完整的单元测试.

本次提交添加(补充) GroovyTriggerProvider 和 SshAuthInfoSerializer 的完整单元测试类.
This commit is contained in:
LamGC 2021-08-20 02:30:56 +08:00
parent 4609e146d9
commit 616179c00a
Signed by: LamGC
GPG Key ID: 6C5AE2A913941E1D
18 changed files with 383 additions and 21 deletions

View File

@ -0,0 +1,20 @@
package net.lamgc.oracle.sentry.oci.compute.ssh;
import java.security.PublicKey;
public class BadPublicKey implements PublicKey {
@Override
public String getAlgorithm() {
return null;
}
@Override
public String getFormat() {
return null;
}
@Override
public byte[] getEncoded() {
return new byte[0];
}
}

View File

@ -3,43 +3,54 @@ package net.lamgc.oracle.sentry.oci.compute.ssh;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.apache.sshd.common.config.keys.KeyUtils; import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.Random;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
/**
* @see SshAuthInfoSerializer
*/
class SshAuthInfoSerializerTest { class SshAuthInfoSerializerTest {
private final static Gson gson = new GsonBuilder() private final static Gson gson = new GsonBuilder()
.registerTypeAdapter(SshAuthInfo.class, SshAuthInfoSerializer.INSTANCE) .registerTypeAdapter(SshAuthInfo.class, SshAuthInfoSerializer.INSTANCE)
.registerTypeAdapter(PasswordAuthInfo.class, SshAuthInfoSerializer.INSTANCE)
.registerTypeAdapter(PublicKeyAuthInfo.class, SshAuthInfoSerializer.INSTANCE)
.registerTypeAdapter(UnsupportedSshAuthInfo.class, SshAuthInfoSerializer.INSTANCE)
.serializeNulls()
.create(); .create();
private JsonObject getPasswordAuthObject() { private JsonObject getTestsInfo(String name) {
return gson.fromJson(""" InputStream resource = this.getClass().getResourceAsStream("/ssh-auth/" + name + ".json");
{ if (resource == null) {
"username": "opc", throw new NoSuchElementException("Required resource not found: " + name);
"authType": "password", }
"serverKey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/NGFFKkchNdE8HDE9WHGIcw97ZVOP5edY7drtRQn0xSSG6uLu08T36B8IWT+XJdg45/YMmcuVSzsG1QZs/R3s0URVUhsWjwdezWDeWeBHt8/6TGl2AsgA0iXSAOeRNldhZlITFvWoBEv2wElNjCTsEGo5bBp3rVPqqZNJFUs+FR9s/uVgmFqe7HGhuKhhk7BrRThJ/NcgDRicMQ4yXU3Hl++pG54TVLH+0HmgWg312XNAWtzw2iRmKBAuu2I4pP1TRp93K/lbD7QU8k8W7QcyGSAc73nZrhyzYVMko5wQGt4/vGpchOw7ehkotSejTB1GSyhzBTZobA23For76YLzuVFOjF3lEvSh1QV30ysu0PREKLtY83ad0WHVFqVgJrFHkkXQrglN335BhGwhFzwyMpRxbD8HCDtz6VjpqwoKtd/ExQkcfaj/g10o28vRzHGyzUbCTe433V61fjSsC4Bikw15vTnQ3ZuyOzfyoCYUNpFcf1Wv+mkoWqn9xU8lGvk= Test-Server", return gson.fromJson(new InputStreamReader(resource, StandardCharsets.UTF_8), JsonObject.class);
"password": "123456"
}
""", JsonObject.class);
} }
private JsonObject getPublicKeyAuthObject() { private boolean matchTestsInfo(String name, JsonObject object) {
return gson.fromJson(""" return getTestsInfo(name).equals(object);
{
"username": "opc",
"authType": "Public_Key",
"serverKey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/NGFFKkchNdE8HDE9WHGIcw97ZVOP5edY7drtRQn0xSSG6uLu08T36B8IWT+XJdg45/YMmcuVSzsG1QZs/R3s0URVUhsWjwdezWDeWeBHt8/6TGl2AsgA0iXSAOeRNldhZlITFvWoBEv2wElNjCTsEGo5bBp3rVPqqZNJFUs+FR9s/uVgmFqe7HGhuKhhk7BrRThJ/NcgDRicMQ4yXU3Hl++pG54TVLH+0HmgWg312XNAWtzw2iRmKBAuu2I4pP1TRp93K/lbD7QU8k8W7QcyGSAc73nZrhyzYVMko5wQGt4/vGpchOw7ehkotSejTB1GSyhzBTZobA23For76YLzuVFOjF3lEvSh1QV30ysu0PREKLtY83ad0WHVFqVgJrFHkkXQrglN335BhGwhFzwyMpRxbD8HCDtz6VjpqwoKtd/ExQkcfaj/g10o28vRzHGyzUbCTe433V61fjSsC4Bikw15vTnQ3ZuyOzfyoCYUNpFcf1Wv+mkoWqn9xU8lGvk= Test-Server",
"privateKeyPath": "",
"keyPassword": ""
}
""", JsonObject.class);
} }
@Test @Test
public void deserializeTest() { public void deserializePasswordTest() {
SshAuthInfo info = gson.fromJson(getPasswordAuthObject(), SshAuthInfo.class); SshAuthInfo info = gson.fromJson(getTestsInfo("StandardPassword"), SshAuthInfo.class);
assertTrue(info instanceof PasswordAuthInfo); assertTrue(info instanceof PasswordAuthInfo);
assertEquals("opc", info.getUsername()); assertEquals("opc", info.getUsername());
@ -47,4 +58,162 @@ class SshAuthInfoSerializerTest {
assertEquals("SHA256:qBu2jRXM6Wog/jWUJJ0WLTMb3UdDGAmYEVZQNZdFZNM", KeyUtils.getFingerPrint(info.getServerKey())); assertEquals("SHA256:qBu2jRXM6Wog/jWUJJ0WLTMb3UdDGAmYEVZQNZdFZNM", KeyUtils.getFingerPrint(info.getServerKey()));
} }
@Test
public void deserializePublicKeyTest() {
SshAuthInfo info = gson.fromJson(getTestsInfo("StandardPublicKey"), SshAuthInfo.class);
assertEquals("SHA256:qBu2jRXM6Wog/jWUJJ0WLTMb3UdDGAmYEVZQNZdFZNM", KeyUtils.getFingerPrint(info.getServerKey()));
assertEquals("opc", info.getUsername());
if (info instanceof PublicKeyAuthInfo pkInfo) {
assertEquals(new File("~/.ssh/id_rsa"), pkInfo.getPrivateKeyPath());
assertEquals("123456", pkInfo.getKeyPassword());
} else {
fail("The type of the parsing result does not match: " + info.getClass());
}
}
@Test
public void deserializeUnsupportedTest() {
assertThrows(JsonParseException.class, () ->
gson.fromJson(getTestsInfo("UnsupportedAuthType"), SshAuthInfo.class));
}
@Test
public void deserializeNoExistTypeTest() {
assertThrows(JsonParseException.class, () ->
gson.fromJson(getTestsInfo("NoExistType"), SshAuthInfo.class));
}
@Test
public void deserializeBadServerKeyFieldTest() {
SshAuthInfo info = gson.fromJson(getTestsInfo("BadServerKeyField"), SshAuthInfo.class);
assertNull(info.getServerKey());
}
@Test
public void deserializeBadServerKeyDecodeTest() {
SshAuthInfo info = gson.fromJson(getTestsInfo("BadServerKey-decode"), SshAuthInfo.class);
assertNull(info.getServerKey());
}
@Test
public void deserializeNoExistServerKeyTest() {
SshAuthInfo info = gson.fromJson(getTestsInfo("ServerKeyNoExist"), SshAuthInfo.class);
assertNull(info.getServerKey());
}
@Test
public void deserializeUnsupportedJsonTypeTest() {
assertThrows(JsonParseException.class, () ->
gson.fromJson(getTestsInfo("UnsupportedJsonType"), SshAuthInfo.class));
}
private void initialSshAuthInfo(SshAuthInfo info) {
try {
KeyPair pair = KeyUtils.generateKeyPair("ssh-rsa", 3072);
info.setServerKey(pair.getPublic());
info.setUsername("linux");
if (info instanceof PasswordAuthInfo psw) {
psw.setPassword(String.valueOf(new Random().nextLong()));
} else if (info instanceof PublicKeyAuthInfo pk) {
pk.setKeyPassword(String.valueOf(new Random().nextLong()));
pk.setPrivateKeyPath(new File("./" + new Random().nextLong() + "/key"));
}
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
private String getOrFailField(JsonObject json, String field) {
if (json.has(field) && json.get(field).isJsonPrimitive()) {
return json.get(field).getAsString();
} else {
fail("The JSON field '" + field + "' does not exist or is not a primitive.");
throw new RuntimeException();
}
}
private PublicKey decodeSshPublicKey(String publicKeyString) throws GeneralSecurityException, IOException {
String[] strings = publicKeyString.split(" ", 3);
@SuppressWarnings("unchecked") PublicKeyEntryDecoder<PublicKey, ?> decoder =
(PublicKeyEntryDecoder<PublicKey, ?>) KeyUtils.getPublicKeyEntryDecoder(strings[0]);
return decoder.decodePublicKey(null, strings[0], Base64.getDecoder().decode(strings[1]), Collections.emptyMap());
}
@Test
public void serializePasswordTest() throws GeneralSecurityException, IOException {
PasswordAuthInfo info = new PasswordAuthInfo();
initialSshAuthInfo(info);
JsonObject json = gson.fromJson(gson.toJson(info), JsonObject.class);
assertEquals(SshAuthInfo.AuthType.PASSWORD.name(), getOrFailField(json, "authType"));
assertEquals(KeyUtils.getFingerPrint(info.getServerKey()),
KeyUtils.getFingerPrint(decodeSshPublicKey(getOrFailField(json, "serverKey"))));
assertEquals(info.getUsername(), getOrFailField(json, "username"));
assertEquals(info.getPassword(), getOrFailField(json, "password"));
}
@Test
public void serializePublicKeyTest() throws GeneralSecurityException, IOException {
PublicKeyAuthInfo info = new PublicKeyAuthInfo();
initialSshAuthInfo(info);
JsonObject json = gson.fromJson(gson.toJson(info), JsonObject.class);
assertEquals(SshAuthInfo.AuthType.PUBLIC_KEY.name(), getOrFailField(json, "authType"));
assertEquals(KeyUtils.getFingerPrint(info.getServerKey()),
KeyUtils.getFingerPrint(decodeSshPublicKey(getOrFailField(json, "serverKey"))));
assertEquals(info.getUsername(), getOrFailField(json, "username"));
assertEquals(info.getPrivateKeyPath().getCanonicalFile(), new File(getOrFailField(json, "privateKeyPath")));
assertEquals(info.getKeyPassword(), getOrFailField(json, "keyPassword"));
}
@Test
public void serializeNoExistServerKeyTest() {
PasswordAuthInfo info = new PasswordAuthInfo();
initialSshAuthInfo(info);
info.setServerKey(null);
JsonObject json = gson.fromJson(gson.toJson(info), JsonObject.class);
assertEquals(SshAuthInfo.AuthType.PASSWORD.name(), getOrFailField(json, "authType"));
assertTrue(json.get("serverKey").isJsonNull());
assertEquals(info.getUsername(), getOrFailField(json, "username"));
assertEquals(info.getPassword(), getOrFailField(json, "password"));
}
@Test
public void serializeUnsupportedTest() {
assertThrows(JsonParseException.class, () ->
gson.toJson(new UnsupportedSshAuthInfo(false)));
}
@Test
public void serializeBadPrivateKeyPathTest() {
PublicKeyAuthInfo info = new PublicKeyAuthInfo();
initialSshAuthInfo(info);
info.setPrivateKeyPath(new File("@#$*%&&96137:()*/key"));
assertThrows(JsonParseException.class, () ->
gson.toJson(info));
}
@Test
public void serializeBadServerKeyTest() {
PasswordAuthInfo info = new PasswordAuthInfo();
initialSshAuthInfo(info);
info.setServerKey(new BadPublicKey());
JsonObject json = gson.fromJson(gson.toJson(info), JsonObject.class);
assertEquals(SshAuthInfo.AuthType.PASSWORD.name(), getOrFailField(json, "authType"));
assertTrue(json.get("serverKey").isJsonNull());
assertEquals(info.getUsername(), getOrFailField(json, "username"));
assertEquals(info.getPassword(), getOrFailField(json, "password"));
}
} }

View File

@ -0,0 +1,15 @@
package net.lamgc.oracle.sentry.oci.compute.ssh;
public class UnsupportedSshAuthInfo extends SshAuthInfo {
private final boolean returnType;
public UnsupportedSshAuthInfo(boolean returnType) {
this.returnType = returnType;
}
@Override
public AuthType getType() {
return returnType ? AuthType.PASSWORD : null;
}
}

View File

@ -0,0 +1,77 @@
package net.lamgc.oracle.sentry.script.groovy;
import net.lamgc.oracle.sentry.script.groovy.trigger.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
/**
* @see GroovyTriggerProvider
*/
class GroovyTriggerProviderTest {
@Test
public void standardRunTest() {
GroovyTrigger trigger = GroovyTriggerProvider.INSTANCE.getTriggerByName("once");
Assertions.assertNotNull(trigger);
Assertions.assertEquals(OnceTrigger.class, trigger.getClass());
}
@Test
public void noAnnotationTriggerTest() throws NoSuchFieldException, IllegalAccessException {
failIfHasTrigger(NoAnnotationTrigger.class);
}
@Test
public void badTriggerNameLoadTest() throws NoSuchFieldException, IllegalAccessException {
failIfHasTrigger(BadAnnotationTrigger.class);
}
@Test
public void duplicateTriggerLoadTest() throws NoSuchFieldException, IllegalAccessException {
Assertions.assertFalse(hasTrigger(DuplicateTriggerA.class) && hasTrigger(DuplicateTriggerB.class));
}
@Test
public void tryToGetNoExistTriggerTest() {
Assertions.assertThrows(NoSuchElementException.class, () ->
GroovyTriggerProvider.INSTANCE.getTriggerByName("NoExistTrigger"));
}
@Test
public void nullTest() {
Assertions.assertThrows(NullPointerException.class, () ->
GroovyTriggerProvider.INSTANCE.getTriggerByName(null));
}
private void failIfHasTrigger(Class<? extends GroovyTrigger> triggerClass)
throws NoSuchFieldException, IllegalAccessException {
if (hasTrigger(triggerClass)) {
Assertions.fail("Trigger did not appear as expected.");
}
}
@SuppressWarnings("unchecked")
private boolean hasTrigger(Class<? extends GroovyTrigger> triggerClass)
throws NoSuchFieldException, IllegalAccessException {
Field providerMapField =
GroovyTriggerProvider.class.getDeclaredField("triggerProviderMap");
providerMapField.setAccessible(true);
Map<String, ServiceLoader.Provider<GroovyTrigger>> map =
(Map<String, ServiceLoader.Provider<GroovyTrigger>>) providerMapField.get(
GroovyTriggerProvider.INSTANCE
);
providerMapField.setAccessible(false);
for (ServiceLoader.Provider<GroovyTrigger> value : map.values()) {
if (triggerClass.equals(value.type())) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,9 @@
package net.lamgc.oracle.sentry.script.groovy.trigger;
@TriggerName("")
public class BadAnnotationTrigger extends BaseTestTrigger {
@Override
public void run(Runnable task) {
throw new UnsupportedOperationException("Unavailable trigger.");
}
}

View File

@ -0,0 +1,8 @@
package net.lamgc.oracle.sentry.script.groovy.trigger;
public abstract class BaseTestTrigger implements GroovyTrigger {
@Override
public void run(Runnable task) {
throw new UnsupportedOperationException("Unavailable trigger.");
}
}

View File

@ -0,0 +1,5 @@
package net.lamgc.oracle.sentry.script.groovy.trigger;
@TriggerName("Duplicate")
public class DuplicateTriggerA extends BaseTestTrigger {
}

View File

@ -0,0 +1,5 @@
package net.lamgc.oracle.sentry.script.groovy.trigger;
@TriggerName("Duplicate")
public class DuplicateTriggerB extends BaseTestTrigger {
}

View File

@ -0,0 +1,5 @@
package net.lamgc.oracle.sentry.script.groovy.trigger;
public class NoAnnotationTrigger extends BaseTestTrigger {
}

View File

@ -0,0 +1,4 @@
net.lamgc.oracle.sentry.script.groovy.trigger.NoAnnotationTrigger
net.lamgc.oracle.sentry.script.groovy.trigger.BadAnnotationTrigger
net.lamgc.oracle.sentry.script.groovy.trigger.DuplicateTriggerA
net.lamgc.oracle.sentry.script.groovy.trigger.DuplicateTriggerB

View File

@ -0,0 +1,6 @@
{
"username": "opc",
"authType": "password",
"serverKey": "ssh-rsa AAAAaCADAQABAAABgQC/NGFFKkchNdE8HDE9WHGIcw97ZVOP5edY7drtRQn0xSSG6uLu08T36B8IWT+XJdg45/YMmcuVSzsG1QZs/R3s0URVUhsWjwdezWDeWeBHt8/6TGl2AsgA0iXSAOeRNldhZlITFvWoBEv2wElNjCTsEGo5bBp3rVPqqZNJFUs+FR9s/uVgmFqe7HGhuKhhk7BrRThJ/NcgDRicMQ4yXU3Hl++pG54TVLH+0HmgWg312XNAWtzw2iRmKBAuu2I4pP1TRp93K/lbD7QU8k8W7QcyGSAc73nZrhyzYVMko5wQGt4/vGpchOw7ehkotSejTB1GSyhzBTZobA23For76YLzuVFOjF3lEvSh1QV30ysu0PREKLtY83ad0WHVFqVgJrFHkkXQrglN335BhGwhFzwyMpRxbD8HCDtz6VjpqwoKtd/ExQkcfaj/g10o28vRzHGyzUbCTe433V61fjSsC4Bikw15vTnQ3ZuyOzfyoCYUNpFcf1Wv+mkoWqn9xU8lGvk= Test-Server",
"password": "123456"
}

View File

@ -0,0 +1,9 @@
{
"username": "opc",
"authType": "Public_Key",
"serverKey": {
"msg": "badServerKeyField"
},
"privateKeyPath": "~/.ssh/id_rsa",
"keyPassword": "123456"
}

View File

@ -0,0 +1,5 @@
{
"username": "opc",
"serverKey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/NGFFKkchNdE8HDE9WHGIcw97ZVOP5edY7drtRQn0xSSG6uLu08T36B8IWT+XJdg45/YMmcuVSzsG1QZs/R3s0URVUhsWjwdezWDeWeBHt8/6TGl2AsgA0iXSAOeRNldhZlITFvWoBEv2wElNjCTsEGo5bBp3rVPqqZNJFUs+FR9s/uVgmFqe7HGhuKhhk7BrRThJ/NcgDRicMQ4yXU3Hl++pG54TVLH+0HmgWg312XNAWtzw2iRmKBAuu2I4pP1TRp93K/lbD7QU8k8W7QcyGSAc73nZrhyzYVMko5wQGt4/vGpchOw7ehkotSejTB1GSyhzBTZobA23For76YLzuVFOjF3lEvSh1QV30ysu0PREKLtY83ad0WHVFqVgJrFHkkXQrglN335BhGwhFzwyMpRxbD8HCDtz6VjpqwoKtd/ExQkcfaj/g10o28vRzHGyzUbCTe433V61fjSsC4Bikw15vTnQ3ZuyOzfyoCYUNpFcf1Wv+mkoWqn9xU8lGvk= Test-Server",
"password": "123456"
}

View File

@ -0,0 +1,5 @@
{
"username": "opc",
"authType": "password",
"password": "123456"
}

View File

@ -0,0 +1,6 @@
{
"username": "opc",
"authType": "password",
"serverKey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/NGFFKkchNdE8HDE9WHGIcw97ZVOP5edY7drtRQn0xSSG6uLu08T36B8IWT+XJdg45/YMmcuVSzsG1QZs/R3s0URVUhsWjwdezWDeWeBHt8/6TGl2AsgA0iXSAOeRNldhZlITFvWoBEv2wElNjCTsEGo5bBp3rVPqqZNJFUs+FR9s/uVgmFqe7HGhuKhhk7BrRThJ/NcgDRicMQ4yXU3Hl++pG54TVLH+0HmgWg312XNAWtzw2iRmKBAuu2I4pP1TRp93K/lbD7QU8k8W7QcyGSAc73nZrhyzYVMko5wQGt4/vGpchOw7ehkotSejTB1GSyhzBTZobA23For76YLzuVFOjF3lEvSh1QV30ysu0PREKLtY83ad0WHVFqVgJrFHkkXQrglN335BhGwhFzwyMpRxbD8HCDtz6VjpqwoKtd/ExQkcfaj/g10o28vRzHGyzUbCTe433V61fjSsC4Bikw15vTnQ3ZuyOzfyoCYUNpFcf1Wv+mkoWqn9xU8lGvk= Test-Server",
"password": "123456"
}

View File

@ -0,0 +1,7 @@
{
"username": "opc",
"authType": "Public_Key",
"serverKey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/NGFFKkchNdE8HDE9WHGIcw97ZVOP5edY7drtRQn0xSSG6uLu08T36B8IWT+XJdg45/YMmcuVSzsG1QZs/R3s0URVUhsWjwdezWDeWeBHt8/6TGl2AsgA0iXSAOeRNldhZlITFvWoBEv2wElNjCTsEGo5bBp3rVPqqZNJFUs+FR9s/uVgmFqe7HGhuKhhk7BrRThJ/NcgDRicMQ4yXU3Hl++pG54TVLH+0HmgWg312XNAWtzw2iRmKBAuu2I4pP1TRp93K/lbD7QU8k8W7QcyGSAc73nZrhyzYVMko5wQGt4/vGpchOw7ehkotSejTB1GSyhzBTZobA23For76YLzuVFOjF3lEvSh1QV30ysu0PREKLtY83ad0WHVFqVgJrFHkkXQrglN335BhGwhFzwyMpRxbD8HCDtz6VjpqwoKtd/ExQkcfaj/g10o28vRzHGyzUbCTe433V61fjSsC4Bikw15vTnQ3ZuyOzfyoCYUNpFcf1Wv+mkoWqn9xU8lGvk= Test-Server",
"privateKeyPath": "~/.ssh/id_rsa",
"keyPassword": "123456"
}

View File

@ -0,0 +1,4 @@
{
"username": "linux",
"authType": "Unsupported"
}

View File

@ -0,0 +1,3 @@
[
"?"
]