import os, sys
from StringIO import StringIO
from twisted.trial import unittest
from twisted.internet import threads # CLI tests use deferToThread
from twisted.internet.utils import getProcessOutputAndValue
from ..scripts import runner

class Basic(unittest.TestCase):
    def test_one(self):
        self.assert_(True, "yay!")

class BasedirMixin:
    def make_basedir(self):
        # TestCase.mktemp() creates _trial_temp/MODULE/CLASS/TEST/RANDOM and
        # returns join(that,"temp"). We just want the part that ends with
        # TEST. So we rmdir the RANDOM and return .../TEST
        basedir = self.mktemp()
        random = os.path.dirname(basedir)
        os.rmdir(random)
        test = os.path.dirname(random)
        return test

# most tests will just do Node.startService and invoke CLI commands by
# talking directly to the web handler: no network, no other processes.

# To cover the HTTP interface, we need a few tests which run the CLI command
# with deferToThread (to handle the time.sleep and blocking IO).

# And we need one or two tests that exercise the daemonization in 'petmail
# start', which requires a subprocess.

class CLIinThreadMixin:
    def cli(self, *args, **kwargs):
        stdout, stderr = StringIO(), StringIO()
        d = threads.deferToThread(runner.run, list(args), stdout, stderr)
        def _done(rc):
            return stdout.getvalue(), stderr.getvalue(), rc
        d.addCallback(_done)
        return d
    def mustSucceed(self, (out, err, rc)):
        if rc != 0:
            self.fail("rc=%s out='%s' err='%s'" % (rc, out, err))
        return out

    def cliMustSucceed(self, *args, **kwargs):
        d = self.cli(*args, **kwargs)
        d.addCallback(self.mustSucceed)
        return d

class CLIinProcessMixin(CLIinThreadMixin):
    def cli(self, *args, **kwargs):
        petmail = runner.petmail_executable[0]
        d = getProcessOutputAndValue(sys.executable, [petmail] + list(args),
                                     os.environ)
        return d

class CLI(CLIinProcessMixin, BasedirMixin, unittest.TestCase):

    def test_create(self):
        basedir = os.path.join(self.make_basedir(), "node1")
        d = self.cliMustSucceed("create-node", basedir)
        def _check(out):
            self.failUnlessEqual(out, "node created in %s\n" % basedir)
            self.failUnless(os.path.exists(os.path.join(basedir, "petmail.db")))
        d.addCallback(_check)
        return d

    def test_run(self):
        basedir = os.path.join(self.make_basedir(), "node1")
        d = self.cliMustSucceed("create-node", basedir)
        d.addCallback(lambda _: self.cliMustSucceed("start", basedir))
        d.addCallback(lambda _: self.cliMustSucceed("open", "-n", "-d",basedir))
        d.addCallback(lambda _: self.cliMustSucceed("stop", basedir))
        return d


@@ -140,16 +140,51 @@
 oThread%0A
+from twisted.internet import defer%0A
 from twi
@@ -2048,25 +2048,367 @@
 turn d%0A%0A
-class CLI
+    def anyways(self, res, cb, *args, **kwargs):%0A        # always run the cleanup callback%0A        d = defer.maybeDeferred(cb, *args, **kwargs)%0A        # if it succeeds, return the original result (which might be a%0A        # Failure). Otherwise return the cleanup failure.%0A        d.addCallbacks(lambda _: res, lambda f: f)%0A        return d%0A%0Aclass Run
 (CLIinPr
@@ -2467,22 +2467,19 @@
 ef test_
-create
+run
 (self):%0A
@@ -2587,32 +2587,184 @@
 node%22, basedir)%0A
+        d.addCallback(lambda _: self.cliMustSucceed(%22start%22, basedir))%0A        d.addCallback(lambda _: self.cliMustSucceed(%22open%22, %22-n%22, %22-d%22,basedir))%0A
         def _che
@@ -2765,16 +2765,20 @@
 f _check
+_url
 (out):%0A 
@@ -2807,181 +2807,402 @@
 less
-Equal(out, %22node created in %25s%5Cn%22 %25 basedir)%0A            self.failUnless(os.path.exists(os.path.join(basedir, %22petmail.db%22)))%0A        d.addCallback(_check)%0A        return d%0A
+Substring(%22Node appears to be running, opening browser%22, out)%0A            self.failUnlessSubstring(%22Please open: http://localhost:%22, out)%0A            self.failUnlessSubstring(%22/open-control?opener-token=%22, out)%0A        d.addCallback(_check_url)%0A        d.addBoth(self.anyways, self.cliMustSucceed, %22stop%22, basedir)%0A        return d%0A%0Aclass CLI(CLIinThreadMixin, BasedirMixin, unittest.TestCase):
 %0A   
@@ -3203,35 +3203,38 @@
 ):%0A    def test_
-run
+create
 (self):%0A        
@@ -3355,59 +3355,86 @@
    d
-.addCallback(lambda _: self.cliMustSucceed(%22start%22,
+ef _check(out):%0A            self.failUnlessEqual(out, %22node created in %25s%5Cn%22 %25
  bas
@@ -3430,33 +3430,32 @@
 %25s%5Cn%22 %25 basedir)
-)
 %0A        d.addCa
@@ -3451,149 +3451,109 @@
     
-d.addCallback(lambda _: self.cliMustSucceed(%22open%22, %22-n%22, %22-d%22,basedir))%0A        d.addCallback(lambda _: self.cliMustSucceed(%22stop%22, basedir)
+    self.failUnless(os.path.exists(os.path.join(basedir, %22petmail.db%22)))%0A        d.addCallback(_check
 )%0A  
@@ -3551,25 +3551,24 @@
 check)%0A        return d%0A
-%0A

clean up after failed 'tahoe start' test, split out thread-based CLI tests