/**
* Copyright 2015-2017 Linagora, Université Joseph Fourier, Floralis
*
* The present code is developed in the scope of the joint LINAGORA -
* Université Joseph Fourier - Floralis research program and is designated
* as a "Result" pursuant to the terms and conditions of the LINAGORA
* - Université Joseph Fourier - Floralis research program. Each copyright
* holder of Results enumerated here above fully & independently holds complete
* ownership of the complete Intellectual Property rights applicable to the whole
* of said Results, and may freely exploit it in any manner which does not infringe
* the moral rights of the other copyright holders.
*
* Licensed 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 net.roboconf.target.docker.internal;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
import org.ops4j.pax.url.mvn.MavenResolver;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.model.Capability;
import net.roboconf.core.utils.Utils;
import net.roboconf.target.api.TargetException;
/**
* @author Vincent Zurczak - Linagora
*/
public class DockerUtilsTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test( expected = TargetException.class )
public void testInvalidConfiguration_noImage_noGeneration() throws Exception {
Map<String,String> map = new HashMap<> ();
map.put( DockerHandler.ENDPOINT, "whatever" );
DockerUtils.createDockerClient( map );
}
@Test
public void testIncompleteConfiguration_noEndpoint_withImage() throws Exception {
Map<String,String> map = new HashMap<> ();
map.put( DockerHandler.IMAGE_ID, "whatever" );
DockerClient client = DockerUtils.createDockerClient( map );
Assert.assertNotNull( client );
}
@Test
public void testIncompleteConfiguration_noEndpoint_withGeneration() throws Exception {
Map<String,String> map = new HashMap<> ();
map.put( DockerHandler.GENERATE_IMAGE, "true" );
DockerClient client = DockerUtils.createDockerClient( map );
Assert.assertNotNull( client );
}
@Test
public void testPrepareParameter() throws Exception {
// Known types
String input = "whatever";
Assert.assertEquals( input, DockerUtils.prepareParameter( input, String.class ));
input = "50";
Assert.assertEquals( 50, DockerUtils.prepareParameter( input, int.class ));
Assert.assertEquals( 50L, DockerUtils.prepareParameter( input, long.class ));
input = "true";
Assert.assertEquals( true, DockerUtils.prepareParameter( input, boolean.class ));
input = "test1, test2,test3, test4 ";
Object result = DockerUtils.prepareParameter( input, String[].class );
Assert.assertEquals( String[].class, result.getClass());
String[] expectedString = { "test1", "test2", "test3", "test4" };
Assert.assertTrue( Arrays.deepEquals( expectedString, (String[]) result ));
input = "AUDIT_CONTROL, SYS_PTRACE";
Capability[] expectedCapabilities = new Capability[] {
Capability.AUDIT_CONTROL,
Capability.SYS_PTRACE
};
result = DockerUtils.prepareParameter( input, Capability[].class );
Assert.assertEquals( Capability[].class, result.getClass());
Assert.assertTrue( Arrays.deepEquals( expectedCapabilities, (Capability[]) result ));
// Unknown types
input = "0.4f";
Assert.assertEquals( input, DockerUtils.prepareParameter( input, double.class ));
}
@Test( expected = TargetException.class )
public void testPrepareParameter_invalidCapability() throws Exception {
String input = "AUDIT_CONTROL, read minds";
DockerUtils.prepareParameter( input, Capability[].class );
}
@Test
public void testConfigureOptions() throws Exception {
Map<String,String> options = new HashMap<> ();
options.put( "cap-drop", "AUDIT_CONTROL" );
options.put( "cap-add", "SYS_PTRACE, SYS_NICE" );
options.put( "hostname", "hello" );
options.put( "AttachStdin", "true" );
options.put( "MemorySwap", "50" );
options.put( "CpuShares", "2" );
options.put( "Memory", "1024" );
options.put( "env", "env1, env2, env3" );
Map<String,String> targetProperties = new HashMap<>( 1 );
targetProperties.put( DockerHandler.IMAGE_ID, "whatever" );
DockerClient dockerClient = DockerUtils.createDockerClient( targetProperties );
CreateContainerCmd cmd = dockerClient.createContainerCmd( "whatever, we won't execute it" );
DockerUtils.configureOptions( options, cmd );
Assert.assertTrue( cmd.isAttachStdin());
Assert.assertEquals( "hello", cmd.getHostName());
Assert.assertTrue( Arrays.deepEquals(
new Capability[] { Capability.SYS_PTRACE, Capability.SYS_NICE },
cmd.getCapAdd()));
Assert.assertTrue( Arrays.deepEquals(
new Capability[] { Capability.AUDIT_CONTROL },
cmd.getCapDrop()));
Assert.assertEquals( Long.valueOf( 50L ), cmd.getMemorySwap());
Assert.assertEquals( Long.valueOf( 1024L ), cmd.getMemory());
Assert.assertEquals( Integer.valueOf( 2 ), cmd.getCpuShares());
Assert.assertTrue( Arrays.deepEquals(
new String[] { "env1", "env2", "env3" },
cmd.getEnv()));
}
@Test( expected = TargetException.class )
public void testConfigureOptions_unknownOption() throws Exception {
Map<String,String> options = new HashMap<> ();
options.put( "what-is-this", "AUDIT_CONTROL" );
Map<String,String> targetProperties = new HashMap<>( 1 );
targetProperties.put( DockerHandler.IMAGE_ID, "whatever" );
DockerClient dockerClient = DockerUtils.createDockerClient( targetProperties );
CreateContainerCmd cmd = dockerClient.createContainerCmd( "whatever, we won't execute it" );
DockerUtils.configureOptions( options, cmd );
}
@Test( expected = TargetException.class )
public void testConfigureOptions_unsupportedOption() throws Exception {
Map<String,String> options = new HashMap<> ();
options.put( "ExposedPorts", "24, 25" );
Map<String,String> targetProperties = new HashMap<>( 1 );
targetProperties.put( DockerHandler.IMAGE_ID, "whatever" );
DockerClient dockerClient = DockerUtils.createDockerClient( targetProperties );
CreateContainerCmd cmd = dockerClient.createContainerCmd( "whatever, we won't execute it" );
DockerUtils.configureOptions( options, cmd );
}
@Test
public void testConfigureOptions_synonyms() throws Exception {
Map<String,String> targetProperties = new HashMap<>( 1 );
targetProperties.put( DockerHandler.IMAGE_ID, "whatever" );
DockerClient dockerClient = DockerUtils.createDockerClient( targetProperties );
CreateContainerCmd cmd = dockerClient.createContainerCmd( "whatever, we won't execute it" );
// First try
Map<String,String> options = new HashMap<>( 1 );
options.put( "cap-drop", "AUDIT_CONTROL" );
DockerUtils.configureOptions( options, cmd );
Assert.assertTrue( Arrays.deepEquals(
new Capability[] { Capability.AUDIT_CONTROL },
cmd.getCapDrop()));
// Second try
options = new HashMap<>( 1 );
options.put( "CapDrop", "SYS_PTRACE" );
DockerUtils.configureOptions( options, cmd );
Assert.assertTrue( Arrays.deepEquals(
new Capability[] { Capability.SYS_PTRACE },
cmd.getCapDrop()));
// Third try
options = new HashMap<>( 1 );
options.put( "--cap-drop", "SYS_NICE" );
DockerUtils.configureOptions( options, cmd );
Assert.assertTrue( Arrays.deepEquals(
new Capability[] { Capability.SYS_NICE },
cmd.getCapDrop()));
}
@Test
public void testParseRunExecLine() {
Assert.assertNull( DockerUtils.parseRunExecLine( null ));
Assert.assertNull( DockerUtils.parseRunExecLine( "" ));
Assert.assertNull( DockerUtils.parseRunExecLine( " " ));
List<String> args = DockerUtils.parseRunExecLine( "[ toto, titi" );
Assert.assertNull( args );
args = DockerUtils.parseRunExecLine( "[ toto, titi ]" );
Assert.assertEquals( 2, args.size());
Assert.assertTrue( args.contains( "toto" ));
Assert.assertTrue( args.contains( "titi" ));
args = DockerUtils.parseRunExecLine( "[ \"toto\", \"titi\" ]" );
Assert.assertEquals( 2, args.size());
Assert.assertTrue( args.contains( "toto" ));
Assert.assertTrue( args.contains( "titi" ));
}
@Test
public void testBuildRunCommand_defaultValue_emptyMessaging() {
List<String> args = DockerUtils.buildRunCommand( null, new HashMap<String,String>( 0 ), "app", "/root" );
Assert.assertEquals( 5, args.size());
Assert.assertTrue( args.get( 0 ).endsWith( "/start.sh" ));
Assert.assertEquals( "etc/net.roboconf.messaging..cfg", args.get( 1 ));
Assert.assertEquals( "agent.application-name=app", args.get( 2 ));
Assert.assertEquals( "agent.scoped-instance-path=/root", args.get( 3 ));
Assert.assertEquals( "agent.messaging-type=", args.get( 4 ));
// No messaging parameter, so no sixth argument
}
@Test
public void testBuildRunCommand_defaultValue_withMessaging() {
Map<String,String> messagingConfiguration = new LinkedHashMap<> ();
messagingConfiguration.put( DockerHandler.MESSAGING_TYPE, "bird" );
messagingConfiguration.put( "paper", "with somethig written on it" );
messagingConfiguration.put( "pen", "to write the answer" );
List<String> args = DockerUtils.buildRunCommand( null, messagingConfiguration, "app", "/root" );
Assert.assertEquals( 7, args.size());
Assert.assertTrue( args.get( 0 ).endsWith( "/start.sh" ));
Assert.assertEquals( "etc/net.roboconf.messaging.bird.cfg", args.get( 1 ));
Assert.assertEquals( "agent.application-name=app", args.get( 2 ));
Assert.assertEquals( "agent.scoped-instance-path=/root", args.get( 3 ));
Assert.assertEquals( "agent.messaging-type=bird", args.get( 4 ));
Assert.assertEquals( "msg.paper=with somethig written on it", args.get( 5 ));
Assert.assertEquals( "msg.pen=to write the answer", args.get( 6 ));
}
@Test
public void testBuildRunCommand_overriding_noCommand() {
Map<String,String> messagingConfiguration = new LinkedHashMap<> ();
messagingConfiguration.put( DockerHandler.MESSAGING_TYPE, "bird" );
messagingConfiguration.put( "paper", "with somethig written on it" );
messagingConfiguration.put( "pen", "to write the answer" );
List<String> args = DockerUtils.buildRunCommand( "[]", messagingConfiguration, "app", "/root" );
Assert.assertEquals( 0, args.size());
}
@Test
public void testBuildRunCommand_overriding_extraCommand() {
Map<String,String> messagingConfiguration = new LinkedHashMap<> ();
messagingConfiguration.put( DockerHandler.MESSAGING_TYPE, "bird" );
messagingConfiguration.put( "paper", "with somethig written on it" );
messagingConfiguration.put( "pen", "to write the answer" );
List<String> args = DockerUtils.buildRunCommand( "[ start.sh ]", messagingConfiguration, "app", "/root" );
Assert.assertEquals( 1, args.size());
Assert.assertEquals( "start.sh", args.get( 0 ));
}
@Test
public void testBuildRunCommand_overriding_mixCommand() {
Map<String,String> messagingConfiguration = new LinkedHashMap<> ();
messagingConfiguration.put( DockerHandler.MESSAGING_TYPE, "bird" );
messagingConfiguration.put( "paper", "with somethig written on it" );
messagingConfiguration.put( "pen", "to write the answer" );
List<String> args = DockerUtils.buildRunCommand(
"[ \"agent.application-name=$applicationName$\", \"start.sh\", \"$messagingType$\" ]",
messagingConfiguration, "app", "/root" );
Assert.assertEquals( 3, args.size());
Assert.assertEquals( "agent.application-name=app", args.get( 0 ));
Assert.assertEquals( "start.sh", args.get( 1 ));
Assert.assertEquals( "bird", args.get( 2 ));
}
@Test
public void testBuildRunCommand_overriding_mixCommandAndMessaging() {
Map<String,String> messagingConfiguration = new LinkedHashMap<> ();
messagingConfiguration.put( DockerHandler.MESSAGING_TYPE, "bird" );
messagingConfiguration.put( "paper", "with somethig written on it" );
messagingConfiguration.put( "pen", "to write the answer" );
List<String> args = DockerUtils.buildRunCommand(
"[ \"$msgConfig$\", \"start.sh\", \"etc/net.roboconf.messaging.$messagingType$.cfg\" ]",
messagingConfiguration, "app", "/root" );
Assert.assertEquals( 4, args.size());
Assert.assertEquals( "msg.paper=with somethig written on it", args.get( 0 ));
Assert.assertEquals( "msg.pen=to write the answer", args.get( 1 ));
Assert.assertEquals( "start.sh", args.get( 2 ));
Assert.assertEquals( "etc/net.roboconf.messaging.bird.cfg", args.get( 3 ));
}
@Test
public void testExtractBoolean() {
Assert.assertEquals( true, DockerUtils.extractBoolean( Boolean.TRUE ));
Assert.assertEquals( false, DockerUtils.extractBoolean( Boolean.FALSE ));
Assert.assertEquals( false, DockerUtils.extractBoolean( null ));
}
@Test
public void testDownloadRemotePackage() throws Exception {
// Copy a usual URL
File toCopy = this.folder.newFile();
Utils.writeStringInto( "this", toCopy );
File targetFile = this.folder.newFile();
DockerUtils.downloadRemotePackage( toCopy.toURI().toString(), targetFile, null );
Assert.assertEquals( "this", Utils.readFileContent( targetFile ));
// Maven resolver
MavenResolver mavenResolver = Mockito.mock( MavenResolver.class );
Mockito.when( mavenResolver.resolve( Mockito.anyString())).thenReturn( targetFile );
DockerUtils.downloadRemotePackage( "mvn://something", targetFile, mavenResolver );
Mockito.verify( mavenResolver, Mockito.only()).resolve( "mvn://something" );
// Null resolver
try {
DockerUtils.downloadRemotePackage( "mvn://something", targetFile, null );
Assert.fail( "An exception was expected." );
} catch( Exception e ) {
// nothing
}
}
}