faassen / bowerstatic

Serve Bower-managed static resources using WSGI
BSD 3-Clause "New" or "Revised" License
49 stars 17 forks source link

Test test_local_with_auto_version is broken #20

Closed icemac closed 10 years ago

icemac commented 10 years ago

The test test_local_with_auto_version fails to run because the timestamp rendered by autoversion() does not match the expected time format.

I'm not sure what is intended here, so I don't know how to fix it.

faassen commented 10 years ago

This looks like a bug. What platform are you on? Could you post a traceback?

icemac commented 10 years ago

I'm running on Mac OS X, Python 2.7.8. See the following traceback:

$ bin/py.test bowerstatic
=========================================================================================================== test session starts ============================================================================================================
platform darwin -- Python 2.7.8 -- py-1.4.24 -- pytest-2.6.2
plugins: cov
collected 48 items

bowerstatic/tests/test_core.py ....
bowerstatic/tests/test_injector.py ....x....................
bowerstatic/tests/test_local.py ......F
bowerstatic/tests/test_publisher.py ............

================================================================================================================= FAILURES =================================================================================================================
_______________________________________________________________________________________________________ test_local_with_auto_version _______________________________________________________________________________________________________

tmpdir = local('/private/var/folders/z_/t859k7rd2f55v89hj1zhsxnw0000gp/T/pytest-11/test_local_with_auto_version0')

    def test_local_with_auto_version(tmpdir):
        # need to cut things a bit of slack, as filesystem time can apparently
        # be ahead slightly
        after_dt = datetime.now() - timedelta(seconds=1)

        # create a bower component directory
        component_dir = tmpdir.mkdir('component')
        bower_json_file = component_dir.join('bower.json')
        bower_json_file.write(json.dumps({
            'name': 'component',
            'version': '2.1',  # should be ignored
            'main': 'main.js'
        }))
        main_js_file = component_dir.join('main.js')
        main_js_file.write('/* this is main.js */')

        # now expose it through local
        bower = bowerstatic.Bower()

        components = bower.components('components', os.path.join(
            os.path.dirname(__file__), 'bower_components'))

        local = bower.local_components('local', components)

        local.component(component_dir.strpath, version=None)

        def wsgi(environ, start_response):
            start_response('200 OK', [('Content-Type', 'text/html;charset=UTF-8')])
            include = local.includer(environ)
            include('component/main.js')
            return ['<html><head></head><body>Hello!</body></html>']

        wrapped = bower.wrap(wsgi)

        c = Client(wrapped)

        response = c.get('/')
        before_dt = datetime.now()

        def get_url_dt(response):
            s = unicode(response.body, 'UTF-8')
            start = s.find('src="') + len('src="')
            end = s.find('"', start)
            url = s[start:end]
            parts = url.split('/')
            url_dt_str = parts[4]
            url_dt = datetime.strptime(url_dt_str, '%Y-%m-%dT%H:%M:%S.%f')
            return url_dt_str, url_dt

>       url_dt_str, url_dt = get_url_dt(response)

bowerstatic/tests/test_local.py:264:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
bowerstatic/tests/test_local.py:261: in get_url_dt
    url_dt = datetime.strptime(url_dt_str, '%Y-%m-%dT%H:%M:%S.%f')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

data_string = '2014-09-22T14:08:4', format = '%Y-%m-%dT%H:%M:%S.%f'

    def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
        """Return a time struct based on the input string and the format string."""
        global _TimeRE_cache, _regex_cache
        with _cache_lock:
            if _getlang() != _TimeRE_cache.locale_time.lang:
                _TimeRE_cache = TimeRE()
                _regex_cache.clear()
            if len(_regex_cache) > _CACHE_MAX_SIZE:
                _regex_cache.clear()
            locale_time = _TimeRE_cache.locale_time
            format_regex = _regex_cache.get(format)
            if not format_regex:
                try:
                    format_regex = _TimeRE_cache.compile(format)
                # KeyError raised when a bad format is found; can be specified as
                # \\, in which case it was a stray % but with a space after it
                except KeyError, err:
                    bad_directive = err.args[0]
                    if bad_directive == "\\":
                        bad_directive = "%"
                    del err
                    raise ValueError("'%s' is a bad directive in format '%s'" %
                                        (bad_directive, format))
                # IndexError only occurs when the format string is "%"
                except IndexError:
                    raise ValueError("stray %% in format '%s'" % format)
                _regex_cache[format] = format_regex
        found = format_regex.match(data_string)
        if not found:
            raise ValueError("time data %r does not match format %r" %
>                            (data_string, format))
E           ValueError: time data '2014-09-22T14:08:4' does not match format '%Y-%m-%dT%H:%M:%S.%f'

/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_strptime.py:325: ValueError
============================================================================================== 1 failed, 46 passed, 1 xfailed in 0.70 seconds ==============================================================================================
faassen commented 10 years ago

Thanks! I'm on Linux. This helps.

The format you get is "2014-09-22T14:08:4" while the format expected is something like "2014-09-22T14:08:40.3".

This timestamp is generated through bowerstatic.autoversion.autoversion(). Apparently it gives back a different format without subsecond granularity when getmtime() is used on Mac OS X. The problem is compounded by the [:-1] it did on the resulting isoformat for no real reason; it would cut off the last bit of subsecond granularity on Linux which does no harm, but on Mac OS X what is cut off is the '0' from the ":40" and this is highly problematic.

In combination with this the test is expecting sub-second granularity in time stamps.

I think second granularity for a cache-busting URL like this is enough on all platform, so I've adjusted the code to throw away the sub-second information instead. I also adjusted things so that the test assuming subsecond resolution is skipped on Mac OS X. Strictly speaking it should also be skipped on Linux ext3 (instead of ext4) but I'm ignoring that issue for now as I don't know how to easily do this.

faassen commented 10 years ago

Could you try running the tests in the latest trunk to see whether you still get this error?

icemac commented 10 years ago

I no longer get this error.