From b3cd4d502ef17a46776eb77b8811a5c6c5207369 Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Tue, 31 Jul 2018 15:53:28 -0400 Subject: [PATCH 1/3] Enable Labels in Container Config - only exposes in core the opportunity to add labels - this PR does NOT - pass through labels from a base image (should be in followup) - enable frontend labels access (should be in followup) --- .../builder/BuildStepsIntegrationTest.java | 12 ++++++- .../jib/builder/steps/BuildImageStep.java | 1 + .../configuration/ContainerConfiguration.java | 30 ++++++++++++++++-- .../google/cloud/tools/jib/image/Image.java | 31 ++++++++++++++++--- .../json/ContainerConfigurationTemplate.java | 13 ++++++++ .../jib/image/json/ImageToJsonTranslator.java | 3 ++ .../configuration/BuildConfigurationTest.java | 14 +++++++++ .../ContainerConfigurationTemplateTest.java | 4 +++ .../image/json/ImageToJsonTranslatorTest.java | 1 + .../test/resources/json/containerconfig.json | 2 +- .../json/translated_ocimanifest.json | 2 +- .../json/translated_v22manifest.json | 2 +- 12 files changed, 105 insertions(+), 10 deletions(-) diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java index 43409a919a..6a480af023 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java @@ -31,6 +31,7 @@ import com.google.cloud.tools.jib.image.InvalidImageReferenceException; import com.google.cloud.tools.jib.registry.LocalRegistry; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.io.Resources; import java.io.IOException; import java.net.URISyntaxException; @@ -147,8 +148,9 @@ public void testSteps_forBuildToDockerDaemon() new Caches.Initializer(cacheDirectory, false, cacheDirectory, false)) .run(); + String dockerContainerConfig = new Command("docker", "inspect", "testdocker").run(); Assert.assertThat( - new Command("docker", "inspect", "testdocker").run(), + dockerContainerConfig, CoreMatchers.containsString( " \"ExposedPorts\": {\n" + " \"1000/tcp\": {},\n" @@ -156,6 +158,13 @@ public void testSteps_forBuildToDockerDaemon() + " \"2001/tcp\": {},\n" + " \"2002/tcp\": {},\n" + " \"3000/udp\": {}")); + Assert.assertThat( + dockerContainerConfig, + CoreMatchers.containsString( + " \"Labels\": {\n" + + " \"key1\": \"value1\",\n" + + " \"key2\": \"value2\"\n" + + " }")); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", "testdocker").run()); } @@ -199,6 +208,7 @@ private BuildConfiguration getBuildConfiguration( .setProgramArguments(Collections.singletonList("An argument.")) .setExposedPorts( ExposedPortsParser.parse(Arrays.asList("1000", "2000-2002/tcp", "3000/udp"))) + .setLabels(ImmutableMap.of("key1", "value1", "key2", "value2")) .build(); return BuildConfiguration.builder(logger) .setBaseImageConfiguration(baseImageConfiguration) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java index ebecdb31e1..87da8a3c77 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java @@ -114,6 +114,7 @@ private Image afterCachedLayersSteps() imageBuilder.setEntrypoint(containerConfiguration.getEntrypoint()); imageBuilder.setJavaArguments(containerConfiguration.getProgramArguments()); imageBuilder.setExposedPorts(containerConfiguration.getExposedPorts()); + imageBuilder.setLabels(containerConfiguration.getLabels()); } // Gets the container configuration content descriptor. diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ContainerConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ContainerConfiguration.java index d8d750c209..fc1691ac63 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ContainerConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ContainerConfiguration.java @@ -37,6 +37,7 @@ public static class Builder { @Nullable private ImmutableList programArguments; @Nullable private ImmutableMap environmentMap; @Nullable private ImmutableList exposedPorts; + @Nullable private ImmutableMap labels; /** * Sets the image creation time. @@ -98,6 +99,23 @@ public Builder setExposedPorts(@Nullable List exposedPorts) { return this; } + /** + * Sets the container's exposed ports. + * + * @param labels the map of labels + * @return this + */ + public Builder setLabels(@Nullable Map labels) { + if (labels == null) { + this.labels = null; + } else { + Preconditions.checkArgument(!Iterables.any(labels.keySet(), Objects::isNull)); + Preconditions.checkArgument(!Iterables.any(labels.values(), Objects::isNull)); + this.labels = ImmutableMap.copyOf(labels); + } + return this; + } + /** * Sets the container entrypoint. * @@ -121,7 +139,7 @@ public Builder setEntrypoint(@Nullable List entrypoint) { */ public ContainerConfiguration build() { return new ContainerConfiguration( - creationTime, entrypoint, programArguments, environmentMap, exposedPorts); + creationTime, entrypoint, programArguments, environmentMap, exposedPorts, labels); } private Builder() {} @@ -141,18 +159,21 @@ public static Builder builder() { @Nullable private final ImmutableList programArguments; @Nullable private final ImmutableMap environmentMap; @Nullable private final ImmutableList exposedPorts; + @Nullable private final ImmutableMap labels; private ContainerConfiguration( Instant creationTime, @Nullable ImmutableList entrypoint, @Nullable ImmutableList programArguments, @Nullable ImmutableMap environmentMap, - @Nullable ImmutableList exposedPorts) { + @Nullable ImmutableList exposedPorts, + @Nullable ImmutableMap labels) { this.creationTime = creationTime; this.entrypoint = entrypoint; this.programArguments = programArguments; this.environmentMap = environmentMap; this.exposedPorts = exposedPorts; + this.labels = labels; } public Instant getCreationTime() { @@ -178,4 +199,9 @@ public ImmutableMap getEnvironmentMap() { public ImmutableList getExposedPorts() { return exposedPorts; } + + @Nullable + public ImmutableMap getLabels() { + return labels; + } } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java index 60d3c2d7f3..bdbf8c9ef3 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java @@ -37,6 +37,7 @@ public static class Builder { @Nullable private ImmutableList entrypoint; @Nullable private ImmutableList javaArguments; @Nullable private ImmutableList exposedPorts; + @Nullable private ImmutableMap labels; /** * Sets the image creation time. @@ -110,15 +111,26 @@ public Builder setJavaArguments(@Nullable List javaArguments) { * @param exposedPorts the list of exposed ports to add * @return this */ - public Builder setExposedPorts(@Nullable ImmutableList exposedPorts) { + public Builder setExposedPorts(@Nullable List exposedPorts) { if (exposedPorts == null) { this.exposedPorts = null; } else { - this.exposedPorts = exposedPorts; + this.exposedPorts = ImmutableList.copyOf(exposedPorts); } return this; } + /** + * Sets the items in the "ExposedPorts" field in the container configuration. + * + * @param labels that map of labels to add + * @return this + */ + public Builder setLabels(@Nullable Map labels) { + this.labels = (labels == null) ? null : ImmutableMap.copyOf(labels); + return this; + } + /** * Adds a layer to the image. * @@ -138,7 +150,8 @@ public Image build() { environmentBuilder.build(), entrypoint, javaArguments, - exposedPorts); + exposedPorts, + labels); } } @@ -164,19 +177,24 @@ public static Builder builder() { /** Ports that the container listens on. */ @Nullable private final ImmutableList exposedPorts; + /** Labels on the container configuration */ + @Nullable private final ImmutableMap labels; + private Image( @Nullable Instant created, ImageLayers layers, @Nullable ImmutableMap environment, @Nullable ImmutableList entrypoint, @Nullable ImmutableList javaArguments, - @Nullable ImmutableList exposedPorts) { + @Nullable ImmutableList exposedPorts, + @Nullable ImmutableMap labels) { this.created = created; this.layers = layers; this.environment = environment; this.entrypoint = entrypoint; this.javaArguments = javaArguments; this.exposedPorts = exposedPorts; + this.labels = labels; } @Nullable @@ -204,6 +222,11 @@ public ImmutableList getExposedPorts() { return exposedPorts; } + @Nullable + public ImmutableMap getLabels() { + return labels; + } + public ImmutableList getLayers() { return layers.getLayers(); } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java index 9d8f0f2b4f..6eae869a42 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java @@ -40,6 +40,7 @@ * "Entrypoint": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], * "Cmd": ["arg1", "arg2"] * "ExposedPorts": { "6000/tcp":{}, "8000/tcp":{}, "9000/tcp":{} } + * "Labels": { "com.example.label": "value" } * }, * "rootfs": { * "diff_ids": [ @@ -87,6 +88,9 @@ private static class ConfigurationObjectTemplate implements JsonTemplate { /** Network ports the container exposes. */ @Nullable private Map> ExposedPorts; + + /** Labels. */ + @Nullable private Map Labels; } /** @@ -125,6 +129,10 @@ public void setContainerExposedPorts(@Nullable Map> exposedPor config.ExposedPorts = exposedPorts; } + public void setContainerLabels(@Nullable Map labels) { + config.Labels = labels; + } + public void addLayerDiffId(DescriptorDigest diffId) { rootfs.diff_ids.add(diffId); } @@ -158,6 +166,11 @@ List getContainerCmd() { return config.ExposedPorts; } + @Nullable + Map getContainerLabels() { + return config.Labels; + } + @VisibleForTesting DescriptorDigest getLayerDiffId(int index) { return rootfs.diff_ids.get(index); diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java index 8e07d870a4..824bbc6229 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java @@ -130,6 +130,9 @@ public Blob getContainerConfigurationBlob() { // Sets the exposed ports. template.setContainerExposedPorts(portListToMap(image.getExposedPorts())); + // Sets the labels. + template.setContainerLabels(image.getLabels()); + // Serializes into JSON. return JsonTemplateMapper.toBlob(template); } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/BuildConfigurationTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/BuildConfigurationTest.java index c82c04fc2f..3a90773b10 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/BuildConfigurationTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/BuildConfigurationTest.java @@ -60,6 +60,7 @@ public void testBuilder() { Map expectedEnvironment = ImmutableMap.of("key", "value"); ImmutableList expectedExposedPorts = ImmutableList.of(new Port(1000, Protocol.TCP), new Port(2000, Protocol.TCP)); + Map expectedLabels = ImmutableMap.of("key1", "value1", "key2", "value2"); Class expectedTargetFormat = OCIManifestTemplate.class; CacheConfiguration expectedApplicationLayersCacheConfiguration = CacheConfiguration.forPath(Paths.get("application/layers")); @@ -90,6 +91,7 @@ public void testBuilder() { .setProgramArguments(expectedJavaArguments) .setEnvironment(expectedEnvironment) .setExposedPorts(expectedExposedPorts) + .setLabels(expectedLabels) .build(); BuildConfiguration.Builder buildConfigurationBuilder = BuildConfiguration.builder(Mockito.mock(BuildLogger.class)) @@ -134,6 +136,7 @@ public void testBuilder() { expectedEnvironment, buildConfiguration.getContainerConfiguration().getEnvironmentMap()); Assert.assertEquals( expectedExposedPorts, buildConfiguration.getContainerConfiguration().getExposedPorts()); + Assert.assertEquals(expectedLabels, buildConfiguration.getContainerConfiguration().getLabels()); Assert.assertEquals(expectedTargetFormat, buildConfiguration.getTargetFormat()); Assert.assertEquals( expectedApplicationLayersCacheConfiguration, @@ -250,6 +253,17 @@ public void testBuilder_nullValues() { Assert.assertNull(ex.getMessage()); } + // Labels element should not be null. + try { + Map badLabels = new HashMap<>(); + badLabels.put("label-key", null); + BuildConfiguration.builder(Mockito.mock(BuildLogger.class)) + .setContainerConfiguration(ContainerConfiguration.builder().setLabels(badLabels).build()); + Assert.fail("The IllegalArgumentException should be thrown."); + } catch (IllegalArgumentException ex) { + Assert.assertNull(ex.getMessage()); + } + // Environment keys element should not be null. Map nullKeyMap = new HashMap<>(); nullKeyMap.put(null, "value"); diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java index fd383447d4..e8f3a7acbc 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java @@ -57,6 +57,7 @@ public void testToJson() throws IOException, URISyntaxException, DigestException ImmutableMap.of(), "3000/udp", ImmutableMap.of())); + containerConfigJson.setContainerLabels(ImmutableMap.of("key1", "value1", "key2", "value2")); containerConfigJson.addLayerDiffId( DescriptorDigest.fromDigest( @@ -85,6 +86,9 @@ public void testFromJson() throws IOException, URISyntaxException, DigestExcepti Arrays.asList("some", "entrypoint", "command"), containerConfigJson.getContainerEntrypoint()); Assert.assertEquals(Arrays.asList("arg1", "arg2"), containerConfigJson.getContainerCmd()); + Assert.assertEquals( + ImmutableMap.of("key1", "value1", "key2", "value2"), + containerConfigJson.getContainerLabels()); Assert.assertEquals( DescriptorDigest.fromDigest( "sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"), diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java index 8e6b3e2451..66945fbef4 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java @@ -65,6 +65,7 @@ public void setUp() throws DigestException, LayerPropertyNotFoundException { new Port(1000, Protocol.TCP), new Port(2000, Protocol.TCP), new Port(3000, Protocol.UDP))); + testImageBuilder.setLabels(ImmutableMap.of("key1", "value1", "key2", "value2")); DescriptorDigest fakeDigest = DescriptorDigest.fromDigest( diff --git a/jib-core/src/test/resources/json/containerconfig.json b/jib-core/src/test/resources/json/containerconfig.json index be521e6341..2ae9606472 100644 --- a/jib-core/src/test/resources/json/containerconfig.json +++ b/jib-core/src/test/resources/json/containerconfig.json @@ -1 +1 @@ -{"created":"1970-01-01T00:00:20Z","architecture":"amd64","os":"linux","config":{"Env":["VAR1=VAL1","VAR2=VAL2"],"Entrypoint":["some","entrypoint","command"],"Cmd":["arg1","arg2"],"ExposedPorts":{"1000/tcp":{},"2000/tcp":{},"3000/udp":{}}},"rootfs":{"type":"layers","diff_ids":["sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"]}} \ No newline at end of file +{"created":"1970-01-01T00:00:20Z","architecture":"amd64","os":"linux","config":{"Env":["VAR1=VAL1","VAR2=VAL2"],"Entrypoint":["some","entrypoint","command"],"Cmd":["arg1","arg2"],"ExposedPorts":{"1000/tcp":{},"2000/tcp":{},"3000/udp":{}},"Labels":{"key1":"value1","key2":"value2"}},"rootfs":{"type":"layers","diff_ids":["sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"]}} \ No newline at end of file diff --git a/jib-core/src/test/resources/json/translated_ocimanifest.json b/jib-core/src/test/resources/json/translated_ocimanifest.json index 07e5cbde08..01a2f68253 100644 --- a/jib-core/src/test/resources/json/translated_ocimanifest.json +++ b/jib-core/src/test/resources/json/translated_ocimanifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:1bc0730d8135d29caa0e0c5b502164195afcab6494e1b024e419dc9d591d778d","size":353},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:b988b86bf80435bdfe7b2f361f5e5838bdf2abd5dcb5ff298122504f8fb80e95","size":396},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file diff --git a/jib-core/src/test/resources/json/translated_v22manifest.json b/jib-core/src/test/resources/json/translated_v22manifest.json index 153f896ef7..18641bc137 100644 --- a/jib-core/src/test/resources/json/translated_v22manifest.json +++ b/jib-core/src/test/resources/json/translated_v22manifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:1bc0730d8135d29caa0e0c5b502164195afcab6494e1b024e419dc9d591d778d","size":353},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:b988b86bf80435bdfe7b2f361f5e5838bdf2abd5dcb5ff298122504f8fb80e95","size":396},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file From 2cfbe275290aeab1684aec9bd53020c20afaa36f Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Tue, 31 Jul 2018 17:45:59 -0400 Subject: [PATCH 2/3] comment cleanup --- .../cloud/tools/jib/configuration/ContainerConfiguration.java | 2 +- .../src/main/java/com/google/cloud/tools/jib/image/Image.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ContainerConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ContainerConfiguration.java index fc1691ac63..2170ca4e4b 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ContainerConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ContainerConfiguration.java @@ -100,7 +100,7 @@ public Builder setExposedPorts(@Nullable List exposedPorts) { } /** - * Sets the container's exposed ports. + * Sets the container's labels. * * @param labels the map of labels * @return this diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java index bdbf8c9ef3..34806b9a62 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java @@ -121,7 +121,7 @@ public Builder setExposedPorts(@Nullable List exposedPorts) { } /** - * Sets the items in the "ExposedPorts" field in the container configuration. + * Sets the items in the "Labels" field in the container configuration. * * @param labels that map of labels to add * @return this From ce1ca71a8bf1b9d3b046e2c6a5f6c361fb27f37d Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Wed, 1 Aug 2018 14:11:06 -0400 Subject: [PATCH 3/3] cleanup null values test on labels --- .../tools/jib/configuration/BuildConfigurationTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/BuildConfigurationTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/BuildConfigurationTest.java index 3a90773b10..a97b44570d 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/BuildConfigurationTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/BuildConfigurationTest.java @@ -254,11 +254,10 @@ public void testBuilder_nullValues() { } // Labels element should not be null. + Map badLabels = new HashMap<>(); + badLabels.put("label-key", null); try { - Map badLabels = new HashMap<>(); - badLabels.put("label-key", null); - BuildConfiguration.builder(Mockito.mock(BuildLogger.class)) - .setContainerConfiguration(ContainerConfiguration.builder().setLabels(badLabels).build()); + ContainerConfiguration.builder().setLabels(badLabels); Assert.fail("The IllegalArgumentException should be thrown."); } catch (IllegalArgumentException ex) { Assert.assertNull(ex.getMessage());