/**
* Copyright 2015 StreamSets Inc.
*
* Licensed under 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 com.streamsets.datacollector.configupgrade;
import com.google.common.collect.ImmutableList;
import com.streamsets.datacollector.config.PipelineConfiguration;
import com.streamsets.datacollector.config.StageConfiguration;
import com.streamsets.datacollector.config.StageDefinition;
import com.streamsets.datacollector.config.StageLibraryDefinition;
import com.streamsets.datacollector.creation.PipelineConfigBean;
import com.streamsets.datacollector.definition.StageDefinitionExtractor;
import com.streamsets.datacollector.definition.StageLibraryDefinitionExtractor;
import com.streamsets.datacollector.runner.preview.StageConfigurationBuilder;
import com.streamsets.datacollector.stagelibrary.StageLibraryTask;
import com.streamsets.datacollector.store.PipelineStoreTask;
import com.streamsets.datacollector.validation.Issue;
import com.streamsets.pipeline.api.BatchMaker;
import com.streamsets.pipeline.api.Config;
import com.streamsets.pipeline.api.StageDef;
import com.streamsets.pipeline.api.StageException;
import com.streamsets.pipeline.api.StageUpgrader;
import com.streamsets.pipeline.api.base.BaseSource;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
public class TestPipelineConfigurationUpgrader {
private static int UPGRADE_CALLED;
@Before
public void setUp() {
UPGRADE_CALLED = 0;
}
@StageDef(version = 1, label = "L", onlineHelpRefUrl = "")
public static class Source1 extends BaseSource {
@Override
public String produce(String lastSourceOffset, int maxBatchSize, BatchMaker batchMaker) throws StageException {
return null;
}
}
public static class Upgrader2 implements StageUpgrader {
@Override
public List<Config> upgrade(String library, String stageName, String stageInstance, int fromVersion, int toVersion,
List<Config> configs) throws StageException {
UPGRADE_CALLED++;
configs.add(new Config("a", "A"));
return configs;
}
}
@StageDef(version = 1, label = "L", upgrader = Upgrader2.class, onlineHelpRefUrl = "")
public static class Source2 extends BaseSource {
@Override
public String produce(String lastSourceOffset, int maxBatchSize, BatchMaker batchMaker) throws StageException {
return null;
}
}
private static final StageLibraryDefinition LIBRARY_DEF =
StageLibraryDefinitionExtractor.get().extract(TestPipelineConfigurationUpgrader.class.getClassLoader());
private static final StageDefinition SOURCE1_DEF = StageDefinitionExtractor.get().extract(LIBRARY_DEF,
Source1.class, "");
private static final StageDefinition SOURCE2_V1_DEF = StageDefinitionExtractor.get().extract(LIBRARY_DEF,
Source2.class, "");
private static final StageDefinition SOURCE2_V2_DEF;
static {
SOURCE2_V2_DEF = Mockito.spy(SOURCE2_V1_DEF);
Mockito.when(SOURCE2_V2_DEF.getVersion()).thenReturn(2);
}
private StageLibraryTask getLibrary(StageDefinition def) {
StageLibraryTask library = Mockito.mock(StageLibraryTask.class);
Mockito.when(library.getStage(Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean())).thenReturn(def);
return library;
}
@Test
public void testNeedsUpgradeStage() throws Exception {
PipelineConfigurationUpgrader up = PipelineConfigurationUpgrader.get();
StageConfiguration stageConf = new StageConfigurationBuilder("i", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.build();
// no upgrade
List<Issue> issues = new ArrayList<>();
Assert.assertFalse(up.needsUpgrade(SOURCE2_V1_DEF, stageConf, issues));
Assert.assertTrue(issues.isEmpty());
// upgrade
Assert.assertTrue(up.needsUpgrade(SOURCE2_V2_DEF, stageConf, issues));
Assert.assertTrue(issues.isEmpty());
stageConf = new StageConfigurationBuilder("i",SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V2_DEF.getVersion())
.build();
// null def
Assert.assertFalse(up.needsUpgrade(null, stageConf, issues));
Assert.assertFalse(issues.isEmpty());
// invalid downgrade
issues.clear();
Assert.assertFalse(up.needsUpgrade(SOURCE2_V1_DEF, stageConf, issues));
Assert.assertFalse(issues.isEmpty());
}
public static class ForMockUpgrader extends PipelineConfigurationUpgrader {
}
;
public PipelineConfigurationUpgrader getPipelineV2Upgrader() {
PipelineConfigurationUpgrader up = new ForMockUpgrader();
StageDefinition pipelineDefV2 = Mockito.spy(up.getPipelineDefinition());
Mockito.when(pipelineDefV2.getVersion()).thenReturn(PipelineConfigBean.VERSION + 1);
Mockito.when(pipelineDefV2.getUpgrader()).thenReturn(new Upgrader2());
up = Mockito.spy(up);
Mockito.when(up.getPipelineDefinition()).thenReturn(pipelineDefV2);
return up;
}
@Test
public void testNeedsUpgradePipelineConfs() throws Exception {
PipelineConfigurationUpgrader up = PipelineConfigurationUpgrader.get();
PipelineConfiguration pipelineConf = new PipelineConfiguration(1, PipelineConfigBean.VERSION, "pipelineId", UUID.randomUUID(),
"label", null, Collections.<Config>emptyList(), null,
Collections.<StageConfiguration>emptyList(), null, null);
// no upgrade
List<Issue> issues = new ArrayList<>();
Assert.assertFalse(up.needsUpgrade(getLibrary(SOURCE1_DEF), pipelineConf, issues));
Assert.assertTrue(issues.isEmpty());
// upgrade
Assert.assertTrue(getPipelineV2Upgrader().needsUpgrade(getLibrary(SOURCE1_DEF), pipelineConf, issues));
Assert.assertTrue(issues.isEmpty());
// invalid downgrade
PipelineConfigurationUpgrader up0 = getPipelineV2Upgrader();
StageDefinition pipelineDefV0 = Mockito.spy(up.getPipelineDefinition());
Mockito.when(pipelineDefV0.getVersion()).thenReturn(0);
Mockito.when(up0.getPipelineDefinition()).thenReturn(pipelineDefV0);
Assert.assertFalse(up0.needsUpgrade(getLibrary(SOURCE1_DEF), pipelineConf, issues));
Assert.assertFalse(issues.isEmpty());
}
@Test
public void testNeedsUpgradePipelineErrorStage() throws Exception {
PipelineConfigurationUpgrader up = new ForMockUpgrader();
StageConfiguration stageConf = new StageConfigurationBuilder("i", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V1_DEF.getVersion())
.build();
PipelineConfiguration pipelineConf = new PipelineConfiguration(1, PipelineConfigBean.VERSION, "pipelineId", UUID.randomUUID(),
"label", null, Collections.<Config>emptyList(), null,
Collections.<StageConfiguration>emptyList(), stageConf, null);
// no upgrade
List<Issue> issues = new ArrayList<>();
Assert.assertFalse(up.needsUpgrade(getLibrary(SOURCE2_V1_DEF), pipelineConf, issues));
Assert.assertTrue(issues.isEmpty());
// upgrade
Assert.assertTrue(up.needsUpgrade(getLibrary(SOURCE2_V2_DEF), pipelineConf, issues));
Assert.assertTrue(issues.isEmpty());
// invalid downgrade
stageConf = new StageConfigurationBuilder("i", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V2_DEF.getVersion())
.build();
pipelineConf = new PipelineConfiguration(1, PipelineConfigBean.VERSION, "pipelineId", UUID.randomUUID(),
"label", null, Collections.<Config>emptyList(), null,
Collections.<StageConfiguration>emptyList(), stageConf, null);
Assert.assertFalse(up.needsUpgrade(getLibrary(SOURCE2_V1_DEF), pipelineConf, issues));
Assert.assertFalse(issues.isEmpty());
}
@Test
public void testNeedsUpgradePipelineStage() throws Exception {
PipelineConfigurationUpgrader up = PipelineConfigurationUpgrader.get();
StageConfiguration stageConf = new StageConfigurationBuilder("i", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V1_DEF.getVersion())
.build();
PipelineConfiguration pipelineConf = new PipelineConfiguration(1, PipelineConfigBean.VERSION, "pipelineId", UUID.randomUUID(),
"label", null, Collections.<Config>emptyList(), null,
ImmutableList.of(stageConf), null, null);
// no upgrade
List<Issue> issues = new ArrayList<>();
Assert.assertFalse(up.needsUpgrade(getLibrary(SOURCE2_V1_DEF), pipelineConf, issues));
Assert.assertTrue(issues.isEmpty());
// upgrade
Assert.assertTrue(up.needsUpgrade(getLibrary(SOURCE2_V2_DEF), pipelineConf, issues));
Assert.assertTrue(issues.isEmpty());
// invalid downgrade
stageConf = new StageConfigurationBuilder("i", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V2_DEF.getVersion())
.build();
pipelineConf = new PipelineConfiguration(1, PipelineConfigBean.VERSION, "pipelineId", UUID.randomUUID(),
"label", null, Collections.<Config>emptyList(), null,
ImmutableList.of(stageConf), null, null);
Assert.assertFalse(up.needsUpgrade(getLibrary(SOURCE2_V1_DEF), pipelineConf, issues));
Assert.assertFalse(issues.isEmpty());
}
@Test
public void testUpgradeStage() throws Exception {
PipelineConfigurationUpgrader up = PipelineConfigurationUpgrader.get();
StageConfiguration stageConf = new StageConfigurationBuilder("i", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V1_DEF.getVersion())
.build();
List<Issue> issues = new ArrayList<>();
Assert.assertTrue(up.needsUpgrade(SOURCE2_V2_DEF, stageConf, issues));
Assert.assertTrue(issues.isEmpty());
// upgrade
stageConf = up.upgrade(SOURCE2_V2_DEF, stageConf, issues);
Assert.assertNotNull(stageConf);
Assert.assertTrue(issues.isEmpty());
Assert.assertEquals(SOURCE2_V2_DEF.getVersion(), stageConf.getStageVersion());
Assert.assertEquals(1, UPGRADE_CALLED);
}
private PipelineConfiguration getPipelineUpToDate() {
StageConfiguration stageConf1 = new StageConfigurationBuilder("i1", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V2_DEF.getVersion())
.build();
StageConfiguration stageConf2 = new StageConfigurationBuilder("i2", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V2_DEF.getVersion())
.build();
StageConfiguration errorConf = new StageConfigurationBuilder("e", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V2_DEF.getVersion())
.build();
return new PipelineConfiguration(1, PipelineConfigBean.VERSION, "pipelineId", UUID.randomUUID(), "label", null, Collections.<Config>emptyList(),
null, ImmutableList.of(stageConf1, stageConf2), errorConf, null);
}
private PipelineConfiguration getPipelineToUpgrade() {
StageConfiguration stageConf1 = new StageConfigurationBuilder("i1", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V2_DEF.getVersion())
.build();
StageConfiguration stageConf2 = new StageConfigurationBuilder("i2", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V1_DEF.getVersion())
.build();
StageConfiguration errorConf = new StageConfigurationBuilder("e", SOURCE2_V1_DEF.getName())
.withLibrary(SOURCE2_V1_DEF.getLibrary())
.withStageVersion(SOURCE2_V1_DEF.getVersion())
.build();
return new PipelineConfiguration(1, PipelineConfigBean.VERSION, "pipelineId", UUID.randomUUID(), "label", null, Collections.<Config>emptyList(),
null, ImmutableList.of(stageConf1, stageConf2), errorConf, null);
}
@Test
public void testUpgradePipeline() throws Exception {
PipelineConfigurationUpgrader up2 = getPipelineV2Upgrader();
PipelineConfiguration pipelineConf = getPipelineToUpgrade();
List<Issue> issues = new ArrayList<>();
Assert.assertTrue(up2.needsUpgrade(getLibrary(SOURCE2_V2_DEF), pipelineConf, issues));
Assert.assertTrue(issues.isEmpty());
// upgrade
pipelineConf = up2.upgrade(getLibrary(SOURCE2_V2_DEF), pipelineConf, issues);
Assert.assertNotNull(pipelineConf);
Assert.assertTrue(issues.isEmpty());
Assert.assertEquals(SOURCE2_V2_DEF.getVersion(), pipelineConf.getErrorStage().getStageVersion());
Assert.assertEquals(SOURCE2_V2_DEF.getVersion(), pipelineConf.getStages().get(0).getStageVersion());
Assert.assertEquals(SOURCE2_V2_DEF.getVersion(), pipelineConf.getStages().get(1).getStageVersion());
Assert.assertEquals(3, UPGRADE_CALLED);
Assert.assertEquals(PipelineConfigBean.VERSION + 1, pipelineConf.getVersion());
Assert.assertEquals("A", pipelineConf.getConfiguration("a").getValue());
Assert.assertEquals(null, pipelineConf.getStages().get(0).getConfig("a"));
Assert.assertEquals(1, pipelineConf.getStages().get(1).getConfiguration().size());
Assert.assertEquals("A", pipelineConf.getStages().get(1).getConfig("a").getValue());
Assert.assertEquals(1, pipelineConf.getErrorStage().getConfiguration().size());
Assert.assertEquals("A", pipelineConf.getErrorStage().getConfig("a").getValue());
}
@Test
public void testUpgradeIfNecessaryPipelineUpgrade() throws Exception {
PipelineConfigurationUpgrader up2 = getPipelineV2Upgrader();
PipelineConfiguration pipelineConf = getPipelineToUpgrade();
List<Issue> issues = new ArrayList<>();
pipelineConf = up2.upgradeIfNecessary(getLibrary(SOURCE2_V2_DEF), pipelineConf, issues);
Assert.assertNotNull(pipelineConf);
Assert.assertTrue(issues.isEmpty());
Assert.assertEquals(PipelineStoreTask.SCHEMA_VERSION, pipelineConf.getSchemaVersion());
Assert.assertEquals(SOURCE2_V2_DEF.getVersion(), pipelineConf.getErrorStage().getStageVersion());
Assert.assertEquals(SOURCE2_V2_DEF.getVersion(), pipelineConf.getStages().get(0).getStageVersion());
Assert.assertEquals(SOURCE2_V2_DEF.getVersion(), pipelineConf.getStages().get(1).getStageVersion());
Assert.assertEquals(3, UPGRADE_CALLED);
Assert.assertEquals(PipelineConfigBean.VERSION + 1, pipelineConf.getVersion());
Assert.assertEquals("A", pipelineConf.getConfiguration("a").getValue());
Assert.assertEquals(null, pipelineConf.getStages().get(0).getConfig("a"));
Assert.assertEquals(1, pipelineConf.getStages().get(1).getConfiguration().size());
Assert.assertEquals("A", pipelineConf.getStages().get(1).getConfig("a").getValue());
Assert.assertEquals(1, pipelineConf.getErrorStage().getConfiguration().size());
Assert.assertEquals("A", pipelineConf.getErrorStage().getConfig("a").getValue());
}
@Test
public void testUpgradeSchemaVersion1to2() throws Exception {
PipelineConfiguration pipelineConf = getPipelineToUpgrade();
PipelineConfigurationUpgrader up = getPipelineV2Upgrader();
List<Issue> issues = new ArrayList<>();
pipelineConf = up.upgradeIfNecessary(getLibrary(SOURCE2_V2_DEF), pipelineConf, issues);
Assert.assertNotNull(pipelineConf);
Assert.assertTrue(issues.isEmpty());
Assert.assertEquals(PipelineStoreTask.SCHEMA_VERSION, pipelineConf.getSchemaVersion());
Assert.assertEquals(2, pipelineConf.getStages().size());
for(StageConfiguration stage : pipelineConf.getStages()) {
Assert.assertNotNull(stage.getEventLanes());
Assert.assertEquals(0, stage.getEventLanes().size());
}
Assert.assertNotNull(pipelineConf.getErrorStage().getEventLanes());
Assert.assertEquals(0, pipelineConf.getErrorStage().getEventLanes().size());
}
}