/* Copyright (c) 2012 LinkedIn Corp. 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 com.linkedin.restli.tools.snapshot.gen; import com.linkedin.data.DataMap; import com.linkedin.data.codec.JacksonDataCodec; import com.linkedin.data.schema.generator.AbstractGenerator; import com.linkedin.pegasus.generator.GeneratorResult; import java.io.BufferedReader; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; /** * @author Moira Tagle * @version $Revision: $ */ public class TestRestLiSnapshotExporter { // TODO These should be passed in as test config private static final String FS = File.separator; private static final String TEST_DIR = "src" + FS + "test" + FS + "java"; private static final String SNAPSHOTS_DIR = "src" + FS + "test" + FS + "resources" + FS + "snapshots"; private static final String STATUSES_FILE = "twitter-statuses.snapshot.json"; private static final String STATUSES_PARAMS_FILE = "twitter-statusesParams.snapshot.json"; private static final String FOLLOWS_FILE = "twitter-follows.snapshot.json"; private static final String ACCOUNTS_FILE = "twitter-accounts.snapshot.json"; private static final String TRENDING_FILE = "twitter-trending.snapshot.json"; private static final String CIRCULAR_FILE = "circular-circular.snapshot.json"; private static final String GREETINGS_FILE = "sample-com.linkedin.restli.tools.sample.greetings.snapshot.json"; private File outdir; // Gradle by default will use the module directory as the working directory // IDE such as IntelliJ IDEA may use the project directory instead // If you create test in IDE, make sure the working directory is always the module directory private String moduleDir; private String resolverPath; @BeforeTest public void setUpTest() { moduleDir = System.getProperty("user.dir"); // set generator.resolver.path... final String resourcesDir = moduleDir + File.separator + RESOURCES_SUFFIX; resolverPath = System.getProperty(AbstractGenerator.GENERATOR_RESOLVER_PATH); if (resolverPath == null) { resolverPath = resourcesDir + PEGASUS_SUFFIX; } } @BeforeMethod public void setUpMethod() throws IOException { outdir = createTmpDir(); } @AfterMethod public void tearDownMethod() { rmdir(outdir); } @AfterTest public void tearDownTest() throws IOException { System.clearProperty(AbstractGenerator.GENERATOR_RESOLVER_PATH); } @Test public void testSimpleSnapshot() throws Exception { RestLiSnapshotExporter exporter = new RestLiSnapshotExporter(); exporter.setResolverPath(resolverPath); assertEquals(outdir.list().length, 0); GeneratorResult result = exporter.export("twitter", null, new String[] {moduleDir + FS + TEST_DIR}, new String[] {"com.linkedin.restli.tools.twitter"}, null, outdir.getAbsolutePath()); String[] expectedFiles = {STATUSES_FILE, FOLLOWS_FILE, ACCOUNTS_FILE, STATUSES_PARAMS_FILE, TRENDING_FILE}; assertEquals(outdir.list().length, expectedFiles.length); assertEquals(result.getModifiedFiles().size(), expectedFiles.length); assertEquals(result.getTargetFiles().size(), expectedFiles.length); for (String file : expectedFiles) { String actualFile = outdir + FS + file; String expectedFile = SNAPSHOTS_DIR + FS + file; compareFiles(actualFile, expectedFile); assertTrue(result.getModifiedFiles().contains(new File(actualFile))); assertTrue(result.getTargetFiles().contains(new File(actualFile))); } } @Test public void testCircularSnapshot() throws Exception { RestLiSnapshotExporter exporter = new RestLiSnapshotExporter(); exporter.setResolverPath(resolverPath); assertEquals(outdir.list().length, 0); GeneratorResult result = exporter.export("circular", null, new String[] {moduleDir + FS + TEST_DIR + FS + "snapshot"}, new String[] {"com.linkedin.restli.tools.snapshot.circular"}, null, outdir.getAbsolutePath()); String[] expectedFiles = {CIRCULAR_FILE}; assertEquals(outdir.list().length, expectedFiles.length); assertEquals(result.getModifiedFiles().size(), expectedFiles.length); assertEquals(result.getTargetFiles().size(), expectedFiles.length); for (String file : expectedFiles) { String actualFile = outdir + FS + file; String expectedFile = SNAPSHOTS_DIR + FS + file; compareFiles(actualFile, expectedFile); assertTrue(result.getModifiedFiles().contains(new File(actualFile))); assertTrue(result.getTargetFiles().contains(new File(actualFile))); } } @Test public void testSampleGreetingSnapshot() throws Exception { RestLiSnapshotExporter exporter = new RestLiSnapshotExporter(); exporter.setResolverPath(moduleDir + File.separator + "src" + File.separator + "test" + File.separator + PEGASUS_SUFFIX); assertEquals(outdir.list().length, 0); GeneratorResult result = exporter.export("sample", null, new String[] {moduleDir + FS + TEST_DIR}, new String[] {"com.linkedin.restli.tools.sample"}, null, outdir.getAbsolutePath()); String[] expectedFiles = {GREETINGS_FILE}; assertEquals(outdir.list().length, expectedFiles.length); assertEquals(result.getModifiedFiles().size(), expectedFiles.length); assertEquals(result.getTargetFiles().size(), expectedFiles.length); for (String file : expectedFiles) { String actualFile = outdir + FS + file; String expectedFile = SNAPSHOTS_DIR + FS + file; compareFiles(actualFile, expectedFile); assertTrue(result.getModifiedFiles().contains(new File(actualFile))); assertTrue(result.getTargetFiles().contains(new File(actualFile))); } } private void compareFiles(String actualFileName, String expectedFileName) throws Exception { String actualContent = readFile(actualFileName); String expectedContent = readFile(expectedFileName); //Compare using a map as opposed to line by line final JacksonDataCodec jacksonDataCodec = new JacksonDataCodec(); final DataMap actualContentMap = jacksonDataCodec.stringToMap(actualContent); final DataMap expectedContentMap = jacksonDataCodec.stringToMap(expectedContent); if(!actualContentMap.equals(expectedContentMap)) { // Ugh... gradle PrintStream actualStdout = new PrintStream(new FileOutputStream(FileDescriptor.out)); actualStdout.println("ERROR " + actualFileName + " does not match " + expectedFileName + " . Printing diff..."); try { // TODO environment dependent, not cross platform ProcessBuilder pb = new ProcessBuilder("diff", expectedFileName, actualFileName); pb.redirectErrorStream(); Process p = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); String line = null; while ((line = reader.readLine()) != null) { actualStdout.println(line); } } catch (Exception e) { // TODO Setup log4j, find appropriate test harness used in R2D2 actualStdout.println("Error printing diff: " + e.getMessage()); } fail(actualFileName + " does not match " + expectedFileName); } } private String readFile(String fileName) throws IOException { File file = new File(fileName); assertTrue(file.exists() && file.canRead(), "Cannot find file: " + fileName); BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); StringBuilder sb = new StringBuilder(); String line; try { while ((line = reader.readLine()) != null) { sb.append(line); } } finally { reader.close(); } return sb.toString(); } private void rmdir(File dir) { if (dir.listFiles() != null) { for (File f : outdir.listFiles()) { f.delete(); } } dir.delete(); } private static File createTmpDir() throws IOException { File temp = File.createTempFile("temp", Long.toString(System.nanoTime())); if(! temp.delete()) { throw new IOException("Could not delete temp file: " + temp.getAbsolutePath()); } temp = new File(temp.getAbsolutePath() + ".d"); if(! temp.mkdir()) { throw new IOException("Could not create temp directory: " + temp.getAbsolutePath()); } return temp; } private static final String PEGASUS_SUFFIX = "pegasus" + File.separator; private static final String RESOURCES_SUFFIX = "src" + File.separator + "test" + File.separator + "resources" + File.separator; }