Author: daijy
Date: Thu Jan 15 22:19:21 2015
New Revision: 1652288

URL: http://svn.apache.org/r1652288
Log:
PIG-2692: Make the Pig unit faciliities more generalizable and update javadocs

Modified:
    pig/trunk/CHANGES.txt
    pig/trunk/src/docs/src/documentation/content/xdocs/test.xml
    pig/trunk/test/org/apache/pig/pigunit/PigTest.java
    pig/trunk/test/org/apache/pig/test/pigunit/TestPigTest.java

Modified: pig/trunk/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/pig/trunk/CHANGES.txt?rev=1652288&r1=1652287&r2=1652288&view=diff
==============================================================================
--- pig/trunk/CHANGES.txt (original)
+++ pig/trunk/CHANGES.txt Thu Jan 15 22:19:21 2015
@@ -24,6 +24,8 @@ INCOMPATIBLE CHANGES
  
 IMPROVEMENTS
 
+PIG-2692: Make the Pig unit faciliities more generalizable and update javadocs 
(razsapps via daijy)
+
 PIG-4379: Make RoundRobinPartitioner public (daijy)
 
 PIG-4378: Better way to fix tez local mode test hanging (daijy)

Modified: pig/trunk/src/docs/src/documentation/content/xdocs/test.xml
URL: 
http://svn.apache.org/viewvc/pig/trunk/src/docs/src/documentation/content/xdocs/test.xml?rev=1652288&r1=1652287&r2=1652288&view=diff
==============================================================================
--- pig/trunk/src/docs/src/documentation/content/xdocs/test.xml (original)
+++ pig/trunk/src/docs/src/documentation/content/xdocs/test.xml Thu Jan 15 
22:19:21 2015
@@ -963,6 +963,50 @@ junit.framework.ComparisonFailure: null
         at org.apache.pig.pigunit.PigTest.assertEquals(PigTest.java:272)
 </source>
       </section>
+      
+<!-- +++++++++++++++++++++++++++++++++++++++ -->      
+      <section>
+        <title>Mocking</title>
+
+        <p>Sometimes you need to mock out the data in specific aliases. Using 
PigTest's 
+        mocking you can override an alias everywhere it is assigned. If you do 
not know
+        the schema (or want to keep your test dynamic) you can use 
PigTest.getAliasToSchemaMap() 
+        to determine the schema. If you chose to go this route, you should 
cache the map for
+        the specific script to ensure efficient execution.
+        </p>
+
+        <source>
+  @Test
+  public void testTop2Queries() {
+    String[] args = {
+        "n=2",
+        };
+ 
+    PigTest test = new PigTest("top_queries.pig", args);
+ 
+    String[] mockData = {
+        "yahoo",
+        "yahoo",
+        "yahoo",
+        "twitter",
+        "facebook",
+        "facebook",
+        "linkedin",
+    };
+    
+    //You should cache the map if you can
+    String schema = test.getAliasToSchemaMap().get("data");
+    test.mockAlias("data", mockData, schema);
+ 
+    String[] output = {
+        "(yahoo,3)",
+        "(facebook,2)",
+    };
+ 
+    test.assertOutputAnyOrder("queries_limit", output);
+  }
+</source>
+      </section>
     </section>
 
 <!-- +++++++++++++++++++++++++++++++++++++++ -->

Modified: pig/trunk/test/org/apache/pig/pigunit/PigTest.java
URL: 
http://svn.apache.org/viewvc/pig/trunk/test/org/apache/pig/pigunit/PigTest.java?rev=1652288&r1=1652287&r2=1652288&view=diff
==============================================================================
--- pig/trunk/test/org/apache/pig/pigunit/PigTest.java (original)
+++ pig/trunk/test/org/apache/pig/pigunit/PigTest.java Thu Jan 15 22:19:21 2015
@@ -18,14 +18,20 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringReader;
+import java.lang.Object;
 import java.nio.MappedByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.charset.Charset;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import com.google.common.collect.Iterables;
 import junit.framework.Assert;
 
 import org.apache.commons.lang.StringUtils;
@@ -38,6 +44,7 @@ import org.apache.pig.data.DataType;
 import org.apache.pig.data.Tuple;
 import org.apache.pig.impl.PigContext;
 import org.apache.pig.impl.io.FileLocalizer;
+import org.apache.pig.impl.logicalLayer.FrontendException;
 import org.apache.pig.impl.logicalLayer.schema.Schema;
 import org.apache.pig.pigunit.pig.PigServer;
 import org.apache.pig.tools.parameters.ParseException;
@@ -254,37 +261,167 @@ public class PigTest {
     aliasOverrides.remove(alias);
   }
 
-  public void assertOutput(String[] expected) throws IOException, 
ParseException {
+  /**
+   * Returns a Map that has alias to it's schema.
+   *
+   * @return A map that has alias name as a key and the alias's schema as a 
value
+   * @throws FrontendException If there was an error dumping the schema
+   */
+  public Map<String, String> getAliasToSchemaMap() throws FrontendException, 
IOException, ParseException {
+    HashMap<String, String> aliasSchemas = new HashMap<String, String>();
     registerScript();
-    String alias = aliasOverrides.get("LAST_STORE_ALIAS");
+    PigServer server = getPigServer();
+    Set<String> aliasKeySet = server.getAliasKeySet();
+    for (String alias: aliasKeySet) {
+      try {
+        StringBuilder tsb = new StringBuilder();
+        Schema.stringifySchema(tsb, server.dumpSchema(alias), DataType.TUPLE, 
Integer.MIN_VALUE);
+        aliasSchemas.put(alias, tsb.toString());
+      } catch (FrontendException e) {
+        /**
+         * If PigServer fails to describe a schema for an alias a 
FrontendException is thrown.
+         * PigServer.getAliasKeySet() returns aliases that cannot have their 
schema described.
+         * We want to skip over these particular aliases.
+         */
+        if (e.getErrorCode() == 1001) {
+          //Let's print a warning
+          System.out.println(e.getMessage());
+        } else {
+          throw e;
+        }
+      }
+    }
+    return aliasSchemas;
+  }
 
-    assertEquals(StringUtils.join(expected, "\n"), 
StringUtils.join(getAliasFromCache(alias), "\n"));
+  /**
+   * Creates a temp file and populates it with the specified mock data.
+   *
+   * @param alias alias that the temp file is for
+   * @param mockData data that is being mocked for the alias
+   * @return path to the temp file
+   */
+  private String makeMockTempFile(String alias, String[] mockData) throws 
IOException {
+    //The FileLocalizer uses a random variable, but that can have collisions. 
By using the current time, thread,
+    //and alias we should be able to guaratee a unique file
+    String uniqueSuffix = alias + "." + System.currentTimeMillis() + "." + 
Thread.currentThread().getId();
+    //PigServer/Cluster is not initialized yet. Let's initialize it.
+    if (getPigServer() == null) {
+        getCluster();
+    }
+    String path = 
FileLocalizer.getTemporaryPath(getPigServer().getPigContext(), 
uniqueSuffix).toString();
+    getCluster().copyFromLocalFile(mockData, path, true);
+    return path;
   }
 
-  public void assertOutput(String alias, String[] expected) throws 
IOException, ParseException {
-    registerScript();
+  private String getActualResults(String alias, boolean ignoreOrder) throws 
IOException, ParseException {
+    //Tuples are sortable, but we should sort it as Strings for convenience 
when comparing to expected data
+    Iterator<Tuple> iterator = getAliasFromCache(alias);
+    List<String> actualResults = new ArrayList<String>();
+    while (iterator.hasNext()) {
+      actualResults.add(iterator.next().toString());
+    }
+    
+    if (ignoreOrder) {
+      Collections.sort(actualResults);
+    }
+    return StringUtils.join(actualResults, "\n");
+  }
 
-    assertEquals(StringUtils.join(expected, "\n"), 
StringUtils.join(getAliasFromCache(alias), "\n"));
+  /**
+   * Allows you to mock a specific alias.
+   *
+   * This method will create a temporary file on the system that contains the 
mock data.  It will then change the pig
+   * script to actually replace the alias when being assigned a value with a 
load file command which loads the temporary
+   * file.
+   *
+   * @param alias The alias to be mocked
+   * @param mockData The data you wished to be contained in the alias where 
each element in the array is a tab-delimited
+   * @param aliasSchema The schema of the alias provided. Your mockData should 
fit this schema
+   */
+  public void mockAlias(String alias, String[] mockData, String aliasSchema) 
throws IOException {
+    mockAlias(alias, mockData, aliasSchema, "\\t");
   }
 
-  public void assertOutput(File expected) throws IOException, ParseException {
+  /**
+   * Allows you to mock a specific alias.
+   *
+   * This method will create a temporary file on the system that contains the 
mock data.  It will then change the pig
+   * script to actually replace the alias when being assigned a value with a 
load file command which loads the temporary
+   * file.
+   *
+   * @param alias The alias to be mocked
+   * @param mockData String array where each element is an entry in the alias 
and the line has its elements delimited
+   *                 by the value provided by delimiter.
+   * @param aliasSchema This is the schema of the alias being mocked
+   * @param delimiter The delimiter used to separate data in mockData
+   */
+  public void mockAlias(String alias, String[] mockData, String aliasSchema, 
String delimiter) throws IOException {
+    String mockFile = makeMockTempFile(alias, mockData);
+    override(alias, String.format("%s = LOAD '%s' USING PigStorage('%s') AS 
%s;", alias, mockFile, delimiter, aliasSchema));
+  }
+  
+  /**
+   * Compares the expected results to the results of the last alias generated 
in the script. Order does not matter
+   * and as long as the result is located in any index of expected and any 
line of the output then this will pass.
+   * 
+   * @param expected The expected results
+   */
+  public void assertOutputAnyOrder(String[] expected) throws IOException, 
ParseException {
+    assertOutput(expected, true);
+  }
+  
+  public void assertOutput(String[] expected) throws IOException, 
ParseException {
+    assertOutput(expected, false);
+  }
+
+  private void assertOutput(String[] expected, boolean ignoreOrder) throws 
IOException, ParseException {
     registerScript();
     String alias = aliasOverrides.get("LAST_STORE_ALIAS");
 
-    assertEquals(readFile(expected).replaceAll("\r\n", "\n"), 
StringUtils.join(getAliasFromCache(alias), "\n"));
+    if (ignoreOrder) {
+      Arrays.sort(expected);
+    }
+    assertEquals(StringUtils.join(expected, "\n"), getActualResults(alias, 
ignoreOrder));
+  }
+  
+  /**
+   * Compares the expected results to the results of the provided alias's 
output. Order does not matter
+   * and as long as the result is located in any index of expected and any 
line of the output then this will pass.
+   * 
+   * @param alias The alias whose results we want to check
+   * @param expected The expected results
+   */
+  public void assertOutputAnyOrder(String alias, String[] expected) throws 
IOException, ParseException {
+    assertOutput(alias, expected, true);
+  }
+  
+  public void assertOutput(String alias, String[] expected) throws 
IOException, ParseException {
+    assertOutput(alias, expected, false);
   }
 
-  public void assertOutput(String alias, File expected) throws IOException, 
ParseException {
+  private void assertOutput(String alias, String[] expected, boolean 
ignoreOrder) throws IOException, ParseException {
     registerScript();
 
-    assertEquals(readFile(expected).replaceAll("\r\n", "\n"), 
StringUtils.join(getAliasFromCache(alias), "\n"));
+    if (ignoreOrder) {
+      Arrays.sort(expected);
+    }
+    assertEquals(StringUtils.join(expected, "\n"), getActualResults(alias, 
ignoreOrder));
   }
 
+  public void assertOutput(File expected) throws IOException, ParseException {
+    assertOutput(readFile(expected).split("(\\r\\n|\\n)"), false);
+  }
+  
+  public void assertOutput(String alias, File expected) throws IOException, 
ParseException {
+    assertOutput(alias, readFile(expected).split("(\\r\\n|\\n)"), false);
+  }
+  
   public void assertOutput(String aliasInput, String[] input, String alias, 
String[] expected)
       throws IOException, ParseException {
     assertOutput(aliasInput, input, alias, expected, "\\t");
   }
-
+  
   public void assertOutput(String aliasInput, String[] input, String alias, 
String[] expected, String delimiter)
       throws IOException, ParseException {
     registerScript();
@@ -292,18 +429,15 @@ public class PigTest {
     StringBuilder sb = new StringBuilder();
     Schema.stringifySchema(sb, getPigServer().dumpSchema(aliasInput), 
DataType.TUPLE) ;
 
-    final String destination = 
FileLocalizer.getTemporaryPath(getPigServer().getPigContext()).toString();
-    getCluster().copyFromLocalFile(input, destination, true);
-    override(aliasInput,
-        String.format("%s = LOAD '%s' USING PigStorage('%s') AS %s;", 
aliasInput, destination, delimiter, sb.toString()));
+    mockAlias(aliasInput, input, sb.toString(), delimiter);
 
-    assertOutput(alias, expected);
+    assertOutput(alias, expected, false);
   }
 
   protected void assertEquals(String expected, String current) {
     Assert.assertEquals(expected, current);
   }
-
+  
   private static String readFile(String path) throws IOException {
     return readFile(new File(path));
   }

Modified: pig/trunk/test/org/apache/pig/test/pigunit/TestPigTest.java
URL: 
http://svn.apache.org/viewvc/pig/trunk/test/org/apache/pig/test/pigunit/TestPigTest.java?rev=1652288&r1=1652287&r2=1652288&view=diff
==============================================================================
--- pig/trunk/test/org/apache/pig/test/pigunit/TestPigTest.java (original)
+++ pig/trunk/test/org/apache/pig/test/pigunit/TestPigTest.java Thu Jan 15 
22:19:21 2015
@@ -17,11 +17,17 @@ package org.apache.pig.test.pigunit;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.String;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.ComparisonFailure;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
@@ -432,4 +438,170 @@ public class TestPigTest {
         scriptFile.delete();
         bootupFile.delete();
     }
+
+    @Test
+    public void testMockedAliasWithDefaultDelimiter() throws Exception  {
+        String[] args = {
+                "n=3",
+                "reducers=1",
+                "input=top_queries_input_data.txt",
+                "output=top_3_queries",
+        };
+
+        test = new PigTest(PIG_SCRIPT, args, null, null);
+
+        String[] mockData = {
+                "Apache\t99",
+                "Pig\t42",
+                "GitHub\t107",
+                "Google\t404"
+        };
+        test.mockAlias("queries_ordered", mockData,"(query: chararray,count: 
int)");
+
+        String[] expectedOutput = {
+                "(Apache,99)",
+                "(Pig,42)",
+                "(GitHub,107)"
+        };
+        test.assertOutput(expectedOutput);
+    }
+
+    @Test
+    public void testMockedAliasWithDifferentDelimiter() throws Exception  {
+        String[] args = {
+                "n=3",
+                "reducers=1",
+                "input=top_queries_input_data.txt",
+                "output=top_3_queries",
+        };
+
+        test = new PigTest(PIG_SCRIPT, args, null, null);
+
+        String[] mockData = {
+                "Apache,99",
+                "Pig,42",
+                "GitHub,107",
+                "Google,404"
+        };
+        test.mockAlias("queries_ordered", mockData,"(query: chararray,count: 
int)", ",");
+
+        String[] expectedOutput = {
+                "(Apache,99)",
+                "(Pig,42)",
+                "(GitHub,107)"
+        };
+        test.assertOutput(expectedOutput);
+    }
+
+    @Test
+    public void testAliasSchemaMap() throws Exception {
+        String[] args = {
+                "n=3",
+                "reducers=1",
+                "input=top_queries_input_data.txt",
+                "output=top_3_queries",
+        };
+
+        test = new PigTest(PIG_SCRIPT, args, null, null);
+        
+        final Map<String, String> expected = new HashMap<String, String>();
+        expected.put("data", "(query: chararray,count: int)");
+        expected.put("queries_group", "(group: chararray,data: {(query: 
chararray,count: int)})");
+        expected.put("queries_sum", "(query: chararray,count: long)");
+        expected.put("queries_ordered", "(query: chararray,count: long)");
+        expected.put("queries_limit", "(query: chararray,count: long)");
+        Map<String, String> map = test.getAliasToSchemaMap();
+        
+        assertEquals(expected, map);
+    }
+    
+    @Test
+    public void testAnyOrderOutput() throws Exception  {
+        String[] args = {
+                "n=3",
+                "reducers=1",
+                "input=top_queries_input_data.txt",
+                "output=top_3_queries",
+        };
+
+        test = new PigTest(PIG_SCRIPT, args);
+
+        String[] reorderedExpectedOutput = {
+                "(twitter,7)",
+                "(yahoo,25)",
+                "(facebook,15)"
+        };
+        test.assertOutputAnyOrder(reorderedExpectedOutput);
+    }
+    
+    @Test
+    public void testAnyOrderOutputForAlias() throws Exception  {
+        String[] args = {
+                "n=3",
+                "reducers=1",
+                "input=top_queries_input_data.txt",
+                "output=top_3_queries",
+        };
+
+        test = new PigTest(PIG_SCRIPT, args);
+
+        String[] reorderedExpectedOutput = {
+                "(twitter,7)",
+                "(yahoo,25)",
+                "(facebook,15)"
+        };
+        test.assertOutputAnyOrder("queries_limit", reorderedExpectedOutput);
+    }
+    
+    @Test
+    public void testSpecificOrderOutput() throws Exception  {
+        String[] args = {
+                "n=3",
+                "reducers=1",
+                "input=top_queries_input_data.txt",
+                "output=top_3_queries",
+        };
+
+        test = new PigTest(PIG_SCRIPT, args);
+
+        String[] reorderedExpectedOutput = {
+                "(twitter,7)",
+                "(yahoo,25)",
+                "(facebook,15)"
+        };
+        
+        try {
+            test.assertOutput(reorderedExpectedOutput);
+            fail("assertOutput should fail when the records are unordered.");
+        }
+        catch(ComparisonFailure e) {
+            //Test passes
+        }
+    }
+    
+    @Test
+    public void testSpecificOrderOutputForAlias() throws Exception  {
+        String[] args = {
+                "n=3",
+                "reducers=1",
+                "input=top_queries_input_data.txt",
+                "output=top_3_queries",
+        };
+
+        test = new PigTest(PIG_SCRIPT, args);
+
+        String[] reorderedExpectedOutput = {
+                "(twitter,7)",
+                "(yahoo,25)",
+                "(facebook,15)"
+        };
+        
+        try {
+            test.assertOutput("queries_limit", reorderedExpectedOutput);
+            fail("assertOutput should fail when the records are unordered.");
+        }
+        catch(ComparisonFailure e) {
+            //Test passes
+        }
+    }
 }


Reply via email to