Java tutorial
/* * The MIT License * * Copyright (c) 2011, 2014 Sony Mobile Communications Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.sonymobile.tools.gerrit.gerritevents.mock; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.sonyericsson.hudson.plugins.gerrit.trigger.GerritServer; import com.sonyericsson.hudson.plugins.gerrit.trigger.config.Config; import com.sonyericsson.hudson.plugins.gerrit.trigger.config.IGerritHudsonTriggerConfig; import org.apache.commons.lang.StringUtils; import org.apache.sshd.SshServer; import org.apache.sshd.common.NamedFactory; import org.apache.sshd.server.Command; import org.apache.sshd.server.CommandFactory; import org.apache.sshd.server.Environment; import org.apache.sshd.server.ExitCallback; import org.apache.sshd.server.UserAuth; import org.apache.sshd.server.auth.UserAuthNone; import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Constructor; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import com.jcraft.jsch.KeyPair; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.APPROVALS; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.AUTHOR; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.BRANCH; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.COMMIT_MESSAGE; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.CREATED_ON; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.EMAIL; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.ID; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.LAST_UPDATED; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.NAME; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.NUMBER; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.OWNER; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.PARENTS; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.PROJECT; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.REF; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.REVISION; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.STATUS; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.SUBJECT; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.TYPE; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.UPLOADER; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.URL; import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.VALUE; /** * The beginning of a mock of a sshd server. When it is done the idea is to use this to send in stream-events over the * ssh connection, and make connection related tests without running Gerrit on the local machine. There is some progress * but most of the predefined command types has issues. * * @author Robert Sandell <robert.sandell@sonyericsson.com> */ public class SshdServerMock implements CommandFactory { /** * The stream-events command. */ public static final String GERRIT_STREAM_EVENTS = "gerrit stream-events"; /** * The default port that Gerrit usually listens to. */ public static final int GERRIT_SSH_PORT = 29418; /** * How long to sleep to let the ssh-keygen error output appear on stderr. */ protected static final int WAIT_FOR_ERROR_OUTPUT = 1000; /** * One second in ms. */ protected static final int ONE_SECOND = 1000; /** * Minimum time a thread can sleep. */ protected static final int MIN_SLEEP = 200; private volatile CommandMock currentCommand; private List<CommandMock> commandHistory; private List<CommandLookup> commandLookups; @Override public Command createCommand(String s) { CommandMock command = findAndCreateCommand(s); return setCurrentCommand(command); } /** * Finds a command that matches the given line or a new {@link CommandMock} if nothing is found. * * @param s the command line to match. * @return a command. * * @see #createCommand(String) * @see CommandLookup */ private CommandMock findAndCreateCommand(String s) { CommandLookup found = null; for (CommandLookup lookup : commandLookups) { if (lookup.isCommand(s)) { found = lookup; break; } } if (found != null) { if (found.isOneShot()) { commandLookups.remove(found); } return found.newInstance(s); } else { return new CommandMock(s); } } /** * Sets the current command being executed and adds it to the commandHistory. * * @param command the command. * @return the command. */ protected synchronized CommandMock setCurrentCommand(CommandMock command) { currentCommand = command; if (commandHistory == null) { commandHistory = new LinkedList<CommandMock>(); } commandHistory.add(0, command); return currentCommand; } /** * The last started command. There could be other commands running in parallel. * * @return the current command. */ public CommandMock getCurrentCommand() { return currentCommand; } /** * Get the command history. * * @return the command history. */ public List<CommandMock> getCommandHistory() { return commandHistory; } /** * Gets the first running command that matches the given regular expression. * * @param commandSearch the regular expression to match. * @return the found command or null. */ public synchronized CommandMock getRunningCommand(String commandSearch) { if (commandHistory != null) { Pattern p = Pattern.compile(commandSearch); for (CommandMock command : commandHistory) { if (!command.isDestroyed() && p.matcher(command.getCommand()).find()) { return command; } } } return null; } /** * Gets the number of commands that match the given regular expression from the command history. * * @param commandSearch the regular expression to match. * @return number of found commands. */ public synchronized int getNrCommandsHistory(String commandSearch) { int matches = 0; if (commandHistory != null) { Pattern p = Pattern.compile(commandSearch, Pattern.MULTILINE); for (CommandMock command : commandHistory) { Matcher matcher = p.matcher(command.getCommand()); if (matcher.find()) { matches++; } } } return matches; } /** * Specifies a command type to instantiate and give to mina when a command matching the given regular expression is * wanted. * * @param commandPattern the regular expression * @param cmd the class to create the command from. The class must have a constructor taking a single * String argument which is the command requested. * @throws NoSuchMethodException if there is no matching constructor. */ public synchronized void returnCommandFor(String commandPattern, Class<? extends CommandMock> cmd) throws NoSuchMethodException { returnCommandFor(commandPattern, cmd, new Object[0], new Class<?>[0]); } /** * Specifies a command type to instantiate and give to mina when a command matching * the given regular expression is wanted. * * @param commandPattern the regular expression * @param cmd the class to create the command from. The class must have a constructor where the first * argument is a String followed by the class types provided by the types parameter. * @param arguments the other arguments to the constructor besides the command. * @param types the other class types to match the constructor against. * @throws NoSuchMethodException if there is no matching constructor. */ public synchronized void returnCommandFor(String commandPattern, Class<? extends CommandMock> cmd, Object[] arguments, Class<?>[] types) throws NoSuchMethodException { returnCommandFor(commandPattern, cmd, false, arguments, types); } /** * Specifies a command type to instantiate and give to mina when a command matching the given regular expression is * wanted. * * @param commandPattern the regular expression * @param cmd the class to create the command from. The class must have a constructor where the first * argument is a String followed by the class types provided by the types parameter. * @param oneShot if this command should only be returned the first time it is called for. * @param arguments the other arguments to the constructor besides the command. * @param types the other class types to match the constructor against. * @throws NoSuchMethodException if there is no matching constructor. */ public synchronized void returnCommandFor(String commandPattern, Class<? extends CommandMock> cmd, boolean oneShot, Object[] arguments, Class<?>[] types) throws NoSuchMethodException { Class<?>[] argumentTypes = new Class<?>[types.length + 1]; argumentTypes[0] = String.class; System.arraycopy(types, 0, argumentTypes, 1, types.length); Constructor<? extends CommandMock> constructor = cmd.getConstructor(argumentTypes); if (constructor != null) { if (commandLookups == null) { commandLookups = new LinkedList<CommandLookup>(); } commandLookups.add(new CommandLookup(cmd, commandPattern, oneShot, constructor, arguments)); } } /** * Waits for a running command matching the provided regular expression to appear in the command history. * * @param commandSearch a regular expression. * @param timeout the maximum time to wait for the command in ms. * @return the command. */ public CommandMock waitForCommand(String commandSearch, int timeout) { long startTime = System.currentTimeMillis(); SshdServerMock.CommandMock command = null; do { if (System.currentTimeMillis() - startTime >= timeout) { throw new RuntimeException("Timeout!"); } command = getRunningCommand(commandSearch); if (command == null) { try { Thread.sleep(MIN_SLEEP); //CS IGNORE EmptyBlock FOR NEXT 2 LINES. REASON: not needed. } catch (InterruptedException e) { } } } while (command == null); System.out.println("Found it!!! " + command.getCommand()); return command; } /** * Waits for number of commands matching the provided regular expression to appear in the command history. * * @param commandSearch a regular expression. * @param need the number of occurrences to wait for. * @param timeout the maximum time to wait for the command in ms. * @return true if the nr of needed commands was found. */ public boolean waitForNrCommands(String commandSearch, int need, int timeout) { long startTime = System.currentTimeMillis(); int got = 0; do { if (System.currentTimeMillis() - startTime >= timeout) { throw new RuntimeException("Timeout!"); } got = getNrCommandsHistory(commandSearch); if (got != need) { try { Thread.sleep(MIN_SLEEP); //CS IGNORE EmptyBlock FOR NEXT 2 LINES. REASON: not needed. } catch (InterruptedException e) { } } } while (got != need); return true; } /** * Starts a ssh server on the provided port. * * @param server the server mock to start * * @return the server. * @throws IOException if so. */ public static SshServer startServer(SshdServerMock server) throws IOException { SshServer sshd = SshServer.setUpDefaultServer(); sshd.setPort(0); sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser")); List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<NamedFactory<UserAuth>>(); userAuthFactories.add(new UserAuthNone.Factory()); sshd.setUserAuthFactories(userAuthFactories); sshd.setCommandFactory(server); sshd.start(); return sshd; } /** * Configures the GerritServer config to connect to the provided ssh server. * * @param sshd the server to connect to * @param gerritServer the config to configure * @param reconnect if the GerritServer connection should be restarted after the configuration change * * @see #getConfigFor(SshServer, IGerritHudsonTriggerConfig) * @see GerritServer#stopConnection() * @see GerritServer#startConnection() */ public static void configureFor(SshServer sshd, GerritServer gerritServer, boolean reconnect) { if (reconnect) { gerritServer.stopConnection(); } configureFor(sshd, gerritServer); if (reconnect) { gerritServer.startConnection(); } } /** * Configures the GerritServer config to connect to the provided ssh server. * * @param sshd the server to connect to * @param sshKey the public key location to configure * @param gerritServer the config to configure * @see #getConfigFor(SshServer, IGerritHudsonTriggerConfig) */ public static void configureFor(final SshServer sshd, KeyPairFiles sshKey, GerritServer gerritServer) { gerritServer.setConfig(getConfigFor(sshd, sshKey, gerritServer.getConfig())); } /** * Configures the GerritServer config to connect to the provided ssh server. * * @param sshd the server to connect to * @param gerritServer the config to configure * @see #getConfigFor(SshServer, IGerritHudsonTriggerConfig) */ public static void configureFor(final SshServer sshd, GerritServer gerritServer) { configureFor(sshd, null, gerritServer); } /** * creates a new Config with the ssh hostname and port set to connect to the provided server. * * @param sshd the server to configure for * @param existing the existing configuration * @return a new Config * @see Config#Config(IGerritHudsonTriggerConfig) */ public static Config getConfigFor(final SshServer sshd, IGerritHudsonTriggerConfig existing) { return getConfigFor(sshd, null, existing); } /** * creates a new Config with the ssh hostname and port set to connect to the provided server. * * @param sshd the server to configure for * @param sshKey the public key location to configure * @param existing the existing configuration * @return a new Config * @see Config#Config(IGerritHudsonTriggerConfig) */ public static Config getConfigFor(final SshServer sshd, KeyPairFiles sshKey, IGerritHudsonTriggerConfig existing) { Config c = new Config(existing); String host = sshd.getHost(); if (StringUtils.isBlank(host)) { c.setGerritHostName("localhost"); } else { c.setGerritHostName(host); } c.setGerritSshPort(sshd.getPort()); if (sshKey != null) { c.setGerritAuthKeyFile(sshKey.getPrivateKey()); } return c; } /** * Generates a rsa key-pair in /tmp/jenkins-testkey for use with authenticating the trigger against the mock * server. * * @return the path to the private key file * * @throws IOException if so. * @throws InterruptedException if interrupted while waiting for ssh-keygen to finish. * @throws JSchException if creation of the keys goes wrong. */ public static KeyPairFiles generateKeyPair() throws IOException, InterruptedException, JSchException { File tmp = new File(System.getProperty("java.io.tmpdir")); File priv = new File(tmp, "jenkins-testkey"); File pub = new File(tmp, "jenkins-testkey.pub"); if (!(priv.exists() && pub.exists())) { if (priv.exists()) { if (!priv.delete()) { throw new IOException("Could not delete temp private key"); } } if (pub.exists()) { if (!pub.delete()) { throw new IOException("Could not delete temp public key"); } } System.out.println("Generating test key-pair."); JSch jsch = new JSch(); KeyPair kpair = KeyPair.genKeyPair(jsch, KeyPair.RSA); kpair.writePrivateKey(new FileOutputStream(priv)); kpair.writePublicKey(new FileOutputStream(pub), "Test"); System.out.println("Finger print: " + kpair.getFingerPrint()); kpair.dispose(); return new KeyPairFiles(priv, pub); } else { System.out.println("Test key-pair seems to already exist."); return new KeyPairFiles(priv, pub); } } /** * Pointer to two key-pair files. * Returned from {@link #generateKeyPair()}. */ public static final class KeyPairFiles { private File privateKey; private File publicKey; /** * Standard constructor. * * @param privateKey the private key * @param publicKey the public key */ private KeyPairFiles(File privateKey, File publicKey) { this.privateKey = privateKey; this.publicKey = publicKey; } /** * The private key. * @return file pointer to the private key */ public File getPrivateKey() { return privateKey; } /** * The public key. * @return file pointer to the public key */ public File getPublicKey() { return publicKey; } } /** * A mocked ssh command. * * @see SshdServerMock#createCommand(String) */ public static class CommandMock implements Command { /** * The max ms to wait before checking if the command is destroyed. */ protected static final int WAIT_FOR_DESTROYED = 2000; private InputStream inputStream; private OutputStream outputStream; private OutputStream errorStream; private ExitCallback exitCallback; private boolean destroyed = false; /** * The command. */ protected String command; /** * Standard constructor. * * @param command the command to "execute". */ public CommandMock(String command) { this.command = command; } @Override public void setInputStream(InputStream inputStream) { this.inputStream = inputStream; } @Override public void setOutputStream(OutputStream outputStream) { this.outputStream = outputStream; } @Override public void setErrorStream(OutputStream errorStream) { this.errorStream = errorStream; } @Override public void setExitCallback(ExitCallback exitCallback) { this.exitCallback = exitCallback; } /** * Default implementation just waits for the command to be destroyed. * * @param environment env. * @throws IOException if so. */ @Override public void start(Environment environment) throws IOException { System.out.println("Starting command: " + command); //Default implementation just waits for a disconnect while (!isDestroyed()) { try { synchronized (this) { this.wait(WAIT_FOR_DESTROYED); } } catch (InterruptedException e) { System.err.println("[SSHD-CommandMock] Awake."); } } } /** * Stops the command from running. * * @param exitCode the exitCode to return to the client. */ public synchronized void stop(int exitCode) { exitCallback.onExit(exitCode); } @Override public void destroy() { synchronized (this) { destroyed = true; notifyAll(); } } /** * Is the command destroyed. * * @return true if so. */ public boolean isDestroyed() { synchronized (this) { return destroyed; } } /** * The input stream to the command. * * @return the input stream. */ public InputStream getInputStream() { return inputStream; } /** * the output stream from the command. * * @return the output stream. */ public OutputStream getOutputStream() { return outputStream; } /** * The error stream from the command. * * @return the error stream. */ public OutputStream getErrorStream() { return errorStream; } /** * The command from the client. * * @return the command. */ public String getCommand() { return command; } } /** * A command that immediately returns 0. There can be some timing issues with this command. */ public static class EofCommandMock extends CommandMock { /** * Standard constructor. * * @param command the command. */ public EofCommandMock(String command) { super(command); } @Override public void start(Environment environment) throws IOException { System.out.println("Starting EOF-command: " + getCommand()); this.stop(0); } } /** * A Command that prints a given list of lines when the {@link #now()} method is called and then exits with 0. This * command is not working as expected yet. */ public static class PrintLinesCommand extends CommandMock { private List<String> lines; private boolean doItNow = false; /** * Standard constructor. * * @param command the command * @param lines the lines to print. */ public PrintLinesCommand(String command, List<String> lines) { super(command); this.lines = lines; } /** * call this to make the command print its lines to the output. */ public synchronized void now() { doItNow = true; this.notifyAll(); } /** * If it is time to start printing. Used for synchronous reading. * * @return true if so. */ private synchronized boolean isNow() { return doItNow; } @Override public void start(final Environment environment) throws IOException { System.out.println("Starting PL-command: " + getCommand()); while (!isNow()) { synchronized (this) { try { this.wait(ONE_SECOND); } catch (InterruptedException e) { System.err.println("Interrupted while waiting."); } } } try { PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(getOutputStream(), "UTF-8"))); for (String line : lines) { System.out.println("Sending: " + line); out.println(line); out.flush(); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } /** * A Command that prints a version and then exits with 0. */ public static class SendVersionCommand extends CommandMock { /** * Standard constructor. * * @param command the command */ public SendVersionCommand(String command) { super(command); } @Override public void start(final Environment environment) throws IOException { String line = "gerrit version 2.11.4"; System.out.println("Starting PL-command: " + getCommand()); try { PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(getOutputStream(), "UTF-8"))); System.out.println("Sending: " + line); out.println(line); out.flush(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } this.stop(0); } } /** * A Command that returns last patcheset with approvals. */ public static class SendQueryLastPatchSet extends CommandMock { /** * Standard constructor. * * @param command the command */ public SendQueryLastPatchSet(String command) { super(command); } @Override public void start(final Environment environment) throws IOException { final int createdOn1 = 1449170072; final int createdOn2 = 1449168976; final int lastUpdated = 1449170950; JSONObject jsonAccount = new JSONObject(); jsonAccount.put(EMAIL, "EngyCZ@gmail.com"); jsonAccount.put(NAME, "Engy"); JSONArray parents = new JSONArray(); parents.add("31581608d63510c13d7cb12d3e9a245ca4f72a62"); JSONObject currentPatchSet = new JSONObject(); currentPatchSet.put(NUMBER, "2"); currentPatchSet.put(REVISION, "87861b77a7614f8e6da19b017c588b741911983c"); currentPatchSet.put(PARENTS, parents); currentPatchSet.put(REF, "refs/changes/00/100/2"); currentPatchSet.put(UPLOADER, jsonAccount); currentPatchSet.put(CREATED_ON, createdOn1); currentPatchSet.put(AUTHOR, jsonAccount); JSONArray approvals = new JSONArray(); JSONObject crw = new JSONObject(); crw.put(TYPE, "Code-Review"); crw.put(VALUE, "2"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Code-Review"); crw.put(VALUE, "1"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Code-Review"); crw.put(VALUE, "-1"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Verified"); crw.put(VALUE, "2"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Verified"); crw.put(VALUE, "1"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Verified"); crw.put(VALUE, "-1"); approvals.add(crw); currentPatchSet.put(APPROVALS, approvals); JSONObject change = new JSONObject(); change.put(PROJECT, "project"); change.put(BRANCH, "branch"); change.put(ID, "I2343434344"); change.put(NUMBER, "100"); change.put(SUBJECT, "subject"); change.put(OWNER, jsonAccount); change.put(URL, "http://localhost:8080"); change.put(COMMIT_MESSAGE, "Change"); change.put(CREATED_ON, createdOn2); change.put(LAST_UPDATED, lastUpdated); change.put("open", true); change.put(STATUS, "NEW"); change.put("currentPatchSet", currentPatchSet); System.out.println("Starting QueryLastPatchSet: " + getCommand()); try { PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(getOutputStream(), "UTF-8"))); System.out.println("Sending: " + change); out.println(change); out.flush(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } this.stop(0); } } /** * A Command that returns last patcheset with approvals. */ public static class SendQueryAllPatchSets extends CommandMock { /** * Standard constructor. * * @param command the command */ public SendQueryAllPatchSets(String command) { super(command); } @Override public void start(final Environment environment) throws IOException { final int createdOn1 = 1449170072; final int createdOn2 = 1449168976; final int lastUpdated = 1449170950; JSONObject jsonAccount = new JSONObject(); jsonAccount.put(EMAIL, "EngyCZ@gmail.com"); jsonAccount.put(NAME, "Engy"); JSONArray parents = new JSONArray(); parents.add("31581608d63510c13d7cb12d3e9a245ca4f72a62"); JSONObject currentPatchSet = new JSONObject(); currentPatchSet.put(NUMBER, "2"); currentPatchSet.put(REVISION, "87861b77a7614f8e6da19b017c588b741911983c"); currentPatchSet.put(PARENTS, parents); currentPatchSet.put(REF, "refs/changes/00/100/2"); currentPatchSet.put(UPLOADER, jsonAccount); currentPatchSet.put(CREATED_ON, createdOn1); currentPatchSet.put(AUTHOR, jsonAccount); JSONArray approvals = new JSONArray(); JSONObject crw = new JSONObject(); crw.put(TYPE, "Code-Review"); crw.put(VALUE, "2"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Code-Review"); crw.put(VALUE, "1"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Code-Review"); crw.put(VALUE, "-1"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Verified"); crw.put(VALUE, "2"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Verified"); crw.put(VALUE, "1"); approvals.add(crw); crw = new JSONObject(); crw.put(TYPE, "Verified"); crw.put(VALUE, "-1"); approvals.add(crw); currentPatchSet.put(APPROVALS, approvals); JSONObject patchSet1 = new JSONObject(); patchSet1.put(NUMBER, "1"); patchSet1.put(REVISION, "009365b77a69cd5ecd05a699b19213682f7f8d79"); patchSet1.put(PARENTS, parents); patchSet1.put(REF, "refs/changes/00/100/1"); patchSet1.put(UPLOADER, jsonAccount); patchSet1.put(CREATED_ON, createdOn2); patchSet1.put(AUTHOR, jsonAccount); JSONObject patchSet2 = new JSONObject(); patchSet2.put(NUMBER, "2"); patchSet2.put(REVISION, "87861b77a7614f8e6da19b017c588b741911983c"); patchSet2.put(PARENTS, parents); patchSet2.put(REF, "refs/changes/00/100/1"); patchSet2.put(UPLOADER, jsonAccount); patchSet2.put(CREATED_ON, createdOn1); patchSet2.put(AUTHOR, jsonAccount); JSONArray patchSets = new JSONArray(); patchSets.add(patchSet1); patchSets.add(patchSet2); JSONObject change = new JSONObject(); change.put(PROJECT, "project"); change.put(BRANCH, "branch"); change.put(ID, "I2343434344"); change.put(NUMBER, "100"); change.put(SUBJECT, "subject"); change.put(OWNER, jsonAccount); change.put(URL, "http://localhost:8080"); change.put(COMMIT_MESSAGE, "Change"); change.put(CREATED_ON, createdOn2); change.put(LAST_UPDATED, lastUpdated); change.put("open", true); change.put(STATUS, "NEW"); change.put("currentPatchSet", currentPatchSet); change.put("patchSets", patchSets); System.out.println("Starting QueryAllPatchSets: " + getCommand()); try { PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(getOutputStream(), "UTF-8"))); System.out.println("Sending: " + change); out.println(change); out.flush(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } this.stop(0); } } /** * A Command that prints a project and then exits with 0 and is destroyed. */ public static class SendOneProjectCommand extends CommandMock { /** * Standard constructor. * * @param command the command */ public SendOneProjectCommand(String command) { super(command); } @Override public void start(final Environment environment) throws IOException { String line = "abcProject"; System.out.println("Starting PL-command: " + getCommand()); try { PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(getOutputStream(), "UTF-8"))); System.out.println("Sending: " + line); out.println(line); out.flush(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } this.stop(0); this.destroy(); } } /** * A Command that prints 2 projects and then exits with 0. */ public static class SendTwoProjectsCommand extends CommandMock { /** * Standard constructor. * * @param command the command */ public SendTwoProjectsCommand(String command) { super(command); } @Override public void start(final Environment environment) throws IOException { String line = "abcProject"; String line2 = "defProject"; System.out.println("Starting PL-command: " + getCommand()); try { PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(getOutputStream(), "UTF-8"))); System.out.println("Sending: " + line); out.println(line); System.out.println("Sending: " + line2); out.println(line2); out.flush(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } this.stop(0); } } /** * Utility class for looking up and creating commands. * * @see SshdServerMock#findAndCreateCommand(String) */ public static class CommandLookup { private Class<? extends CommandMock> cmdClass; private Pattern commandPattern; private boolean oneShot; private Constructor<? extends CommandMock> constructor; private Object[] arguments; /** * Standard constructor. * * @param cmdClass the class of the command to create. * @param commandPattern a regular expression matching a command the creation should be performed on. * @param oneShot if this command should only be returned the first time it is called for. * @param constructor the constructor of the command to call. * @param arguments the arguments to the constructor except for the first actual command. * @see SshdServerMock#returnCommandFor(String, Class) * @see SshdServerMock#returnCommandFor(String, Class, Object[], Class[]) */ public CommandLookup(Class<? extends CommandMock> cmdClass, Pattern commandPattern, boolean oneShot, Constructor<? extends CommandMock> constructor, Object... arguments) { this.cmdClass = cmdClass; this.commandPattern = commandPattern; this.oneShot = oneShot; this.constructor = constructor; this.arguments = arguments; } /** * Standard constructor. * * @param cmdClass the class of the command to create. * @param commandPattern a regular expression matching a command the creation should be performed on. * @param oneShot if this command should only be returned the first time it is called for. * @param constructor the constructor of the command to call. * @param arguments the arguments to the constructor except for the first actual command. * @see SshdServerMock#returnCommandFor(String, Class) * @see SshdServerMock#returnCommandFor(String, Class, Object[], Class[]) */ public CommandLookup(Class<? extends CommandMock> cmdClass, String commandPattern, boolean oneShot, Constructor<? extends CommandMock> constructor, Object... arguments) { this(cmdClass, Pattern.compile(commandPattern), oneShot, constructor, arguments); } /** * If the given command matches the pattern. * * @param command the command * @return true if so. */ public boolean isCommand(String command) { return commandPattern.matcher(command).find(); } /** * If this command should only be returned the first time it is called for. * @return true if so */ public boolean isOneShot() { return oneShot; } /** * Creates a new instance of the command with all it's parameters. * * @param command the first parameter to the constructor. * @return a new instance of the command. */ public CommandMock newInstance(String command) { try { if (arguments == null || arguments.length <= 0) { return constructor.newInstance(command); } else { Object[] args = new Object[arguments.length + 1]; args[0] = command; System.arraycopy(arguments, 0, args, 1, arguments.length); return constructor.newInstance(args); } } catch (Exception e) { throw new RuntimeException("Unpredicted reflection error. ", e); } } } }