Permalink
Browse files

Got validation flow up and running

  • Loading branch information...
1 parent 54adc76 commit dd4a9c253af3ba6bae11b9979f8425951ea92a41 @mattbasta mattbasta committed Aug 6, 2012
View
6 README.rst
@@ -84,7 +84,7 @@ your environment.
Run the validator as follows ::
- python app-validator <path to app> [-o <output type>] [-v] [--boring] [--selfhosted] [--determined]
+ python app-validator <path to app> [-o <output type>] [-v] [--boring] [--selfhosted]
The path to the XPI should point to an XPI file.
@@ -97,10 +97,6 @@ The path to the XPI should point to an XPI file.
--selfhosted Disables messages that are specific to add-ons hosted on
AMO.
--boring Disables colorful shell output.
---determined Continue validating the remaining tiers of an add-on if one
- tier has failed. Certain high-tiered tests may
- inadvertently fail when this option is enabled for badly
- malformed add-ons.
Output Type:
============
View
4 app-validator
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-import validator.main
+import appvalidator.main
if __name__ == '__main__':
- validator.main.main()
+ appvalidator.main.main()
View
30 appvalidator/constants.py
@@ -5,40 +5,17 @@
# Package type constants.
PACKAGE_ANY = 0
-PACKAGE_EXTENSION = 1
-PACKAGE_THEME = 2
-PACKAGE_DICTIONARY = 3
-PACKAGE_LANGPACK = 4
-PACKAGE_SEARCHPROV = 5
-PACKAGE_MULTI = 1 # A multi extension is an extension
-PACKAGE_SUBPACKAGE = 7
PACKAGE_WEBAPP = 8
-
-# Application GUIDs
-FIREFOX_GUID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
-MOZILLA_GUID = "{86c18b42-e466-45a9-ae7a-9b95ba6f5640}"
-THUNDERBIRD_GUID = "{3550f703-e582-4d05-9a08-453d09bdfdc6}"
-SUNBIRD_GUID = "{718e30fb-e89b-41dd-9da7-e25a45638b28}"
-SEAMONKEY_GUID = "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}"
-FENNEC_GUID = "{a23983c0-fd0e-11dc-95ff-0800200c9a66}"
-ANDROID_GUID = "{aa3c5121-dab2-40e2-81ca-7ea25febc110}"
-
-APPLICATIONS = {
- FIREFOX_GUID: "firefox",
- MOZILLA_GUID: "mozilla",
- THUNDERBIRD_GUID: "thunderbird",
- SUNBIRD_GUID: "sunbird",
- SEAMONKEY_GUID: "seamonkey",
- FENNEC_GUID: "fennec",
- ANDROID_GUID: "android",
-}
+PACKAGE_PACKAGED_WEBAPP = 9
SPIDERMONKEY_INSTALLATION = os.environ.get("SPIDERMONKEY_INSTALLATION")
DEFAULT_WEBAPP_MRKT_URLS = ["https://marketplace.mozilla.org",
"https://marketplace-dev.allizom.org"]
BUGZILLA_BUG = "https://bugzilla.mozilla.org/show_bug.cgi?id=%d"
+DEFAULT_TIMEOUT = 60
+
# Graciously provided by @kumar in bug 614574
if (not SPIDERMONKEY_INSTALLATION or
not os.path.exists(SPIDERMONKEY_INSTALLATION)):
@@ -60,4 +37,3 @@
from constants_local import *
except ImportError:
pass
-
View
23 appvalidator/main.py
@@ -5,7 +5,7 @@
import zipfile
from StringIO import StringIO
-from .validate import validate
+from .validate import validate_app, validate_packaged_app
from constants import *
@@ -38,11 +38,6 @@ def main():
const=True,
help="""Activating this flag will remove color
support from the terminal.""")
- parser.add_argument("--determined",
- action="store_const",
- const=True,
- help="""This flag will continue running tests in
- successive tests even if a lower tier fails.""")
parser.add_argument("--selfhosted",
action="store_const",
const=True,
@@ -56,26 +51,14 @@ def main():
args = parser.parse_args()
- # We want to make sure that the output is expected. Parse out the expected
- # type for the add-on and pass it in for validation.
- if args.type not in expectations:
- # Fail if the user provided invalid input.
- print "Given expectation (%s) not valid. See --help for details" % \
- args.type
- sys.exit(1)
-
try:
timeout = int(args.timeout)
except ValueError:
print "Invalid timeout. Integer expected."
sys.exit(1)
- expectation = expectations[args.type]
- error_bundle = validate(args.package,
- format=None,
- determined=args.determined,
- listed=not args.selfhosted,
- timeout=timeout)
+ error_bundle = validate_packaged_app(
+ args.package, listed=not args.selfhosted, format=None, timeout=timeout)
# Print the output of the tests based on the requested format.
if args.output == "text":
View
51 appvalidator/submain.py
@@ -10,16 +10,6 @@
from constants import *
-types = {0: "Unknown",
- 1: "Extension/Multi-Extension",
- 2: "Theme",
- 3: "Dictionary",
- 4: "Language Pack",
- 5: "Search Provider"}
-
-assumed_extensions = {"jar": PACKAGE_THEME,
- "xml": PACKAGE_SEARCHPROV}
-
log = logging.getLogger()
@@ -39,29 +29,30 @@ def prepare_package(err, path, timeout=None):
If timeout is -1 then no timeout checking code will run.
"""
if not timeout:
- timeout = 60 # seconds
+ timeout = DEFAULT_TIMEOUT # seconds
# Test that the package actually exists. I consider this Tier 0
# since we may not even be dealing with a real file.
if not os.path.isfile(path):
- err.error(
+ return err.error(
err_id=("main", "prepare_package", "not_found"),
error="The package could not be found")
- return
# Pop the package extension.
package_extension = os.path.splitext(path)[1]
package_extension = package_extension.lower()
if package_extension == ".webapp":
- return test_webapp(err, path)
+ detect_webapp(err, path)
+ err.set_type(PACKAGE_WEBAPP)
+ return err
validation_state = {'complete': False}
def timeout_handler(signum, frame):
if validation_state['complete']:
# There is no need for a timeout. This might be the result of
# sequential validators, like in the test suite.
- return
+ return err
ex = ValidationTimeout(timeout)
log.error("%s; Package: %s" % (str(ex), path))
raise ex
@@ -70,18 +61,11 @@ def timeout_handler(signum, frame):
if timeout != -1:
signal.signal(signal.SIGALRM, timeout_handler)
signal.setitimer(signal.ITIMER_REAL, timeout)
- output = test_package(err, package, path)
+ test_package(err, package, path)
validation_state['complete'] = True
- return output
-
-
-def test_webapp(err, package):
- "Tests the package to see if it is a webapp."
-
- detect_webapp(err, package)
- err.set_type(PACKAGE_WEBAPP)
+ return err
def test_package(err, file_, name):
@@ -98,27 +82,26 @@ def test_package(err, file_, name):
except (BadZipfile, zlib_error):
# Die if the zip file is corrupt.
return err.error(
- err_id=("submain", "_load_install_rdf", "badzipfile"),
- error="Corrupt ZIP file",
- description="We were unable to decompress the zip file.")
+ err_id=("submain", "_load_install_rdf", "badzipfile"),
+ error="Corrupt ZIP file",
+ description="We were unable to decompress the zip file.")
try:
output = test_inner_package(err, package)
except ValidationTimeout as ex:
err.error(
- err_id=("main", "test_package", "timeout"),
- error="Validation timed out",
- description=["The validation process took too long to "
- "complete. Contact an addons.mozilla.org editor "
- "for more information.",
- str(ex)])
+ err_id=("main", "test_package", "timeout"),
+ error="Validation timed out",
+ description=["The validation process took too long to complete. "
+ "Contact an addons.mozilla.org editor for more "
+ "information.", str(ex)])
output = None
return output
def test_inner_package(err, package):
- "Tests a package's inner content."
+ """Tests a package's inner content."""
# Iterate through each tier.
for tier in sorted(decorator.get_tiers()):
View
2 appvalidator/testcases/javascript/actions.py
@@ -6,7 +6,7 @@
import spidermonkey
import instanceactions
import instanceproperties
-from appvalidator.constants import BUGZILLA_BUG, FENNEC_GUID, FIREFOX_GUID
+from appvalidator.constants import BUGZILLA_BUG
from jstypes import *
View
3 appvalidator/testcases/packagelayout.py
@@ -1,8 +1,5 @@
from fnmatch import fnmatch as fnm
-from ..constants import (FIREFOX_GUID, FENNEC_GUID,
- THUNDERBIRD_GUID as TB_GUID, ANDROID_GUID,
- PACKAGE_DICTIONARY, )
from .. import decorator
# Detect blacklisted files based on their extension.
View
2 appvalidator/testcases/scripting.py
@@ -5,7 +5,7 @@
import javascript.traverser as traverser
from javascript.spidermonkey import get_tree, JSReflectException
-from appvalidator.constants import PACKAGE_THEME, SPIDERMONKEY_INSTALLATION
+from appvalidator.constants import SPIDERMONKEY_INSTALLATION
from ..contextgenerator import ContextGenerator
from ..textfilter import *
View
1 appvalidator/textfilter.py
@@ -16,4 +16,3 @@ def filter_ascii(text):
if isinstance(text, list):
return [filter_ascii(x) for x in text]
return "".join((x if is_standard_ascii(x) else "?") for x in text)
-
View
32 appvalidator/validate.py
@@ -23,11 +23,6 @@ def validate_app(data, listed=True, market_urls=None):
- App validation is always determined because there is only one tier.
- Spidermonkey paths are not accepted by this function because we don't
perform JavaScript validation on webapps.
- - We don't accept a flag for compatibility because there are no
- compatibility tests for apps, nor will there likely ever be. The same
- goes for associated parameters (i.e.: for_appversions).
- - `approved_applications` is not set because apps are not bound to
- individual Mozilla apps.
"""
bundle = ErrorBundle(listed=listed, determined=True)
@@ -38,6 +33,33 @@ def validate_app(data, listed=True, market_urls=None):
return format_result(bundle, "json")
+def validate_packaged_app(path, listed=True, format="json", market_urls=None,
+ timeout=None):
+ """
+ A handy function for validating apps.
+
+ `path`:
+ The path to the packaged app.
+ `listed`:
+ Whether the app is headed for the app marketplace.
+ `format`:
+ The output format to return the results in.
+ `market_urls`:
+ A list of URLs to use when validating the `installs_allowed_from`
+ field of the manifest. Does not apply if `listed` is not set to `True`.
+ `timeout`:
+ The amount of time (in seconds) that the validation process may take.
+ When this value is `None`, timeouts are disabled.
+ """
+ bundle = ErrorBundle(listed=listed)
+
+ # Set the market URLs.
+ set_market_urls(market_urls)
+
+ submain.prepare_package(bundle, path, timeout)
+ return format_result(bundle, format)
+
+
def format_result(bundle, format):
# Write the results to the pipe
formats = {"json": lambda b: b.render_json()}
View
3 appvalidator/zip.py
@@ -15,15 +15,14 @@ class ZipPackage(object):
worry about things like zip files or IO.
"""
- def __init__(self, package, mode="r", name=None, subpackage=False):
+ def __init__(self, package, mode="r", name=None):
"Create a new managed XPI package"
self.zf = ZipFile(package, mode=mode)
# Store away the filename for future use.
self.filename = name or package
self.extension = self.filename.split(".")[-1]
- self.subpackage = subpackage
self.contents_cache = None
View
11 tests/helper.py
@@ -40,7 +40,7 @@ def reset(self):
"""
self.err = None
- def setup_err(self, for_appversions=None):
+ def setup_err(self):
"""
Instantiate the error bundle object. Use the `instant` parameter to
have it output errors as they're generated. `for_appversions` may be set
@@ -120,12 +120,11 @@ def namelist(self):
class MockXPI:
- def __init__(self, data=None, subpackage=False):
+ def __init__(self, data=None):
if not data:
data = {}
self.zf = MockZipFile()
self.data = data
- self.subpackage = subpackage
self.filename = "mock_xpi.xpi"
def test(self):
@@ -136,10 +135,8 @@ def info(self, name):
"extension": name.lower().split(".")[-1]}
def __iter__(self):
- def i():
- for name in self.data.keys():
- yield name
- return i()
+ for name in self.data.keys():
+ yield name
def __contains__(self, name):
return name in self.data
View
25 tests/js/js_helper.py
@@ -11,13 +11,6 @@
appvalidator.testcases.scripting.traverser.DEBUG = True
-def _do_test(path):
- "Performs a test on a JS file"
-
- script = open(path).read()
- return _do_test_raw(script, path)
-
-
def _do_test_raw(script, path="foo.js"):
"Performs a test on a JS file"
@@ -31,22 +24,6 @@ def _do_test_raw(script, path="foo.js"):
return err
-def _do_real_test_raw(script, path="foo.js", versions=None, metadata=None,
- resources=None):
- """Perform a JS test using a non-mock bundler."""
-
- err = ErrorBundle(for_appversions=versions or {})
- if detected_type:
- err.detected_type = detected_type
- if metadata is not None:
- err.metadata = metadata
- if resources is not None:
- err.resources = resources
-
- appvalidator.testcases.content._process_file(err, MockXPI(), path, script)
- return err
-
-
def _get_var(err, name):
return err.final_context.data[name].get_literal_value()
@@ -109,5 +86,5 @@ def assert_var_eq(self, name, value):
Assert that the value of a variable from the final script context
contains the value specified.
"""
- self.assertEqual(self.get_var(name), value)
+ eq_(self.get_var(name), value)
View
114 tests/js/test_basicstrings.py
@@ -1,47 +1,69 @@
-from js_helper import _do_test, _do_test_raw, _get_var
-
-def test_basic_concatenation():
- "Tests that contexts work and that basic concat ops are executed properly"
-
- err = _do_test("tests/resources/javascript/basicstrings.js")
- assert err.message_count == 0
-
- assert _get_var(err, "x") == "foo"
- assert _get_var(err, "y") == "bar"
- assert _get_var(err, "z") == "foobar"
- assert _get_var(err, "a") == "5"
- assert _get_var(err, "b") == "6"
- assert _get_var(err, "c") == "56"
- assert _get_var(err, "d") == 1
- assert _get_var(err, "e") == 30
- assert _get_var(err, "f") == 5
-
-def test_augconcat():
- "Tests augmented concatenation operators"
-
- err = _do_test_raw("""
- var x = "foo";
- x += "bar";
- """)
- assert not err.message_count
- print _get_var(err, "x")
- assert _get_var(err, "x") == "foobar"
-
- err = _do_test_raw("""
- var x = {"xyz":"foo"};
- x["xyz"] += "bar";
- """)
- assert not err.message_count
- xyz_val = err.final_context.data["x"].get(None, "xyz").get_literal_value()
- print xyz_val
- assert xyz_val == "foobar"
-
-def test_typecasting():
- "Tests that strings are treated as numbers when necessary"
-
- err = _do_test("tests/resources/javascript/strings_typecasting.js")
- assert err.message_count == 0
-
- assert _get_var(err, "x") == "44"
- assert _get_var(err, "y") == 16
+from js_helper import TestCase
+
+class TestBasicStrings(TestCase):
+ """Test that strings and their related functions are handled properly."""
+
+ def test_basic_concatenation(self):
+ """
+ Tests that contexts work and that basic concat ops are executed
+ properly.
+ """
+
+ self.run_script("""
+ var x = "foo";
+ var y = "bar";
+ var z = x + y; // foobar
+
+ var a = "5";
+ var b = "6";
+ var c = a + b; // 56
+ var d = b - a; // 1
+ var e = b * a; // 30
+ var f = "10" / "2"; // 5
+ """)
+ self.assert_silent()
+ self.assert_var_eq("x", "foo")
+ self.assert_var_eq("y", "bar")
+ self.assert_var_eq("z", "foobar")
+ self.assert_var_eq("a", "5")
+ self.assert_var_eq("b", "6")
+ self.assert_var_eq("c", "56")
+ self.assert_var_eq("d", 1)
+ self.assert_var_eq("e", 30)
+ self.assert_var_eq("f", 5)
+
+ def test_augconcat(self):
+ """Tests augmented concatenation operators."""
+
+ self.run_script("""
+ var x = "foo";
+ x += "bar";
+ """)
+ self.assert_silent()
+ self.assert_var_eq("x", "foobar")
+
+ def test_ref_augconcat(self):
+ """
+ Test that augmented concatenation happens even within referenced
+ variable placeholders.
+ """
+
+ self.run_script("""
+ var x = {"xyz":"foo"};
+ x["xyz"] += "bar";
+ var y = x.xyz;
+ """)
+ self.assert_silent()
+ self.assert_var_eq("y", "foobar")
+
+ def test_typecasting(self):
+ """Tests that strings are treated as numbers when necessary."""
+
+ self.run_script("""
+ var x = "4" + 4; // "44"
+ var y = "4" * 4; // 16
+ """)
+ self.assert_silent()
+ self.assert_var_eq("x", "44")
+ self.assert_var_eq("y", 16)
View
15 tests/js/test_bug_626878.py
@@ -1,8 +1,13 @@
-from js_helper import _do_test
+from js_helper import TestCase
-def test_double_escaped():
- """Test that escaped characters don't result in errors."""
+class TestDoubleEscape(TestCase):
- err = _do_test("tests/resources/bug_626878.js")
- assert not err.message_count
+ def test_double_escaped(self):
+ """Test that escaped characters don't result in errors."""
+
+ self.run_script("""
+ var x = "\u1234\x12"
+ var y = "\\u1234\\x12"
+ """)
+ self.assert_silent()
View
2 tests/js/test_operators.py
@@ -1,5 +1,5 @@
from nose.tools import eq_
-from js_helper import _do_real_test_raw, _do_test_raw, _do_test_scope, _get_var
+from js_helper import _do_test_raw, _do_test_scope, _get_var
def test_basic_math():
View
3 tests/resources/bug_626878.js
@@ -1,3 +0,0 @@
-var x = "\u1234\x12"
-var y = "\\u1234\\x12"
-
View
1 tests/resources/content/one_error.js
@@ -1 +0,0 @@
-var this_file_contains_a_single_error = eval("foo");
View
8 tests/resources/content/pollution_error.js
@@ -1,8 +0,0 @@
-a = 1;
-b = 2;
-c = 3;
-d = 4;
-e = 5;
-f = 6;
-g = 7;
-h = 8;
View
13 tests/resources/javascript/basicstrings.js
@@ -1,13 +0,0 @@
-var x = "foo";
-var y = "bar";
-var z = x + y; // foobar
-
-var a = "5";
-var b = "6";
-var c = a + b; // 56
-var d = b - a; // 1
-var e = b * a; // 30
-var f = "10" / "2"; // 5
-
-// TODO : Add all binary and unary operators.
-
View
2 tests/resources/javascript/strings_typecasting.js
@@ -1,2 +0,0 @@
-var x = "4" + 4; // "44"
-var y = "4" * 4; // 16
View
BIN tests/resources/packagelayout/theme.jar
Binary file not shown.
View
BIN tests/resources/packagelayout/theme_extra_unimportant.jar
Binary file not shown.
View
BIN tests/resources/typedetection/td_bad_emtype.xpi
Binary file not shown.
View
BIN tests/resources/typedetection/td_dictionary.xpi
Binary file not shown.
View
BIN tests/resources/typedetection/td_langpack.xpi
Binary file not shown.
View
BIN tests/resources/typedetection/td_multipack.xpi
Binary file not shown.
View
BIN tests/resources/typedetection/td_notype_dictionary.xpi
Binary file not shown.
View
BIN tests/resources/typedetection/td_notype_ext.xpi
Binary file not shown.
View
BIN tests/resources/typedetection/td_notype_theme.jar
Binary file not shown.

0 comments on commit dd4a9c2

Please sign in to comment.