import unittest
import web
import tempfile
from time import sleep
from os.path import join
from shutil import rmtree
import db
import sys
sys.path += ['../job_executer']

from job_executer import MAX_INTERVAL_TIMEOUT
from clientjob.model import Job, JOB_TIMEOUT
from utils import adquire_thread_orm
from main.model import Computer
from config_client1 import client_daemon_port as c1_port
from config_client2 import client_daemon_port as c2_port
from config_client3 import client_daemon_port as c3_port

class TestJob(unittest.TestCase):
    def setUp(self):
        self.orm = adquire_thread_orm()
        self.tmp_dir = tempfile.mkdtemp()
        self.computer1 = self.orm.query(Computer).filter(
            Computer.port == c1_port).one()
        self.computer2 = self.orm.query(Computer).filter(
            Computer.port == c2_port).one()
        self.computer3 = self.orm.query(Computer).filter(
            Computer.port == c3_port).one()
    
    def tearDown(self):
        pass

    def test_SimpleJob(self):
        '''
        Launches a simple job in a client and tests the result.
        '''
        for i in xrange(10):
            open(join(self.tmp_dir, str(i)), "w").close()

        job = Job("ls", [self.tmp_dir + "/0"])
        self.orm.add(job)
        self.orm.commit()
        job.send(self.computer1)
        sleep(3)
        job2 = db.connect().query(Job).get(job.id)
        self.assertEqual(job2.status, 'FINISHED')

        rmtree(self.tmp_dir)

    def test_CommandNotFoundJob(self):
        '''
        Launches a simple job in a client executing a unexistant command and
        tests the result.
        '''
        import json
        job = Job("washinakiwohoo")
        self.orm.add(job)
        self.orm.commit()
        job.send(self.computer1)
        sleep(3)
        job2 = db.connect().query(Job).get(job.id)
        self.assertEqual(job2.status, 'ERROR')
        msg = json.loads(job2.client_message)
        self.assertEqual(msg['type'], "ClientSideError")
        self.assertEqual(msg['response'], "[Errno 2] No such file or directory")

    def test_SlowJob(self):
        '''
        Launches an slow job in a client, testing that automatic updates are
        received.
        '''
        job = Job("sleep", [str(MAX_INTERVAL_TIMEOUT*2)])
        self.orm.add(job)
        self.orm.commit()
        job.send(self.computer1)
        sleep(MAX_INTERVAL_TIMEOUT+1)
        job2 = db.connect().query(Job).get(job.id)
        self.assertEqual(job2.status, 'INPROGRESS')
        sleep(MAX_INTERVAL_TIMEOUT)
        job2 = db.connect().query(Job).get(job.id)
        self.assertEqual(job2.status, 'FINISHED')

    def test_WaitingJob(self):
        '''
        Launches a job in an offline client, tests that that job is effectively
        not launched until after a timeout the job receiver notices that the
        computer is online, and then checks that the job is finished correctly.
        '''
        self.computer1.online = False
        self.orm.add(self.computer1)
        self.orm.commit()

        job = Job("sleep", ["1"])
        self.orm.add(job)
        self.orm.commit()
        job.send(self.computer1)
        sleep(3)
        job2 = db.connect().query(Job).get(job.id)
        self.assertEqual(job2.status, 'WAITING')

        # wait for update waiting jobs to notice that computer1 is online
        sleep(JOB_TIMEOUT/5 - 2)
        job2 = db.connect().query(Job).get(job.id)
        self.assertEqual(job2.status, 'FINISHED')

    def test_SimpleOgrJob(self):
        '''
        Launches a simple OGR job.
        '''
        self.computer1.online = False
        self.orm.add(self.computer1)
        self.orm.commit()

        job = Job("ogr", ["simple.sh"])
        self.orm.add(job)
        self.orm.commit()
        sleep(3)
        job2 = db.connect().query(Job).get(job.id)
        self.assertEqual(job2.status, 'FINISHED')

    def test_ProgressOgrJob(self):
        '''
        Launches a simple OGR job.
        '''
        self.computer1.online = False
        self.orm.add(self.computer1)
        self.orm.commit()

        job = Job("ogr", ["simple.sh"])
        self.orm.add(job)
        self.orm.commit()
        sleep(3)
        job2 = db.connect().query(Job).get(job.id)
        self.assertEqual(job2.status, 'FINISHED')

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