# Copyright 2012 Rackspace Hosting, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import subprocess
import signal
import time
import socket
import errno
import atexit
from os.path import join as pjoin


# From https://github.com/Kami/python-yubico-client/blob/master/tests/utils.py

def waitForStartUp(process, pid, address, timeout=10):
    # connect to it, with a timeout in case something went wrong
    start = time.time()
    while time.time() < start + timeout:
        try:
            s = socket.create_connection(address)
            s.close()
            break
        except:
            time.sleep(0.1)
    else:
        # see if process is still alive
        process.poll()

        if pid and process.returncode is None:
            os.kill(pid, signal.SIGKILL)
        raise RuntimeError("Couldn't connect to server; aborting test")


class ProcessRunner(object):
    def setUp(self, *args, **kwargs):
        # clean up old.
        p = self.getPid()
        if p is not None:
            try:
                # remember, process may already be dead.
                os.kill(p, 9)
                time.sleep(0.01)
            except:
                pass

    def tearDown(self, *args, **kwargs):
        spid = self.getPid()
        if spid:
            max_wait = 1
            os.kill(spid, signal.SIGTERM)
            slept = 0
            while (slept < max_wait):
                time.sleep(0.5)
                if not self.isAlive(spid):
                    if os.path.exists(self.pid_fname):
                        os.unlink(self.pid_fname)
                    break
                slept += 0.5
            if (slept > max_wait and self.isAlive(spid)):
                os.kill(spid, signal.SIGKILL)
                if os.path.exists(self.pid_fname):
                    os.unlink(self.pid_fname)
                raise Exception('Server did not shut down correctly')
        else:
            print 'Unable to locate pid file (%s)!' % self.pid_fname

    def isAlive(self, pid):
        try:
            os.kill(pid, 0)
            return 1
        except OSError, err:
            return err.errno == errno.EPERM

    def getPid(self):
        if self.process:
            return self.process.pid
        elif os.path.exists(self.pid_fname):
            return int(open(self.pid_fname, 'r').read())
        return None


class MockAPIServerRunner(ProcessRunner):
    def __init__(self, port=8881):
        self.port = port

    def setUp(self, *args, **kwargs):
        self.cwd = os.getcwd()
        self.process = None
        self.base_dir = pjoin(self.cwd)
        self.pid_fname = pjoin(self.cwd, 'mock_api_server.pid')
        self.log_path = pjoin(self.cwd, 'mock_api_server.log')

        super(MockAPIServerRunner, self).setUp(*args, **kwargs)
        script = pjoin(os.path.dirname(__file__), 'mock_http_server.py')

        with open(self.log_path, 'a+') as log_fp:
            port_arg = '%s --port=%s' % (script, self.port)
            fixtures_dir_arg = \
                '--fixtures-dir=txServiceRegistry/test/fixtures/response'
            args = '%s %s' % (port_arg, fixtures_dir_arg)
            self.process = subprocess.Popen(args,
                                            shell=True,
                                            cwd=self.base_dir,
                                            stdout=log_fp,
                                            stderr=log_fp)
            waitForStartUp(self.process,
                           self.getPid(),
                           ('127.0.0.1', self.port), 10)
        atexit.register(self.tearDown)

@@ -585,16 +585,66 @@
 e.%0A%0A
-import o
+from __future__ import with_statement%0A%0Aimport os%0Aimport sy
 s%0Aim
@@ -726,16 +726,17 @@
  atexit%0A
+%0A
 from os.
@@ -766,12 +766,17 @@
 in%0A%0A
-%0A
 # 
-F
+Taken f
 rom 
@@ -847,17 +847,16 @@
 tils.py%0A
-%0A
 def wait
@@ -878,13 +878,8 @@
 ess,
- pid,
  add
@@ -1260,18 +1260,22 @@
     if p
-id
+rocess
  and pro
@@ -1315,35 +1315,26 @@
     
-os.kill(pid, signal.SIGKILL
+process.terminate(
 )%0A  
@@ -1484,1427 +1484,116 @@
     
-# clean up old.%0A        p = self.getPid()%0A        if p is not None:%0A            try:%0A                # remember, process may already be dead.%0A                os.kill(p, 9)%0A                time.sleep(0.01)%0A            except:%0A                pass%0A%0A    def tearDown(self, *args, **kwargs):%0A        spid = self.getPid()%0A        if spid:%0A            max_wait = 1%0A            os.kill(spid, signal.SIGTERM)%0A            slept = 0%0A            while (slept %3C max_wait):%0A                time.sleep(0.5)%0A                if not self.isAlive(spid):%0A                    if os.path.exists(self.pid_fname):%0A                        os.unlink(self.pid_fname)%0A                    break%0A                slept += 0.5%0A            if (slept %3E max_wait and self.isAlive(spid)):%0A                os.kill(spid, signal.SIGKILL)%0A                if os.path.exists(self.pid_fname):%0A                    os.unlink(self.pid_fname)%0A                raise Exception('Server did not shut down correctly')%0A        else:%0A            print 'Unable to locate pid file (%25s)!' %25 self.pid_fname%0A%0A    def isAlive(self, pid):%0A        try:%0A            os.kill(pid, 0)%0A            return 1%0A        except OSError, err:%0A            return err.errno == errno.EPERM%0A%0A    def getPid(self):%0A        if self.process:%0A            return self.process.pid%0A        elif os.path.exists(self.pid_fname):%0A            return int(open(self.pid_fname, 'r').read())%0A        return None
+pass%0A%0A    def tearDown(self, *args, **kwargs):%0A        if self.process:%0A            self.process.terminate()
 %0A%0A%0Ac
@@ -1835,72 +1835,8 @@
 wd)%0A
-        self.pid_fname = pjoin(self.cwd, 'mock_api_server.pid')%0A
     
@@ -2095,24 +2095,20 @@
         
-port_
 arg
+s
  = '%25s -
@@ -2128,16 +2128,20 @@
 script, 
+str(
 self.por
@@ -2142,16 +2142,17 @@
 lf.port)
+)
 %0A       
@@ -2274,27 +2274,42 @@
 s = 
-'%25s %25s' %25 (port_arg
+%5Bscript, '--port=%25s' %25 (self.port)
 , fi
@@ -2322,17 +2322,18 @@
 _dir_arg
-)
+%5D%0A
 %0A       
@@ -2378,62 +2378,19 @@
 rgs,
-%0A                                           
  shell=
-Tru
+Fals
 e,%0A 
@@ -2454,52 +2454,8 @@
 dir,
-%0A                                           
  std
@@ -2569,77 +2569,8 @@
 ess,
-%0A                           self.getPid(),%0A                          
  ('1

Update test utils.