/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.plugin.docker.compose.yaml; import com.fasterxml.jackson.dataformat.yaml.snakeyaml.reader.ReaderException; import org.eclipse.che.plugin.docker.compose.ComposeEnvironment; import org.eclipse.che.plugin.docker.compose.ComposeServiceImpl; import org.mockito.InjectMocks; import org.mockito.testng.MockitoTestNGListener; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import java.util.List; import java.util.Map; import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; /** * Test deserialization field {@link ComposeServiceImpl#command} * by {@link org.eclipse.che.plugin.docker.compose.yaml.deserializer.CommandDeserializer} * in the {@link ComposeEnvironmentParser}. * * @author Alexander Andrienko */ @Listeners(MockitoTestNGListener.class) public class CommandDeserializerTest { @InjectMocks private ComposeEnvironmentParser composeEnvironmentParser; private static final String RECIPE_WITHOUT_COMMAND_VALUE = "services:\n" + " machine1:\n" + " image: codenvy/mysql\n" + " environment:\n" + " MYSQL_USER: petclinic\n" + " MYSQL_PASSWORD: password\n" + " mem_limit: 2147483648\n" + " command: %s\n" + //<- test target " expose: [4403, 5502]"; @Test(dataProvider = "validCommand") public void composeServiceCommandShouldBeParsedSuccessfully(String command, List<String> commandWords, int commandNumberOfWords) throws Exception { String content = format(RECIPE_WITHOUT_COMMAND_VALUE, command); ComposeEnvironment composeEnvironment = composeEnvironmentParser.parse(content, "application/x-yaml"); assertEquals(composeEnvironment.getServices().size(), 1); ComposeServiceImpl service = composeEnvironment.getServices().get("machine1"); assertEquals(service.getImage(), "codenvy/mysql"); assertEquals(service.getMemLimit().longValue(), 2147483648L); Map<String, String> environment = service.getEnvironment(); assertEquals(environment.size(), 2); assertEquals(environment.get("MYSQL_USER"), "petclinic"); assertEquals(environment.get("MYSQL_PASSWORD"), "password"); assertTrue(service.getExpose().containsAll(asList("4403", "5502"))); assertTrue(service.getCommand().containsAll(commandWords)); assertEquals(service.getCommand().size(), commandNumberOfWords); } @DataProvider(name = "validCommand") private Object[][] validCommand() { return new Object[][] { //allow command in one line {"service mysql start", asList("service", "mysql", "start"), 3}, {"service mysql start && tail -f /dev/null", asList("service", "mysql", "start", "&&", "tail", "-f", "/dev/null"), 7}, {"service mysql start", asList("service", "mysql", "start"), 3}, {"service mysql start ", asList("service", "mysql", "start"), 3}, {"service mysql start ", asList("service", "mysql", "start"), 3}, //allow break line feature {"| \n" + " service mysql\n" + " restart", asList("service", "mysql", "restart"), 3}, {"| \r" + " service mysql\r" + " restart", asList("service", "mysql", "restart"), 3}, {"| \r\n" + " service mysql\r\n" + " restart", asList("service", "mysql", "restart"), 3}, {"| \n\n" + " service mysql\n\n" + " restart", asList("service", "mysql", "restart"), 3}, {"| \n \n" + " service mysql\n \n" + " restart", asList("service", "mysql", "restart"), 3}, {"> \n \n" + " service mysql\n \n" + " restart", asList("service", "mysql", "restart"), 3}, {"> \n \n" + " ls -a\n \n" + " -i -p", asList("ls", "-a", "-i", "-p"), 4}, //allow list command words //first form {"[service, mysql, start]", asList("service", "mysql", "start"), 3}, {"[service, mysql, start, '&&', tail, -f, /dev/null]", asList("service", "mysql", "start", "&&", "tail", "-f", "/dev/null"), 7}, //second form {"\n" + " - tail\n" + " - -f\n" + " - /dev/null", asList("tail", "-f", "/dev/null"), 3}, {"\n" + " - service\n" + " - mysql\n" + " - start\n" + " - '&&'\n" + " - tail\n" + " - -f\n" + " - /dev/null\n", asList("service", "mysql", "start", "&&", "tail", "-f", "/dev/null"), 7}, //Some special symbol should be accessible in case line was wrapped by quotes {"\"echo ${PWD}\"", asList("echo", "${PWD}"), 2}, {"\"(Test)\"", singletonList("(Test)"), 1}, {"", singletonList(""), 1}, }; } @Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "inValidCommand") public void composeServiceCommandShouldBeParsedFailed(String command) throws Exception { String content = format(RECIPE_WITHOUT_COMMAND_VALUE, command); try { composeEnvironmentParser.parse(content, "application/x-yaml"); } catch (Exception e) { System.out.println(e.getLocalizedMessage()); throw e; } } @DataProvider(name = "inValidCommand") private Object[][] inValidCommand() { return new Object[][] { {"\n |" + " - tail\n" + " - -f\n" + " - /dev/null"}, {"\n |" + " - tail\n" + " -f\n" + " - /dev/null"}, {"\n >" + " - tail\n" + " -f\n" + " - /dev/null"}, {"{service mysql start}"}, {"[service, mysql, {start : test}]"}, {"[service, mysql, [start : test]]"}, {"service mysql \nstart"}, {"test : value"}, {"[service mysql start"}, }; } @Test(expectedExceptions = ReaderException.class, expectedExceptionsMessageRegExp = "special characters are not allowed", dataProvider = "inValidSymbols") public void symbolsShouldBeInvalidForYaml(String command) throws Exception { String content = format(RECIPE_WITHOUT_COMMAND_VALUE, command); try { composeEnvironmentParser.parse(content, "application/x-yaml"); } catch (Exception e) { System.out.println(e.getLocalizedMessage()); throw e; } } /** * Valid yaml Regex by specification Yaml 1.2 (for two bytes - UTF-16): * (\\x09|\\x0A|\\x0D|[\\x20-\\x7E]|\\x85|[\\xA0-\\xD7FF]|[\\xE000-\\xFFFD])+ */ @DataProvider(name = "inValidSymbols") private Object[][] inValidSymbols() { return new Object[][] { {"service mysql start\uFFFE"}, {"service mysql start\uDFFF"}, {"service mysql start\uD800"}, {"service mysql start\u009F"}, {"service mysql start\u0086"}, {"service mysql start\u0084"}, {"service mysql start\u0084"}, {"service mysql start\u007F"}, {"service mysql start\u001F"}, {"service mysql start\u000E"}, {"service mysql start\u000C"}, {"service mysql start\u000B"}, {"service mysql start\u0008"}, }; } }