package org.jenkinsci.plugins.dockerbuildstep.util; import static com.github.dockerjava.api.model.AccessMode.ro; import static com.github.dockerjava.api.model.AccessMode.rw; import static org.junit.Assert.assertEquals; import org.junit.Test; import com.github.dockerjava.api.model.AccessMode; import com.github.dockerjava.api.model.Bind; /** * Defines legal syntax for entering bind mount definitions ({@link Bind}s). */ public class BindParserTest { @Test public void defaultAccessMode_blank() { assertCreatesBinds(input("/host /container"), expected("/host", "/container", AccessMode.DEFAULT)); } @Test public void readWrite_blank() { assertCreatesBinds(input("/host /container rw"), expected("/host", "/container", rw)); } @Test public void readOnly_blank() { assertCreatesBinds(input("/host /container ro"), expected("/host", "/container", ro)); } @Test(expected = IllegalArgumentException.class) public void invalidAccessMode_blank() { BindParser.parse("/host /container xx"); } @Test public void defaultAccessMode_colon() { assertCreatesBinds(input("/host:/container"), expected("/host", "/container", AccessMode.DEFAULT)); } @Test public void readWrite_colon() { assertCreatesBinds(input("/host:/container:rw"), expected("/host", "/container", rw)); } @Test public void readOnly_colon() { assertCreatesBinds(input("/host:/container:ro"), expected("/host", "/container", ro)); } @Test public void pathWithBlanks_colon() { // not sure if this would work in Docker and why anybody should want to do this, // but let's allow this as well. assertCreatesBinds(input("/host with blanks:/container with blanks:ro"), expected("/host with blanks", "/container with blanks", ro)); } @Test(expected = IllegalArgumentException.class) public void invalidAccessMode_colon() { BindParser.parse("/host:/container:xx"); } @Test(expected = IllegalArgumentException.class) public void parseInvalidInput() { BindParser.parse("nonsense"); } @Test public void parseEmptyString() { assertEquals(0, BindParser.parse("").length); } @Test public void twoBindings_UnixStyle() { assertCreatesBinds(input("/host1:/container1:rw\n/host2:/container2:ro"), expected("/host1", "/container1", rw), expected("/host2", "/container2", ro)); } @Test public void twoBindings_DosStyle() { assertCreatesBinds(input("/host1:/container1:rw\r\n/host2:/container2:ro"), expected("/host1", "/container1", rw), expected("/host2", "/container2", ro)); } private void assertCreatesBinds(String input, Expected... expected) { Bind[] parsed = BindParser.parse(input); assertEquals("wrong number of Binds created", expected.length, parsed.length); for (int i = 0; i < parsed.length; i++) { assertEquals("Bind #" + i, expected[i].hostPath, parsed[i].getPath()); assertEquals("Bind #" + i, expected[i].containerPath, parsed[i].getVolume().getPath()); assertEquals("Bind #" + i, expected[i].accessMode, parsed[i].getAccessMode()); } } /** * Designates the argument as input for parsing.<br> * For increased readability. * * @param input the input string for the parser * @return the input string, but semantically enhanced */ private static String input(String input) { return input; } /** * Designates the arguments as the expected result of parsing.<br> * For increased readability. * * @param hostPath the expected host path of the parsing result * @param containerPath the expected container path of the parsing result * @param accessMode the access mode of the parsing result * @return a container object for the expected values */ private static Expected expected(String hostPath, String containerPath, AccessMode accessMode) { return new Expected(hostPath, containerPath, accessMode); } /** Parameter object for expected parsing results */ private static class Expected { public final String hostPath; public final String containerPath; public final AccessMode accessMode; public Expected(String hostPath, String containerPath, AccessMode accessMode) { this.hostPath = hostPath; this.containerPath = containerPath; this.accessMode = accessMode; } } }