def test_delete(self): data_cache, key, value = self.data_cache, self.key, self.value cache_fpath = self.root_dir + '/' + self.key if "called then remove cache file and returns True if it exists": data_cache.set(key, value, 1) ok(cache_fpath).is_file() # pre_cond ok(data_cache.delete(key)) == True not_ok(cache_fpath).is_file() if "called when cache file not exist then returns False": ok(data_cache.delete(key)) == False
def test_add_template(self): if "template is added then it can be got by get_template()": input = """val=#{val}""" template = tenjin.Template('foo.pyhtml', input=input) engine = tenjin.Engine(postfix='.pyhtml') engine.add_template(template) ok (engine.get_template('foo.pyhtml')) == template ok (engine.get_template(':foo')) == template if "template is added then it should not create cache file": ok (engine.render(':foo', {'val': 'ABC'})) == 'val=ABC' not_ok ('foo.pyhtml').exists()
def test_get_template(self): e1 = tenjin.Engine(path=['_views/blog', '_views'], postfix='.pyhtml') filepath = '_views/blog/index.pyhtml' fullpath = os.getcwd() + filepath cachepath = fullpath + '.cache' assert not os.path.exists(cachepath) t = None if spec("return template object.") and \ spec("accept template_name such as ':index'."): t = e1.get_template(':index') ok (t).is_a(tenjin.Template) ok (t.filename) == filepath if spec("if template object is added by add_template(), return it."): tmp = tenjin.Template('foo.pyhtml', input="<<dummy>>") e1.add_template(tmp) ok (e1.get_template('foo.pyhtml')).is_(tmp) if spec("get filepath and fullpath of template"): e1._filepaths['index.pyhtml'] == (filepath, fullpath) if spec("if template file is not found then raise TemplateNotFoundError"): def f(): e1.get_template('index') ok (f).raises(tenjin.TemplateNotFoundError, "index: filename not found (path=['_views/blog', '_views']).") if spec("use full path as base of cache file path") and \ spec("get template object from cache"): ok (list(e1.cache.items.keys())) == ["%s/_views/blog/index.pyhtml.cache" % os.getcwd()] if spec("change template filename according to prefer_fullpath"): pass if spec("use full path as base of cache file path"): pass if spec("get template object from cache"): pass if spec("if template object is not found in cache or is expired..."): e1.cache.clear() ok (len(e1.cache.items)) == 0 tname = ':layout' fpath = '_views/layout.pyhtml' cpath = os.path.join(os.getcwd(), '_views/layout.pyhtml.cache') not_ok (cpath).exists() if spec("create template object."): t = e1.get_template(tname) ok (t).is_a(tenjin.Template) if spec("set timestamp and filename of template object."): ok (t.timestamp) == os.path.getmtime(filepath) ok (t.filename) == fpath delta = JYTHON and 0.03 or 0.003 ok (t._last_checked_at).in_delta(time.time(), delta) if spec("save template object into cache."): ok (cpath).exists() ok (len(e1.cache.items)) == 1 ok (e1.cache.items).contains(cpath)
def test_has(self): data_cache, key, value = self.data_cache, self.key, self.value cache_fpath = self.root_dir + '/' + self.key if "cache file not exist then returns False": ok(data_cache.has(key)) == False if "cache file eixsts and not expired then returns True": data_cache.set(key, value, 1) ok(data_cache.has(key)) == True if "cache file eixsts but is expired then remove cache file and returns False": ok(cache_fpath).is_file() # pre_cond #time.sleep(1) now = time.time() os.utime(cache_fpath, (now - 1, now - 1)) ok(data_cache.has(key)) == False not_ok(cache_fpath).is_file()
def test_set(self): data_cache, key, value = self.data_cache, self.key, self.value cache_fpath = self.root_dir + '/' + self.key if "called then create cache file": not_ok(cache_fpath).is_file() data_cache.set(key, value, 1) ok(cache_fpath).is_file() ok(_read_file(cache_fpath)) == value if "called with lifetime then set cache file's mtime as lifetime seconds ahead": data_cache.set(key, value, 10) ok(int(os.path.getmtime(cache_fpath))) == int(time.time()) + 10 if "called without lifetime then set cache file's mtime as 1 week ahead": data_cache.set(key, value, 0) ok(int(os.path.getmtime(cache_fpath))) == int( time.time()) + 60 * 60 * 24 * 7
def test_get(self): data_cache, key, value = self.data_cache, self.key, self.value if "called before data set then returns None": ok(data_cache.get(key)) == None if "called after data set then returns value": data_cache.set(key, value, 1) ok(data_cache.get(key)) == value if "called after lifetime seconds passed then retunrs None": cache_fpath = self.root_dir + '/' + self.key ok(cache_fpath).is_file() # pre_cond #time.sleep(1) now = time.time() os.utime(cache_fpath, (now - 1, now - 1)) ok(data_cache.get(key)) == None if "called after lifetime seconds passed then remove cache file": not_ok(cache_fpath).is_file()
def test_cachefile_timestamp(self): """engine should clear cache not only template is newer but also template is older than cache.""" data = EngineTest._testdata['test_cachefile'] filenames = { 'layout': 'layout.pyhtml', 'page': 'account_create.pyhtml', 'form': 'account_form.pyhtml', } expected = data['expected'] context = { 'params': { } } cache_filenames = ['account_create.pyhtml.cache', 'account_form.pyhtml.cache'] try: interval = tenjin.Engine.timestamp_interval tenjin.Engine.timestamp_interval = 0 for key, filename in filenames.items(): write_file(filename, data[key]) props = { 'prefix': 'account_', 'postfix':'.pyhtml', 'layout':'layout.pyhtml', 'cache':True } ## create cache files and check them time.sleep(1) curr_time = time.time() engine = tenjin.Engine(**props) output = engine.render(':create', context) for fname in filenames.values(): ok (fname).exists() # file created? ok (engine.get_template(fname).timestamp) < curr_time ok (engine.get_template(fname).timestamp) == os.path.getmtime(fname) ## save current cached object cached = {} for fname in filenames.values(): cached[fname] = engine.get_template(fname) ## confirm that get_template() returns the same object for fname in filenames.values(): ok (cached[fname]).is_(engine.get_template(fname)) ## change timestamp of templates to be old for fname in filenames.values(): atime = mtime = os.path.getmtime(fname) - 10 os.utime(fname, (atime, mtime)) ## check whether new caches are created for fname in filenames.values(): t = engine.get_template(fname) not_ok (cached[fname]).is_(t) ok (t.timestamp) == os.path.getmtime(fname) finally: tenjin.Engine.timestamp_interval = interval _remove_files(filenames.values())
def test_cached_contents(self): data = EngineTest._testdata['test_cached_contents'] def _test(filename, cachename, cachemode, input, expected_script, expected_args): if input: write_file(filename, input) engine = tenjin.Engine(cache=cachemode) t = engine.get_template(filename) ok (t.args) == expected_args ok (t.script) == expected_script #import marshal #f = open(filename + '.cache', 'rb') #try: # dct = marshal.load(f) # ok (dct['args']) == expected_args # ok (dct['script']) == expected_script #finally: # f.close() ## try: ## args=[x,y,z], cache=1 filename = 'input.pyhtml' for f in glob(filename+'*'): os.path.exists(f) and os.remove(f) script = data['script1'] args = data['args1'] input = data['input1'] cachename = filename+'.cache' not_ok (cachename).exists() _test(filename, cachename, True, input, script, args) ok (cachename).exists() _test(filename, cachename, True, None, script, args) ## args=[], cache=1 cachename = filename+'.cache' input = data['input2'] # re.sub(r'<\?py #@ARGS.*?\?>\n', '<?py #@ARGS ?>\n', input) script = data['script2'] # re.sub(r'#@ARGS.*?\n', '#@ARGS \n', cache) args = data['args2'] # [] time.sleep(1) #ok (cachename).exists() _test(filename, cachename, True, input, script, args) #ok (cachename).exists() _test(filename, cachename, True, None, script, args) finally: _remove_files(['input.pyhtml'])
def test_cachefile_unset(self): try: input = "<?py x = 10 ?>" template_name = "cachefile_delete.pyhtml" f = open(template_name, 'w'); f.write(input); f.close() storage = tenjin.MarshalCacheStorage() engine = tenjin.Engine(cache=storage) engine.render(template_name) fullpath = os.path.abspath(template_name) cachepath = engine.cachename(fullpath) ok (storage.items).contains(cachepath) ok (template_name + '.cache').exists() storage.unset(cachepath) not_ok (storage.items).contains(cachepath) not_ok (template_name + '.cache').exists() def f(): storage.unset(fullpath) ok (f).not_raise() finally: _remove_files([template_name, template_name+'.cache'])
def func(): engine = tenjin.Engine() actual = engine.render(filename, context) ok(actual) == output not_ok(filename + '.cache').exists() if "rendered then converted script is stored into memcache": from google.appengine.api import memcache key = os.path.abspath(filename) + '.cache' obj = memcache.get(key, namespace='dev123.1') ok(obj).is_a(dict) keys = obj.keys() keys.sort() ok(keys) == ['args', 'script', 'timestamp'] ok(obj['script']) == script if "cached then version is used as namespace": ok(memcache.get(key)) == None ok(memcache.get(key, namespace='dev123.1')) != None if "cached once then it is possible to render even if file is removed": os.unlink(filename) not_ok(filename).exists() ok(engine.render(filename, context)) == output
def test__set_cache_storage(self): if "default then Engine.cache is TextCacheStorage instance": ok (tenjin.Engine.cache).is_a(tenjin.TextCacheStorage) if "cache=True specified then use default cache object": engine = tenjin.Engine(cache=True) ok ('cache' in engine.__dict__) == False ok (engine.cache).is_(tenjin.Engine.cache) ok (engine.cache).is_(tenjin.Engine(cache=True).cache) if "cache=True and default cache is not set then create MarshalCacheStorage object for each engine": bkup = tenjin.Engine.cache try: tenjin.Engine.cache = None engine = tenjin.Engine(cache=True) ok (engine.__dict__).contains('cache') ok (engine.cache).is_a(tenjin.MarshalCacheStorage) not_ok (engine.cache).is_(tenjin.Engine(cache=True).cache) finally: tenjin.Engine.cache = bkup #if "cache=None specified then set MemoryCacheObject instance as cache object": # engine = tenjin.Engine(cache=None) # ok ('cache' in engine.__dict__) == True # ok (engine.cache).is_a(tenjin.MemoryCacheStorage) if "cache=None then do nothing": engine = tenjin.Engine(cache=None) not_ok (engine.__dict__).contains('cache') if "cache=False specified then don't use cache object": engine = tenjin.Engine(cache=False) ok (engine.__dict__).contains('cache') ok (engine.cache) == None if "CacheStorage instance is specified then use it as cache object": cache_storage = tenjin.MarshalCacheStorage() engine = tenjin.Engine(cache=cache_storage) ok (engine.__dict__).contains('cache') ok (engine.cache).is_(cache_storage) if "invalid object is specified as cache object then raise ValueError": def f(): tenjin.Engine(cache=123) ok (f).raises(ValueError, '123: invalid cache object.')
def test_to_str_func_does_not_keep_escaped(self): from tenjin.escaped import EscapedStr, EscapedUnicode # to_str = tenjin.helpers.generate_tostrfunc(encode='utf-8') if "arg is str object then returns it as-is, keeping escaped.": ok (to_str('s')).is_a(str) not_ok (to_str('s')).is_a(EscapedStr) ok (to_str(EscapedStr('s'))).is_a(str) ok (to_str(EscapedStr('s'))).is_a(EscapedStr) if "arg is unicode object then encodes it into str, without keeping escaped.": ok (to_str(u's')).is_a(str) not_ok (to_str(u's')).is_a(EscapedStr) ok (to_str(EscapedUnicode(u's'))).is_a(str) not_ok (to_str(EscapedUnicode(u's'))).is_a(EscapedStr) # to_str = tenjin.helpers.generate_tostrfunc(decode='utf-8') if "arg is str object then decodes it into unicode, without keeping escaped.": ok (to_str('s')).is_a(unicode) not_ok (to_str('s')).is_a(EscapedUnicode) ok (to_str(EscapedStr('s'))).is_a(unicode) not_ok (to_str(EscapedStr('s'))).is_a(EscapedUnicode) if "arg is unicode object then returns it as-is, keeping escaped.": ok (to_str(u's')).is_a(unicode) not_ok (to_str(u's')).is_a(EscapedUnicode) ok (to_str(EscapedUnicode(u's'))).is_a(unicode) ok (to_str(EscapedUnicode(u's'))).is_a(EscapedUnicode)
def test_cachefile(self): data = EngineTest._testdata['test_cachefile'] filenames = { 'layout': 'layout.pyhtml', 'page': 'account_create.pyhtml', 'form': 'account_form.pyhtml', } expected = data['expected'] context = { 'params': { } } cache_filenames = ['account_create.pyhtml.cache', 'account_form.pyhtml.cache'] try: for key, filename in filenames.items(): write_file(filename, data[key]) props = { 'prefix':'account_', 'postfix':'.pyhtml', 'layout':'layout.pyhtml' } ## no caching props['cache'] = False engine = tenjin.Engine(**props) output = engine.render(':create', context) ok (output) == expected for fname in cache_filenames: not_ok (fname).exists() ## marshal caching if not JYTHON: props['cache'] = tenjin.MarshalCacheStorage() engine = tenjin.Engine(**props) output = engine.render(':create', context) ok (output) == expected if python2: nullbyte = '\0' elif python3: nullbyte = '\0'.encode('ascii') for fname in cache_filenames: ok (fname).exists() # file created? s = read_file(fname, 'rb') # read binary file ok (s.find(nullbyte)) >= 0 # binary file? f = open(fname, 'rb') fn = lambda: marshal.load(f) try: ok (fn).not_raise() # marshal? finally: f.close() engine = tenjin.Engine(**props) output = engine.render(':create', context) ok (output) == expected # reloadable? # for fname in glob('*.pyhtml.cache'): os.unlink(fname) for fname in cache_filenames: not_ok (fname).exists() ## pickle caching props['cache'] = tenjin.PickleCacheStorage() engine = tenjin.Engine(**props) output = engine.render(':create', context) ok (output) == expected if python2: nullbyte = '\0' elif python3: nullbyte = '\0'.encode('ascii') for fname in cache_filenames: ok (fname).exists() # file created? s = read_file(fname, 'rb') # read text file if python2: ok (s.find(nullbyte)) < 0 # text file? (pickle protocol ver 2) elif python3: ok (s.find(nullbyte)) >= 0 # binary file? (pickle protocol ver 3) f = open(fname, 'rb') fn = lambda: Pickle.load(f) try: ok (fn).not_raise(ValueError) finally: f.close() f = open(fname, 'rb') pickle.load(f) f.close() engine = tenjin.Engine(**props) output = engine.render(':create', context) ok (output) == expected # reloadable? # for fname in glob('*.cache'): os.unlink(fname) for fname in cache_filenames: not_ok (fname).exists() ## text caching props['cache'] = tenjin.TextCacheStorage() engine = tenjin.Engine(**props) output = engine.render(':create', context) ok (output) == expected if python2: nullchar = '\0' elif python3: nullchar = '\0' for fname in cache_filenames: ok (fname).exists() # file created? s = read_file(fname, 'r') # read text file ok (s.find(nullchar)) < 0 # text file? if JYTHON: continue #fn = lambda: marshal.loads(s) f = open(fname, 'rb') fn = lambda: marshal.load(f) try: if python3: ok (fn).raises(ValueError) # non-marshal? if sys.version_info[1] == 0: # python 3.0 ok (str(fn.exception)) == "bad marshal data" else: # python 3.1 or later ok (str(fn.exception)) == "bad marshal data (unknown type code)" elif python2 and sys.version_info[1] >= 5: ok (fn).raises(EOFError, "EOF read where object expected") # non-marshal? finally: f.close() engine = tenjin.Engine(**props) output = engine.render(':create', context) ok (output) == expected # reloadable? finally: _remove_files(filenames.values())