/* * Copyright © 2015-2016 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.proto.id; import co.cask.cdap.proto.Id; import co.cask.cdap.proto.ProgramType; import co.cask.cdap.proto.codec.EntityIdTypeAdapter; import co.cask.cdap.proto.codec.IdTypeAdapter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Tests for {@link EntityId}. */ public class EntityIdTest { private static final Gson GSON = new GsonBuilder() .registerTypeAdapter(Id.class, new IdTypeAdapter()) .registerTypeAdapter(EntityId.class, new EntityIdTypeAdapter()) .create(); private static final List<EntityId> ids = new ArrayList<>(); static { ids.add(Ids.namespace("foo")); ids.add(Ids.namespace("foo").artifact("art", "1.2.3")); ids.add(Ids.namespace("foo").dataset("zoo")); ids.add(Ids.namespace("foo").datasetModule("moo")); ids.add(Ids.namespace("foo").datasetType("typ")); ids.add(Ids.namespace("foo").stream("t")); ids.add(Ids.namespace("foo").app("app")); ids.add(Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo")); ids.add(Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").run("run1")); ids.add(Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").flowlet("flol")); ids.add(Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").flowlet("flol").queue("q")); ids.add(Ids.namespace("foo").app("app").flow("flo")); ids.add(Ids.namespace("foo").app("app").workflow("flo")); ids.add(Ids.namespace("foo").app("app").mr("flo")); ids.add(Ids.namespace("foo").app("app").spark("flo")); ids.add(Ids.namespace("foo").app("app").worker("flo")); ids.add(Ids.namespace("foo").app("app").service("flo")); // components mostly the same ids.add(Ids.namespace("zzz")); ids.add(Ids.namespace("zzz").artifact("zzz", "1.2.3")); ids.add(Ids.namespace("zzz").dataset("zzz")); ids.add(Ids.namespace("zzz").datasetModule("zzz")); ids.add(Ids.namespace("zzz").datasetType("zzz")); ids.add(Ids.namespace("zzz").stream("zzz")); ids.add(Ids.namespace("zzz").app("zzz")); ids.add(Ids.namespace("zzz").app("zzz").program(ProgramType.FLOW, "zzz")); ids.add(Ids.namespace("zzz").app("zzz").program(ProgramType.FLOW, "zzz").run("zzz")); ids.add(Ids.namespace("zzz").app("zzz").program(ProgramType.FLOW, "zzz").flowlet("zzz")); ids.add(Ids.namespace("zzz").app("zzz").program(ProgramType.FLOW, "zzz").flowlet("zzz").queue("zzz")); ids.add(Ids.namespace("zzz").app("zzz").flow("zzz")); ids.add(Ids.namespace("zzz").app("zzz").workflow("zzz")); ids.add(Ids.namespace("zzz").app("zzz").mr("zzz")); ids.add(Ids.namespace("zzz").app("zzz").spark("zzz")); ids.add(Ids.namespace("zzz").app("zzz").worker("zzz")); ids.add(Ids.namespace("zzz").app("zzz").service("zzz")); } /** * To maintain backwards compatibility, don't change this. */ private static final Map<EntityId, String> idsToString = new HashMap<>(); static { idsToString.put(Ids.namespace("foo"), "namespace:foo"); idsToString.put(Ids.namespace("foo").artifact("art", "1.2.3"), "artifact:foo.art.1.2.3"); idsToString.put(Ids.namespace("foo").dataset("zoo"), "dataset:foo.zoo"); idsToString.put(Ids.namespace("foo").datasetModule("moo"), "dataset_module:foo.moo"); idsToString.put(Ids.namespace("foo").datasetType("typ"), "dataset_type:foo.typ"); idsToString.put(Ids.namespace("foo").stream("sdf"), "stream:foo.sdf"); idsToString.put(Ids.namespace("foo").app("app"), "application:foo.app"); idsToString.put(Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo"), "program:foo.app.flow.flo"); idsToString.put( Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").run("run1"), "program_run:foo.app.flow.flo.run1"); idsToString.put( Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").flowlet("flol"), "flowlet:foo.app.flo.flol"); idsToString.put( Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").flowlet("flol").queue("q"), "flowlet_queue:foo.app.flo.flol.q"); } /** * To maintain backwards compatibility, don't change this. */ private static final Map<EntityId, String> idsToJson = new HashMap<>(); static { idsToJson.put(Ids.namespace("foo"), "{\"namespace\":\"foo\",\"entity\":\"NAMESPACE\"}"); idsToJson.put( Ids.namespace("foo").artifact("art", "1.2.3"), "{\"namespace\":\"foo\",\"artifact\":\"art\",\"version\":\"1.2.3\",\"entity\":\"ARTIFACT\"}"); idsToJson.put( Ids.namespace("foo").dataset("zoo"), "{\"namespace\":\"foo\",\"dataset\":\"zoo\",\"entity\":\"DATASET\"}"); idsToJson.put( Ids.namespace("foo").datasetModule("moo"), "{\"namespace\":\"foo\",\"module\":\"moo\",\"entity\":\"DATASET_MODULE\"}"); idsToJson.put( Ids.namespace("foo").datasetType("typ"), "{\"namespace\":\"foo\",\"type\":\"typ\",\"entity\":\"DATASET_TYPE\"}"); idsToJson.put( Ids.namespace("foo").stream("t"), "{\"namespace\":\"foo\",\"stream\":\"t\",\"entity\":\"STREAM\"}"); idsToJson.put( Ids.namespace("foo").app("app"), "{\"namespace\":\"foo\",\"application\":\"app\",\"entity\":\"APPLICATION\"}"); idsToJson.put( Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo"), "{\"namespace\":\"foo\",\"application\":\"app\",\"type\":\"Flow\",\"program\":\"flo\",\"entity\":\"PROGRAM\"}"); idsToJson.put( Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").run("run1"), "{\"namespace\":\"foo\",\"application\":\"app\",\"type\":\"Flow\",\"program\":\"flo\"," + "\"run\":\"run1\",\"entity\":\"PROGRAM_RUN\"}"); idsToJson.put( Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").flowlet("flol"), "{\"namespace\":\"foo\",\"application\":\"app\",\"flow\":\"flo\",\"flowlet\":\"flol\",\"entity\":\"FLOWLET\"}"); idsToJson.put( Ids.namespace("foo").app("app").program(ProgramType.FLOW, "flo").flowlet("flol").queue("q"), "{\"namespace\":\"foo\",\"application\":\"app\",\"flow\":\"flo\"," + "\"flowlet\":\"flol\",\"queue\":\"q\",\"entity\":\"FLOWLET_QUEUE\"}"); } @Test public void testToFromString() { for (EntityId id : ids) { doTestToFromString(id); } } private void doTestToFromString(EntityId id) { Assert.assertEquals( "doTestToFromString failed for class " + id.getClass().getName(), id, EntityId.fromString(id.toString(), id.getClass())); } @Test public void testToFromJson() { for (EntityId id : ids) { doTestToFromJson(id); } } private void doTestToFromJson(EntityId id) { Assert.assertEquals( "doTestToFromJson failed for class " + id.getClass().getName(), id, GSON.fromJson(GSON.toJson(id), id.getClass()) ); Assert.assertEquals( "doTestToFromJson failed for class " + id.getClass().getName(), id, GSON.fromJson(GSON.toJson(id), EntityId.class) ); } @Test public void testToFromOldId() { for (EntityId id : ids) { doTestToFromOldId(id); } } private void doTestToFromOldId(EntityId id) { Assert.assertEquals( "doTestToFromOldId failed for class " + id.getClass().getName(), id, id.toId().toEntityId()); } @Test public void testDatasetName() { // TODO: CDAP-5730: Even though dots are allowed, if we use it here, id creation will fail. DatasetId.fromString("dataset:foo.Zo123_-$$_-"); try { DatasetId.fromString("dataset:i have a space in my name"); Assert.fail("Dataset Id with space in its name was created successfully while it should have failed."); } catch (IllegalArgumentException e) { // expected } } @Test public void testInvalidId() { try { ApplicationId.fromString("application:ns1"); Assert.fail(); } catch (IllegalArgumentException e) { // expected } } /** * This shouldn't be changed, so that we can maintain backwards compatibility. */ @Test public void testCompatibility() { for (Map.Entry<? extends EntityId, String> toStringEntry : idsToString.entrySet()) { Assert.assertEquals(toStringEntry.getValue(), toStringEntry.getKey().toString()); } for (Map.Entry<? extends EntityId, String> toJsonEntry : idsToJson.entrySet()) { Assert.assertEquals(toJsonEntry.getValue(), GSON.toJson(toJsonEntry.getKey())); } } @Test public void testHierarchy() { NamespaceId namespace = Ids.namespace("foo"); ApplicationId app = namespace.app("bar"); ProgramId program = app.flow("foo"); List<EntityId> expectedHierarchy = new ArrayList<>(); expectedHierarchy.add(namespace); Assert.assertEquals(expectedHierarchy, namespace.getHierarchy()); expectedHierarchy.add(app); Assert.assertEquals(expectedHierarchy, app.getHierarchy()); expectedHierarchy.add(program); Assert.assertEquals(expectedHierarchy, program.getHierarchy()); } @Test(expected = UnsupportedOperationException.class) public void testInstanceId() { InstanceId instanceId = new InstanceId("mycdap"); instanceId.toId(); } @Test @Ignore public void printToString() { for (EntityId id : ids) { System.out.println(id.getEntity() + ": " + id.toString()); } } @Test @Ignore public void printToJson() { for (EntityId id : ids) { System.out.println(id.getEntity() + ": " + GSON.toJson(id)); } } }