/*
* Copyright © 2015 Cask Data, Inc.
*
* 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 co.cask.cdap.internal.app;
import co.cask.cdap.api.app.AbstractApplication;
import co.cask.cdap.api.app.Application;
import co.cask.cdap.api.app.ApplicationSpecification;
import co.cask.cdap.api.schedule.SchedulableProgramType;
import co.cask.cdap.api.schedule.Schedule;
import co.cask.cdap.api.schedule.ScheduleSpecification;
import co.cask.cdap.api.schedule.Schedules;
import co.cask.cdap.api.workflow.ScheduleProgramInfo;
import co.cask.cdap.app.DefaultAppConfigurer;
import co.cask.cdap.app.DefaultApplicationContext;
import co.cask.cdap.internal.io.ReflectionSchemaGenerator;
import co.cask.cdap.internal.schedule.StreamSizeSchedule;
import co.cask.cdap.internal.schedule.TimeSchedule;
import co.cask.cdap.proto.Id;
import co.cask.cdap.proto.codec.ScheduleSpecificationCodec;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.junit.Assert;
import org.junit.Test;
/**
*
*/
public class ScheduleSpecificationCodecTest {
private static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(ScheduleSpecification.class, new ScheduleSpecificationCodec())
.create();
@Test
public void testTimeSchedule() throws Exception {
TimeSchedule timeSchedule = (TimeSchedule) Schedules.builder("foo")
.setDescription("bar")
.createTimeSchedule("cronEntry");
ScheduleProgramInfo programInfo = new ScheduleProgramInfo(SchedulableProgramType.WORKFLOW, "testWorkflow");
ImmutableMap<String, String> properties = ImmutableMap.of("a", "b", "c", "d");
ScheduleSpecification specification = new ScheduleSpecification(timeSchedule, programInfo, properties);
String jsonStr = GSON.toJson(specification);
ScheduleSpecification deserialized = GSON.fromJson(jsonStr, ScheduleSpecification.class);
Assert.assertEquals(specification, deserialized);
}
@Test
public void testStreamSizeSchedule() throws Exception {
Schedule dataSchedule = Schedules.builder("foo")
.setDescription("bar")
.createDataSchedule(Schedules.Source.STREAM, "stream", 10);
ScheduleProgramInfo programInfo = new ScheduleProgramInfo(SchedulableProgramType.WORKFLOW, "testWorkflow");
ImmutableMap<String, String> properties = ImmutableMap.of("a", "b", "c", "d");
ScheduleSpecification specification = new ScheduleSpecification(dataSchedule, programInfo, properties);
String jsonStr = GSON.toJson(specification);
ScheduleSpecification deserialized = GSON.fromJson(jsonStr, ScheduleSpecification.class);
Assert.assertEquals(specification, deserialized);
}
@Test
public void testBackwardsCompatibility() throws Exception {
// Before 2.8, the ScheduleSpecificationCodec used to have the same behavior as what Gson would do by
// default, and only Schedules existed. We make sure that ScheduleSpecification persisted before
// 2.8 can still be deserialized using the new codec.
String cronEntry = "* * * * *";
Schedule schedule = new OldSchedule("foo", "bar", cronEntry);
ScheduleProgramInfo programInfo = new ScheduleProgramInfo(SchedulableProgramType.WORKFLOW, "testWorkflow");
ImmutableMap<String, String> properties = ImmutableMap.of("a", "b", "c", "d");
ScheduleSpecification specification = new ScheduleSpecification(schedule, programInfo, properties);
// Use default Gson to serialize
String jsonStr = new Gson().toJson(specification);
ScheduleSpecification deserialized = GSON.fromJson(jsonStr, ScheduleSpecification.class);
ScheduleSpecification expectedSpec = new ScheduleSpecification(
Schedules.createTimeSchedule(schedule.getName(), schedule.getDescription(), cronEntry),
programInfo, properties);
Assert.assertEquals(expectedSpec, deserialized);
}
@Test
public void testAppConfigurerRoute() throws Exception {
Application app = new AbstractApplication() {
@Override
public void configure() {
scheduleWorkflow(Schedules.builder("timeSchedule").createTimeSchedule("cronEntry"), "workflow");
scheduleWorkflow(Schedules.builder("streamSizeSchedule")
.createDataSchedule(Schedules.Source.STREAM, "stream", 1),
"workflow");
}
};
DefaultAppConfigurer configurer = new DefaultAppConfigurer(Id.Namespace.DEFAULT, app);
app.configure(configurer, new DefaultApplicationContext());
ApplicationSpecification specification = configurer.createSpecification();
ApplicationSpecificationAdapter gsonAdapater =
ApplicationSpecificationAdapter.create(new ReflectionSchemaGenerator());
String jsonStr = gsonAdapater.toJson(specification);
ApplicationSpecification deserializedSpec = gsonAdapater.fromJson(jsonStr);
Assert.assertEquals(new TimeSchedule("timeSchedule", "", "cronEntry"),
deserializedSpec.getSchedules().get("timeSchedule").getSchedule());
Assert.assertEquals(new StreamSizeSchedule("streamSizeSchedule", "", "stream", 1),
deserializedSpec.getSchedules().get("streamSizeSchedule").getSchedule());
}
// the Schedule class used to look like this prior to v2.8
private class OldSchedule extends Schedule {
private final String cronEntry;
OldSchedule(String name, String description, String cronEntry) {
super(name, description, null);
this.cronEntry = cronEntry;
}
}
}