import copy
import os
import sets
import sys
import time
import traceback
import unittest

if __name__ == '__main__':
    execfile(os.path.join(sys.path[0], 'framework.py'))

from Testing                 import ZopeTestCase
from Products.PloneTestCase import PloneTestCase

ZopeTestCase.installProduct('PythonScripts')
ZopeTestCase.installProduct('PageCacheManager')
ZopeTestCase.installProduct('CMFSquidTool')
ZopeTestCase.installProduct('CacheSetup')

PloneTestCase.setupPloneSite()

from DateTime import DateTime
from Products.CMFCore.utils  import getToolByName
from Products.CacheSetup.Extensions.Install import install as installCacheSetup
import Products.CacheSetup.config as config

# util for making content in a container
def makeContent(container, id, portal_type, title=None):
    container.invokeFactory(id=id, type_name=portal_type)
    o = getattr(container, id)
    if title is not None:
        o.setTitle(title)
    return o

# This is the test case. You will have to add test_<methods> to your
# class inorder to assert things about your Product.
class TestBaseRule(PloneTestCase.PloneTestCase):
    USER1 = 'user1'
    
    def afterSetUp(self):
        PloneTestCase.PloneTestCase.afterSetUp(self)
        
        # Add a couple of users
        self.portal.acl_users._doAddUser('manager', 'secret', ['Manager'], [])
        self.portal.acl_users._doAddUser(self.USER1, 'secret', ['Member'], [])
        self.login('manager')

        installCacheSetup(self.portal)

        # We have added a skin so we need to rebuild the skin object
        # (since the object is cached in the current request)
        self._refreshSkinData()

        self.folder.invokeFactory(id='doc', type_name='Document')
        pcs = self.portal.portal_cache_settings
        headers = pcs.getHeaderSets()
        headers.invokeFactory(id='my_hs', type_name='HeaderSet')
        rules = pcs.getRules()
        rules.invokeFactory(id='my_rule', type_name='ContentCacheRule')
        rules.moveObjectsToTop(['my_rule'])

    def test_last_modified(self):
        pcs = self.portal.portal_cache_settings
        rule = getattr(pcs.getRules(), 'my_rule')

        # test default value
        expr = rule.getLastModifiedExpression()
        self.assertEqual(expr, 'python:object.modified()')

        # make sure getting and setting work
        rule.setLastModifiedExpression('python:3')
        self.assertEqual(rule.getLastModifiedExpression(), 'python:3')

        # test validation
        self.assertEqual(rule.validate_lastModifiedExpression(''), None)
        self.assertEqual(rule.validate_lastModifiedExpression('python:3'), None)
        self.assertNotEqual(rule.validate_lastModifiedExpression('python:foo bar'), None)
        
        doc = self.folder.doc
        expr_context = rule._getExpressionContext(doc.REQUEST, doc, 'document_view', None)
        self.assertEqual(rule.getLastModified(expr_context), 3)


    def test_etag_expression(self):
        pcs = self.portal.portal_cache_settings
        rule = getattr(pcs.getRules(), 'my_rule')

        # test default value
        expr = rule.getEtagExpression()
        self.assertEqual(expr, '')

        # make sure getting and setting work
        rule.setEtagExpression('python:2')
        self.assertEqual(rule.getEtagExpression(), 'python:2')

        # test validation
        self.assertEqual(rule.validate_etagExpression('python:2'), None)
        self.assertNotEqual(rule.validate_etagExpression('python: foo bar'), None)

        doc = self.folder.doc
        expr_context = rule._getExpressionContext(doc.REQUEST, doc, 'document_view', None)
        self.assertEqual(rule.getEtagExpressionValue(expr_context), 2)

    def test_headersetid_expression(self):
        pcs = self.portal.portal_cache_settings
        rule = getattr(pcs.getRules(), 'my_rule')

        # test default value
        expr = rule.getHeaderSetIdExpression()
        self.assertEqual(expr, '')

        # make sure getting and setting work
        rule.setHeaderSetIdExpression('python:2')
        self.assertEqual(rule.getHeaderSetIdExpression(), 'python:2')

        # test validation
        self.assertEqual(rule.validate_etagExpression('python:2'), None)
        self.assertNotEqual(rule.validate_etagExpression('python: foo bar'), None)

        doc = self.folder.doc
        expr_context = rule._getExpressionContext(doc.REQUEST, doc, 'document_view', None)
        self.assertEqual(rule.getHeaderSetIdExpressionValue(expr_context), 2)

    def test_get_default_view(self):
        pcs = self.portal.portal_cache_settings
        rule = getattr(pcs.getRules(), 'my_rule')
        doc = self.folder.doc
        self.assertEqual(rule.getObjectDefaultView(doc), 'document_view')

    def test_get_etag(self):
        pcs = self.portal.portal_cache_settings
        rule = getattr(pcs.getRules(), 'my_rule')
        hs = getattr(pcs.getHeaderSets(), 'my_hs')
        doc = self.folder.doc
        request = doc.REQUEST
        pcs.setGzip('accept-encoding')

        rule.setEtagComponents([])
        rule.setEtagTimeout(None)
        rule.setEtagRequestValues([])
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '')

        rule.setEtagComponents(['member'])
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|')
        member = self.portal.portal_membership.getMemberById(self.USER1)
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, '|'+self.USER1)

        rule.setEtagComponents(['member','roles'])
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '||Anonymous')
        member = self.portal.portal_membership.getMemberById(self.USER1)
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, '|%s|%s' % (self.USER1, ';'.join(['Authenticated','Member'])))

        rule.setEtagComponents(['member','permissions'])
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '||%s|%s' % ('Anonymous', str(pcs.getPermissionCount())))
        member = self.portal.portal_membership.getMemberById(self.USER1)
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, '|%s|%s|%s' % (self.USER1, ';'.join(['Authenticated','Member']), str(pcs.getPermissionCount())))

        rule.setEtagComponents(['member','role', 'permissions'])
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '||%s|%s' % ('Anonymous', str(pcs.getPermissionCount())))
        member = self.portal.portal_membership.getMemberById(self.USER1)
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, '|%s|%s|%s' % (self.USER1, ';'.join(['Authenticated','Member']), str(pcs.getPermissionCount())))
        cumulative_etag = etag
        
        rule.setEtagComponents(['skin'])
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|'+self.portal.getCurrentSkinName())
        rule.setEtagComponents(['member','role','permissions','skin'])
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, cumulative_etag + '|' + self.portal.getCurrentSkinName())
        cumulative_etag = etag
        
        rule.setEtagComponents(['language'])
        request.set('HTTP_ACCEPT_LANGUAGE', 'en-us, en-uk')
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|en-us; en-uk')
        rule.setEtagComponents(['member','role','permissions','skin','language'])
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, cumulative_etag + '|en-us; en-uk')
        cumulative_etag = etag

        rule.setEtagComponents(['gzip'])
        request.set('HTTP_ACCEPT_ENCODING', '')
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|0')
        request.set('HTTP_ACCEPT_ENCODING', 'gzip')
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|1')
        rule.setEtagComponents(['member','role','permissions','skin','language','gzip'])
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, cumulative_etag + '|1')
        cumulative_etag = etag
        
        rule.setEtagComponents(['last_modified'])
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|'+str(doc.modified().timeTime()))
        rule.setEtagComponents(['member','role','permissions','skin','language','gzip','last_modified'])
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, cumulative_etag + '|' + str(doc.modified().timeTime()))
        cumulative_etag = etag
        
        rule.setEtagComponents(['catalog_modified'])
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|'+str(pcs.getCatalogCount()))
        rule.setEtagComponents(['member','role','permissions','skin','language','gzip','last_modified','catalog_modified'])
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, cumulative_etag + '|' + str(pcs.getCatalogCount()))
        cumulative_etag = etag

        rule.setEtagComponents([])
        rule.setEtagExpression('string:my, value')
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|my; value')
        rule.setEtagComponents(['member','role','permissions','skin','language','gzip','last_modified','catalog_modified'])
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, cumulative_etag + '|my; value')
        cumulative_etag = etag

        rule.setEtagRequestValues([])
        rule.setEtagRequestValues(['foo','bar','foobar'])
        request.set('foo', 'FOO')
        request.set('bar', 'BAR')
        rule.setEtagComponents([])
        rule.setEtagExpression('')
        etag = rule.getEtag(request, doc, 'document_view', None)
        self.assertEqual(etag, '|FOO|BAR|')
        rule.setEtagComponents(['member','role','permissions','skin','language','gzip','last_modified','catalog_modified'])
        rule.setEtagExpression('string:my, value')
        etag = rule.getEtag(request, doc, 'document_view', member)
        self.assertEqual(etag, cumulative_etag + '|FOO|BAR|')
        cumulative_etag = etag

        now = DateTime()
        rule.setEtagComponents([])
        rule.setEtagExpression('')
        rule.setEtagRequestValues([])
        rule.setEtagTimeout(3600)
        etag = rule.getEtag(request, doc, 'document_view', None, time=now)
        timeout = str(int(now.timeTime()/3600))
        self.assertEqual(etag, '|'+timeout)
        rule.setEtagComponents(['member','role','permissions','skin','language','gzip','last_modified','catalog_modified'])
        rule.setEtagExpression('string:my, value')
        rule.setEtagRequestValues(['foo','bar','foobar'])
        etag = rule.getEtag(request, doc, 'document_view', member, time=now)
        self.assertEqual(etag, cumulative_etag + '|' + timeout)
        cumulative_etag = etag
        

def test_suite():
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestBaseRule))
    return suite

if __name__ == '__main__':
    framework()
