Added py_test rule to Bazel

py_test rule enable to use a test written in Python. A py_test is
basically a py_binary that returns a non null on failure. Extraneous
support is need to have nice output (see //src/test/shell/unittest.bash
for the kind of support neeeded).

Actually the py_test code was already there but it was just missing the
necessary glue code. Also added an integration test for py_* rules in
Bazel.

--
MOS_MIGRATED_REVID=91407748
diff --git a/examples/BUILD b/examples/BUILD
index 0e42866..3ce954e 100644
--- a/examples/BUILD
+++ b/examples/BUILD
@@ -10,5 +10,6 @@
         "//examples/objc:srcs",
         "//examples/proto:srcs",
         "//examples/py:srcs",
+        "//examples/py_native:srcs",
     ],
 )
diff --git a/examples/py_native/BUILD b/examples/py_native/BUILD
index 3d8de94..d6fdfa9 100644
--- a/examples/py_native/BUILD
+++ b/examples/py_native/BUILD
@@ -1,3 +1,9 @@
+filegroup(
+    name = "srcs",
+    srcs = glob(["*.py"]) + ["BUILD"],
+    visibility = ["//examples:__pkg__"],
+)
+
 py_binary(
     name = "bin",
     srcs = ["bin.py"],
@@ -8,3 +14,15 @@
     name = "lib",
     srcs = ["lib.py"],
 )
+
+py_test(
+    name = "test",
+    srcs = ["test.py"],
+    deps = [":lib"],
+)
+
+py_test(
+    name = "fail",
+    srcs = ["fail.py"],
+    deps = [":lib"],
+)
diff --git a/examples/py_native/fail.py b/examples/py_native/fail.py
new file mode 100644
index 0000000..98e35f4
--- /dev/null
+++ b/examples/py_native/fail.py
@@ -0,0 +1,13 @@
+"""A tiny example binary for the native Python rules of Bazel."""
+import unittest
+from examples.py_native.lib import GetNumber
+
+
+class TestGetNumber(unittest.TestCase):
+
+  def test_fail(self):
+    self.assertEquals(GetNumber(), 0)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/examples/py_native/test.py b/examples/py_native/test.py
new file mode 100644
index 0000000..811eee1
--- /dev/null
+++ b/examples/py_native/test.py
@@ -0,0 +1,13 @@
+"""A tiny example binary for the native Python rules of Bazel."""
+import unittest
+from examples.py_native.lib import GetNumber
+
+
+class TestGetNumber(unittest.TestCase):
+
+  def test_ok(self):
+    self.assertEquals(GetNumber(), 42)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 94e64ff..feb1402 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -47,6 +47,7 @@
 import com.google.devtools.build.lib.bazel.rules.python.BazelPyBinaryRule;
 import com.google.devtools.build.lib.bazel.rules.python.BazelPyLibraryRule;
 import com.google.devtools.build.lib.bazel.rules.python.BazelPyRuleClasses;
+import com.google.devtools.build.lib.bazel.rules.python.BazelPyTestRule;
 import com.google.devtools.build.lib.bazel.rules.sh.BazelShBinaryRule;
 import com.google.devtools.build.lib.bazel.rules.sh.BazelShLibraryRule;
 import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses;
@@ -240,6 +241,7 @@
     builder.addRuleDefinition(new BazelPyRuleClasses.PyBinaryBaseRule());
     builder.addRuleDefinition(new BazelPyLibraryRule());
     builder.addRuleDefinition(new BazelPyBinaryRule());
+    builder.addRuleDefinition(new BazelPyTestRule());
 
     builder.addWorkspaceFile(BazelJavaRuleClasses.getDefaultWorkspace());
     builder.addRuleDefinition(new BazelJavaRuleClasses.BaseJavaBinaryRule());
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTest.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTest.java
new file mode 100644
index 0000000..15e035d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTest.java
@@ -0,0 +1,28 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// 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.google.devtools.build.lib.bazel.rules.python;
+
+import com.google.devtools.build.lib.rules.python.PyTest;
+import com.google.devtools.build.lib.rules.python.PythonSemantics;
+
+/**
+ * Implementation of the {@code py_test} rule for Bazel.
+ */
+public class BazelPyTest extends PyTest {
+  @Override
+  protected PythonSemantics createSemantics() {
+    return new BazelPythonSemantics();
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTestRule.java
new file mode 100644
index 0000000..38b2811
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTestRule.java
@@ -0,0 +1,95 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// 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.google.devtools.build.lib.bazel.rules.python;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.TRISTATE;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.python.BazelPyRuleClasses.PyBinaryBaseRule;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.packages.TriState;
+
+/**
+ * Rule definition for the py_test rule.
+ */
+public final class BazelPyTestRule implements RuleDefinition {
+  @Override
+  public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
+    return builder
+        .override(attr("testonly", BOOLEAN).value(true)
+            .nonconfigurable("policy decision: should be consistent across configurations"))
+        /* <!-- #BLAZE_RULE(py_test).ATTRIBUTE(stamp) -->
+        ${SYNOPSIS}
+        See the section on <a href="#py_binary_args">py_binary()</a> arguments, except
+        that the stamp argument is set to 0 by default for tests.
+        <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+        .override(attr("stamp", TRISTATE).value(TriState.NO))
+        .build();
+  }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("py_test")
+        .type(RuleClassType.TEST)
+        .ancestors(PyBinaryBaseRule.class, BaseRuleClasses.TestBaseRule.class)
+        .factoryClass(BazelPyTest.class)
+        .build();
+  }
+}
+
+/*<!-- #BLAZE_RULE (NAME = py_test, TYPE = TEST, FAMILY = Python) -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>
+A <code>py_test()</code> rule compiles a test.  A test is a binary wrapper
+ around some test code.</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="py_test_examples">Examples</h4>
+
+<p>
+<pre class="code">
+py_test(
+    name = "runtest_test",
+    srcs = ["runtest_test.py"],
+    deps = [
+        "//path/to/a/py/library",
+    ],
+)
+</pre>
+
+<p>It's also possible to specify a main module:</p>
+
+<pre class="code">
+py_binary(
+    name = "foo",
+    srcs = [
+        "bar.py",
+        "baz.py",
+    ],
+    main = "bar.py",
+)
+</pre>
+
+<!-- #END_BLAZE_RULE -->*/
+
diff --git a/src/test/shell/bazel/bazel_example_test.sh b/src/test/shell/bazel/bazel_example_test.sh
index 4165846..4b127c2 100755
--- a/src/test/shell/bazel/bazel_example_test.sh
+++ b/src/test/shell/bazel/bazel_example_test.sh
@@ -97,6 +97,12 @@
   }
 }
 
+function test_native_python() {
+  assert_build "//examples/py_native:bin"
+  assert_test_ok "//examples/py_native:test"
+  assert_test_fails "//examples/py_native:fail"
+}
+
 #
 # Skylark rules
 #
diff --git a/tools/BUILD b/tools/BUILD
index 41b4e23..39af650 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -12,5 +12,6 @@
         "//tools/cpp:srcs",
         "//tools/objc:srcs",
         "//tools/test:srcs",
+        "//tools/python:srcs",
     ],
 )
diff --git a/tools/python/BUILD b/tools/python/BUILD
index f489fe1..6933f9d 100644
--- a/tools/python/BUILD
+++ b/tools/python/BUILD
@@ -4,3 +4,12 @@
     name = "2to3",
     srcs = ["2to3.sh"],
 )
+
+filegroup(
+    name = "srcs",
+    srcs = [
+        # Tools are build from the workspace for tests.
+        "2to3.sh",
+        "BUILD",
+    ],
+)