/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 gobblin.runtime.template;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigFactory;
import gobblin.runtime.api.JobCatalogWithTemplates;
import gobblin.runtime.api.JobTemplate;
import gobblin.runtime.api.SpecNotFoundException;
import lombok.AllArgsConstructor;
public class InheritingJobTemplateTest {
@Test
public void testSimpleInheritance() throws Exception {
TestTemplate template1 = new TestTemplate(new URI("template1"), Lists.<JobTemplate>newArrayList(), ImmutableMap.of("key1", "value1"),
Lists.newArrayList("required"));
TestTemplate template2 = new TestTemplate(new URI("template2"), Lists.<JobTemplate>newArrayList(template1), ImmutableMap.of("key2", "value2"),
Lists.newArrayList("required2"));
Collection<String> required = template2.getRequiredConfigList();
Assert.assertEquals(required.size(), 2);
Assert.assertTrue(required.contains("required"));
Assert.assertTrue(required.contains("required2"));
Config rawTemplate = template2.getRawTemplateConfig();
Assert.assertEquals(rawTemplate.getString("key1"), "value1");
Assert.assertEquals(rawTemplate.getString("key2"), "value2");
Config resolved = template2.getResolvedConfig(ConfigFactory.parseMap(ImmutableMap.of("required", "r1", "required2", "r2")));
Assert.assertEquals(resolved.getString("key1"), "value1");
Assert.assertEquals(resolved.getString("key2"), "value2");
Assert.assertEquals(resolved.getString("required"), "r1");
Assert.assertEquals(resolved.getString("required2"), "r2");
try {
// should throw exception because missing required property
resolved = template2.getResolvedConfig(ConfigFactory.parseMap(ImmutableMap.of("required", "r1")));
Assert.fail();
} catch (JobTemplate.TemplateException te) {
// expected
}
}
@Test
public void testMultiInheritance() throws Exception {
TestTemplate template1 = new TestTemplate(new URI("template1"), Lists.<JobTemplate>newArrayList(), ImmutableMap.of("key1", "value1"),
Lists.newArrayList("required"));
TestTemplate template2 = new TestTemplate(new URI("template2"), Lists.<JobTemplate>newArrayList(), ImmutableMap.of("key2", "value2"),
Lists.newArrayList("required2"));
TestTemplate inheriting = new TestTemplate(new URI("inheriting"), Lists.<JobTemplate>newArrayList(template1, template2), ImmutableMap.<String, String>of(),
Lists.<String>newArrayList());
Collection<String> required = inheriting.getRequiredConfigList();
Assert.assertEquals(required.size(), 2);
Assert.assertTrue(required.contains("required"));
Assert.assertTrue(required.contains("required2"));
Config rawTemplate = inheriting.getRawTemplateConfig();
Assert.assertEquals(rawTemplate.getString("key1"), "value1");
Assert.assertEquals(rawTemplate.getString("key2"), "value2");
Config resolved = inheriting.getResolvedConfig(ConfigFactory.parseMap(ImmutableMap.of("required", "r1", "required2", "r2")));
Assert.assertEquals(resolved.getString("key1"), "value1");
Assert.assertEquals(resolved.getString("key2"), "value2");
Assert.assertEquals(resolved.getString("required"), "r1");
Assert.assertEquals(resolved.getString("required2"), "r2");
}
@Test
public void testLoopInheritance() throws Exception {
JobCatalogWithTemplates catalog = Mockito.mock(JobCatalogWithTemplates.class);
Mockito.when(catalog.getTemplate(new URI("template2"))).thenAnswer(
new TestTemplateAnswer(Lists.newArrayList(new URI("template3")), ImmutableMap.of("key2", "value2"),
Lists.<String>newArrayList(), catalog));
Mockito.when(catalog.getTemplate(new URI("template3"))).thenAnswer(
new TestTemplateAnswer(Lists.newArrayList(new URI("template1")), ImmutableMap.of("key3", "value3"),
Lists.newArrayList("required3"), catalog));
TestTemplate template = new TestTemplate(new URI("template1"), Lists.newArrayList(new URI("template2")),
ImmutableMap.of("key1", "value1"), Lists.newArrayList("required"), catalog);
Collection<String> required = template.getRequiredConfigList();
Assert.assertEquals(required.size(), 2);
Assert.assertTrue(required.contains("required"));
Assert.assertTrue(required.contains("required3"));
Config rawTemplate = template.getRawTemplateConfig();
Assert.assertEquals(rawTemplate.getString("key1"), "value1");
Assert.assertEquals(rawTemplate.getString("key2"), "value2");
Assert.assertEquals(rawTemplate.getString("key3"), "value3");
Config resolved = template.getResolvedConfig(ConfigFactory.parseMap(ImmutableMap.of("required", "r1", "required3", "r3")));
Assert.assertEquals(resolved.getString("key1"), "value1");
Assert.assertEquals(resolved.getString("key2"), "value2");
Assert.assertEquals(resolved.getString("key3"), "value3");
Assert.assertEquals(resolved.getString("required"), "r1");
Assert.assertEquals(resolved.getString("required3"), "r3");
}
@Test
public void testSatisfySuperTemplateRequirements() throws Exception {
TestTemplate template1 = new TestTemplate(new URI("template1"), Lists.<JobTemplate>newArrayList(), ImmutableMap.of("key1", "value1"),
Lists.newArrayList("required"));
TestTemplate template2 = new TestTemplate(new URI("template2"), Lists.<JobTemplate>newArrayList(template1), ImmutableMap.of("required", "r1"),
Lists.newArrayList("required2"));
Collection<String> required = template2.getRequiredConfigList();
Assert.assertEquals(required.size(), 1);
Assert.assertTrue(required.contains("required2"));
Config rawTemplate = template2.getRawTemplateConfig();
Assert.assertEquals(rawTemplate.getString("key1"), "value1");
Assert.assertEquals(rawTemplate.getString("required"), "r1");
Config resolved = template2.getResolvedConfig(ConfigFactory.parseMap(ImmutableMap.of("required2", "r2")));
Assert.assertEquals(resolved.getString("key1"), "value1");
Assert.assertEquals(resolved.getString("required"), "r1");
Assert.assertEquals(resolved.getString("required2"), "r2");
}
@AllArgsConstructor
public static class TestTemplateAnswer implements Answer<JobTemplate> {
private final List<URI> superTemplateUris;
private final Map<String,String> rawTemplate;
private final List<String> required;
private final JobCatalogWithTemplates catalog;
@Override
public JobTemplate answer(InvocationOnMock invocation)
throws Throwable {
return new TestTemplate((URI) invocation.getArguments()[0],
this.superTemplateUris, this.rawTemplate, this.required, this.catalog);
}
}
public static class TestTemplate extends InheritingJobTemplate {
private final URI uri;
private final Map<String,String> rawTemplate;
private final List<String> required;
public TestTemplate(URI uri, List<URI> superTemplateUris, Map<String, String> rawTemplate, List<String> required,
JobCatalogWithTemplates catalog) throws SpecNotFoundException, TemplateException {
super(superTemplateUris, catalog);
this.uri = uri;
this.rawTemplate = rawTemplate;
this.required = required;
}
public TestTemplate(URI uri, List<JobTemplate> superTemplates, Map<String, String> rawTemplate, List<String> required) {
super(superTemplates);
this.uri = uri;
this.rawTemplate = rawTemplate;
this.required = required;
}
@Override
public URI getUri() {
return this.uri;
}
@Override
public String getVersion() {
return "1";
}
@Override
public String getDescription() {
return "description";
}
@Override
protected Config getLocalRawTemplate() {
return ConfigFactory.parseMap(this.rawTemplate);
}
@Override
protected Collection<String> getLocallyRequiredConfigList() {
return this.required;
}
@Override
protected Config getLocallyResolvedConfig(Config userConfig) throws TemplateException {
for (String required : this.required) {
if (!userConfig.hasPath(required)) {
throw new TemplateException("Missing required property " + required);
}
}
return userConfig.withFallback(getLocalRawTemplate());
}
}
}