pytest migration: convert simple functional tests to TestControllerPytest
Replace usage of TestController with TestControllerPytest for those files in tests/functional where there is no setUp/tearDown method (the pytest equivalent to be investigated) and that do not use test parametrization.
pytest migration: search: use tmpdir fixture instead of 'current dir'
The test_empty_search method needs to refer to an existing directory that is guaranteed to not contain a search index. The current implementation chose the 'current' directory '.' but it is more of a hack than careful planning. A temporary empty directory would be cleaner but was more involved to create.
With the introduction of pytest-style test classes, this can very easily be improved. Creating a temporary directory with pytest is as simple as accepting the magic 'tmpdir' argument to the test method. This 'tmpdir' is a fixture provided by pytest. The variable is initialized with a py.path.local object referring a temporary directory. For details, see: http://pytest.org/latest/tmpdir.html
In order to allow tests to benefit from pytest specific functionality, like fixtures, they can no longer derive from unittest.TestCase. What's more, while they can derive from any user-defined class, none of the classes involved (the test class itself nor any of the base classes) can have an __init__ method.
Converting all tests from unittest-style to pytest-style in one commit is not realistic. Hence, a more gradual approach is needed.
Most existing test classes derive from TestController, which in turn derives from BaseTestCase, which derives from unittest.TestCase. Some test classes derive directly from BaseTestCase. Supporting both unittest-style and pytest-style from TestController directly is not possible: pytest-style _cannot_ and unittest-style _must_ derive from unittest.TestCase. Thus, in any case, an extra level in the class hierarchy is needed (TestController deriving from Foo and from unittest.TestCase; pytest-style test classes would then directly derive from Foo).
The requirement that pytest-style test classes cannot have an __init__ method anywhere in the class hierarchy imposes another restriction that makes it difficult to support both unittest-style and pytest-style test classes with one class. Any init code needs to be placed in another method than __init__ and be called explicitly when the test class is initialized. For unittest-style test classes this would naturally be done with a setupClass method, but several test classes already use that. Thus, there would need to be explicit 'super' calls from the test classes. This is technically possible but not very nice.
A more transparent approach (from the existing test classes point of view), implemented by this patch, works as follows: - the implementation of the existing TestController class is now put under a new class BaseTestController. To accomodate pytest, the __init__ method is renamed init. - contrary to the original TestController, BaseTestController does not derive from BaseTestCase (and neither from unittest.TestCase). Instead, the 'new' TestController derives both from BaseTestCase, which is untouched, and from BaseTestController. - TestController has an __init__ method that calls the base classes' __init__ methods and the renamed 'init' method of BaseTestController. - a new class TestControllerPytest is introduced that derives from BaseTestController but not from BaseTestCase. It uses a pytest fixture to automatically call the setup functionality previously provided by BaseTestCase and also calls 'init' on BaseTestController. This means a little code duplication but is hard to avoid.
The app setup fixture is scoped on the test method, which means that the app is recreated for every test (unlike for the unittest-style tests where the app is created per test class). This has the advantage of detecting current inter-test dependencies and thus improve the health of our test suite. This in turn is one step closer to allowing parallel test execution.
The unittest-style assert methods (assertEqual, assertIn, ...) do not exist for pytest-style tests. To avoid having to change all existing test cases upfront, provide transitional implementations of these methods. The conversion of the unittest asserts to the pytest/python asserts can happen gradually over time.
Test test_index_trending depended on previous actions performed by the test test_index_statistics. Such inter-test dependencies should not be present.
This would become a problem when converting the test class to pytest-style, because the app is recreated for each test, while the original TestController creates it once per class.
tests: move remove_all_notifications outside of BaseTestCase
In preparation of allowing real pytest-style test cases (instead of unittest-style ones), some reorganization is needed in the base test classes, for one because we want a transition period where pytest and unittest style test cases can live alongside each other, and secondly because the pytest style test classes cannot have an __init__ method.
The BaseTestCase class will not be reused for the pytest test cases, but the remove_all_notifications method will. To avoid having to duplicate it, and since it does not use any resources from the class (self), move the method out of the BaseTestCase class to top-level, and export it in kallithea.tests.
pytest migration: use pytest test skipping instead of nose's
While the nose test skipping still worked, we want to remove all remnants of nose, so switch to the pytest equivalent.
Note: due to a bug in pytest-sugar (reported at [1]) the skipped tests are not shown explicitly when using the 'skipif' approach, while they were with the nose approach. Since pytest-sugar is not enabled yet in setup.py, this is not deemed a problem.
tests: gists: comment out always-skipped test of put functionality
There is little sense in always skipping a test because the tested functionality is not implemented. Instead, comment out the test and leave it to the future implementer to re-enable it.
middleware: allow git and hg users to use email address instead of the username
This commit also replaces __get_user('default') with a call to a more widely used User.get_default_user() function, and removes no longer really used __get_user() methods from both SimpleHg and SimpleGit.
auth: authenticate using either username or email address
Use User.get_by_username_or_email() in get_user. In authenticate(), update username if get_user succeeds.
The point of this change is that the web login is a complex thing that includes, apart the authentication itself, form validation and a bunch of other things.
This change on its own makes it possible to authenticate a user using its email address, but that on its own isn't enough for web login or git/hg auth.
db: match case-insensitively using func.lower, not ilike
ilike() uses SQL ILIKE operator internally, which means it interprets '%' and '_' in the match pattern as wildcards. Instead of ilike(), it's better to turn both operands to the lower case and compare them.
This also unbreaks the test case introduced in 13d0fe6f751a.
This commit removes case-sensitive email matching. It also adds a couple of tests which fail, to demonstrate a defect in the current implementation (using ILIKE matching instead of case-insensitive equality comparison).
pullrequests: show tags in lists of included and available changesets
Further improvement: Also show bookmarks and other names (preferably by using some helper function/template instead of duplicating code). It would perhaps also be better to avoid using floating.
The table is populated on database creation, and assumed to be populated so many places in the code, we're unlikely to even reach this point if it's empty. (E.g. web.push_ssl must be defined to push/pull/fetch both Mercurial and Git repositories.)
Only newly created objects (and objects explicitly expunged) need to be added to the SQLAlchemy session; any object returned from a database query is already in the session.
comments: change comment formatting to plain text instead of rst
There might be value in enabling rich markup (especially if it is markdown instead of rst) ... or it might be a waste of time. We might revisit that later.
But either way: Changing to plain text makes it more feasible to do markup of hashes and issues - for now that is more important than rtf.
Eventually this function should support and auto detect multiple formats and is thus not named for a specific format. But for now it is plain text only.
This kind of markup can quite easily and safely support additional magic markup. It is much harder to do that on top of a richer markup format; it must essentially be done in a single pass, with both all the various regexps and the rst formatting done in a single pass.
db: make sure all (non-primary) columns have nullable set explicitly
The default of nullable=True is rarely good for us so nullable should always be specified unless there is a reason to allow nullable ... and if the default is fine, xplicit is better than implicit.
The declared nulliness of some fields are changed where it seems like code already enforced it.
Some fields are marked as FIXME when they need (trivial?) data conversion to convert NULLs to default values.
tests: cleanup of unicode in test_create_non_ascii repository test
Repository names are generally conceptually unicode. Prepare for future changes by explicitly encoding repo_name as utf8 before appending a utf8 string.
Drop test_create_non_ascii - test_delete_non_ascii contains exactly the same test.