#!/usr/bin/env python

import sys, os
sys.path = ([os.path.dirname(os.path.dirname(os.path.realpath(__file__)))]
            + sys.path)
    
__requires__='Bazki'
import pkg_resources
pkg_resources.require('Bazki')

import unittest
import shutil, subprocess
import tempfile
from cStringIO import StringIO
import urllib2

from paste.script import command

from bazbase import testing, custom

verbose = '-v' in sys.argv

class EndToEnd(unittest.TestCase):
    paster_command = 'bazstart'
    
    def setUp(self):
        # Sitedir hack
        import __main__
        __main__.__paster_sitedir__ = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

        self.dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
        self.cwd = os.getcwd()
        self.directory = tempfile.mkdtemp(suffix='.%s.test'
                                          % self.paster_command)
        testing.set_up_for_tests()
        self.database = custom.get_sqlalchemy_args()['url']
        os.chdir(self.directory)

    def tearDown(self):
        if hasattr(self, 'child'):
            self.child.terminate()
        os.chdir(self.cwd)
        shutil.rmtree(self.directory)

    def run_bazstart(self, custom_db=None, remove_db=None,
                     no_auxiliaries=False,
                     failure_message=None):
        args = [self.paster_command,
                '%sUnitTest' % self.paster_command.capitalize(),
                '-d', self.database,
                '--package', '%sunittest' % self.paster_command,
                '--password', 'fish',
                '--noinput']
        if not verbose:
            args.append('-q')
        if custom_db is not None:
            args.append('--custom-db')
            args.append(os.path.join(self.dir, 'test_db', custom_db))
        if remove_db is not None:
            args.append('--remove-db')
            args.append(remove_db)
        if no_auxiliaries:
            args.append('--urlprefix')
            args.append("")
        try:
            stderr = sys.stderr
            errio = StringIO()
            sys.stderr = errio
            if not verbose:
                stdout = sys.stdout
                sys.stdout = open('/dev/null', 'w')
            try:
                command.run(args)
            finally:
                sys.stderr = stderr
                if verbose:
                    print >>sys.stderr, errio.getvalue()
                else:
                    sys.stdout.close()
                    sys.stdout = stdout
        except SystemExit,e:
            if failure_message is None:
                self.assertEquals(0, e.code)
            else:
                self.assertNotEqual(0, e.code)
                self.assertTrue(failure_message in errio.getvalue(),
                                errio.getvalue())
        else:
            if failure_message is not None:
                self.fail("bazstart succeeded")
        finally:
            errio.close()

    def serve(self):
        env = dict(os.environ)
        env['PYTHONUNBUFFERED'] = '1'
        kw = {}
        if not verbose:
            kw['stderr'] = open('/dev/null', 'w')
        self.child = subprocess.Popen(['paster', 'serve', 'development.ini',
                                       #'test_identity=Admin'
                                       ],
                                      stdout=subprocess.PIPE,
                                      env=env,
                                      **kw)
        tag = 'serving on'
        while True:
            lin = self.child.stdout.readline()
            if not lin:
                self.fail("never started serving")
            if lin.startswith(tag):
                self.host = lin[len(tag):].strip()
                if verbose:
                    print >>sys.stderr, lin
                break

    def fetch(self, path):
        url = self.host + path
        try:
            return urllib2.urlopen(url).read()
        except urllib2.HTTPError, e:
            if verbose:
                print >>sys.stderr, "X!!", e.read()
                #print >>sys.stderr, "O!!", self.child.stdout.read()
            raise

class BazstartEndToEnd(EndToEnd):
    def test_default(self):
        self.run_bazstart()
        self.serve()
        # Make sure this doesn't fail.
        self.fetch('/')
        # TODO(xavid): This blows up for dumb reasons.
        #print >>sys.stderr, self.fetch('/edit/DocumentationHome')
        self.assertEqual("Index",
                         self.fetch('/Index/name.txt'))

    def test_empty(self):
        self.run_bazstart(remove_db='Object',
                          failure_message="No root element Object!",
                          no_auxiliaries=True)
        
    def test_lonely_leaf(self):
        self.run_bazstart(custom_db='invalid/lonely_leaf',
                          failure_message="If Thing has no kids, it needs to "
                          "be in the form Thing.yaml, not Thing/Thing.yaml")

if __name__ == "__main__":
    unittest.main()
