def testStore(self): project = launcher.Project('/tmp/hoover', 8000) flagsproj = launcher.Project('/tmp/markd-attack', 8001, 'run-for-your-life', flags=['--vehicular-assault']) # make some stuff, write it out, and re-load it parser = ConfigParser.ConfigParser() parser.add_section('greeble') parser.add_section('grooble') project.SaveToConfigParser(parser, 'greeble') flagsproj.SaveToConfigParser(parser, 'grooble') self.checkProject( launcher.Project.ProjectWithConfigParser(parser, 'greeble'), project.path, project.name, project.port) self.checkProject(launcher.Project.ProjectWithConfigParser( parser, 'grooble'), flagsproj.path, flagsproj.name, flagsproj.port, flags=flagsproj.flags)
def testName(self): p = launcher.Project('/tmp/foo', 8000, 'my_name') self.assertEqual('my_name', p.name) # make sure we cannot set the name (hidden with @property) def setName(): p.name = 'doh' self.assertRaises(AttributeError, setName) self.assertEqual('my_name', p.name) p = launcher.Project('/tmp/foo', 8000, name='bozo') self.assertEqual('bozo', p.name)
def testVerifyAndValid(self): p = launcher.Project('/tmp/foo/smin/du7737g', 8000, 'name') self.assertFalse(p.valid) p.Verify() self.assertFalse(p.valid) self.createTempProject('turbo-monkey') p = launcher.Project(self._temp_project, 8000) self.assertTrue(p.valid) p.Verify() self.assertTrue(p.valid) self.deleteTempProject() p.Verify() self.assertFalse(p.valid)
def testDeployServer(self): class MockPref(object): def __init__(self, pref=None): self.pref = pref def Get(self, name): if name == launcher.Preferences.PREF_DEPLOY_SERVER: return self.pref return None class MockText(object): def __init__(self): self.text = None def SetLabel(self, text): self.text = text project = launcher.Project('path', 8000, 'project_name') mockpref = MockPref() mocktext = MockText() d = launcher.DeployController(None, mockpref, [project]) d._AddDeployServerToTextField(mocktext) self.assertFalse(mocktext.text) mockpref = MockPref('hi dave') d = launcher.DeployController(None, mockpref, [project]) d._AddDeployServerToTextField(mocktext) self.assertTrue('dave' in mocktext.text)
def doTestThreadRun(self, killit=False): """Run a command, watch for state change. Optionally kill it to speed up death. """ controller = launcher.TaskController(FakeAppController()) project = launcher.Project('himom', 8000) secs = 3 if killit: # If in killit mode, make sure it'll last longer than us so we # don't confuse kill with runout secs = 20 # Start a task ripe for the killing. command = [sys.executable, '-c', 'import time; time.sleep(%d)' % secs] tt = launcher.TaskThread(controller, project, command) tt.start() # TODO(jrg): is this a reasonable chance? for i in range(20): time.sleep(0.25) if tt.isAlive(): break self.assertTrue(tt.isAlive()) if killit: tt.stop() for i in range(20): time.sleep(0.25) if not tt.isAlive(): break self.assertFalse(tt.isAlive()) pass
def testProperties(self): for plist in (('foo', '/tmp/foo', 8000), ('zzz', '/yo/momma/zzz', 9000)): p = launcher.Project(plist[1], plist[2]) self.assertEqual(p.name, plist[0]) self.assertEqual(p.path, plist[1]) self.assertEqual(p.port, plist[2])
def testShowModal(self): project = launcher.Project('path', 9000) for (wx_rtn, updated_calls) in ((wx.ID_OK, 1), (wx.ID_CANCEL, 0)): sc = launcher.SettingsController(project) settings_dialog = project_dialogs.ProjectSettingsDialog dialog_mock = mox.MockObject(settings_dialog) dialog_mock.ShowModal().AndReturn(wx_rtn) mox.Replay(dialog_mock) sc.dialog = dialog_mock actual_updated = [0] def plusone(): """Must use mutable to modify var in enclosing scope.""" actual_updated[0] += 1 sc._UpdateProject = plusone rtn = sc.ShowModal() self.assertEqual(wx_rtn, rtn) mox.Verify(dialog_mock) self.assertEqual(updated_calls, actual_updated[0]) # SettingsController needs to Destroy() its dialog. # That is done in SettingsController's __del__. # But that's past the mox.Verify(), so we can't expect it. # We can, however, make sure it doesn't cause mox # to yell. sc.dialog = None
def testUpdateProject(self): project = launcher.Project('path', 9001) sc = launcher.SettingsController(project) # Basic change: # First a port... sc.dialog.app_port_text_ctrl.SetValue(str(1008)) sc._UpdateProject() self.assertEqual(1008, project.port) # Then a flag. sc.dialog.full_flag_list_text_ctrl.SetValue('--bozo-assault') sc._UpdateProject() self.assertTrue('--bozo-assault' in project.flags) # Deny a change if it's running failures = [0] def plusone(arg1, arg2): """Must use mutable to modify var in enclosing scope.""" failures[0] += 1 sc.FailureMessage = plusone # First change the port... oldport = project.port sc.dialog.app_port_text_ctrl.SetValue(str(5555)) project.runstate = launcher.Project.STATE_RUN sc._UpdateProject() self.assertEqual(1, failures[0]) failures[0] = 0 # Restore, then change the flags sc.dialog.app_port_text_ctrl.SetValue(str(oldport)) sc.dialog.full_flag_list_text_ctrl.SetValue('--anti-clown-spray') sc._UpdateProject() self.assertEqual(1, failures[0])
def testInstallDemoByName(self): # Create a demo source sourcedir = tempfile.mkdtemp() demo = os.path.join(sourcedir, 'sooper-dooper-demo') os.mkdir(demo) yaml = os.path.join(demo, 'app.yaml') f = open(yaml, 'w') f.write('hi mom\n') f.close() # Create a demo dest dir destdir = tempfile.mkdtemp() # Now copy a demo. ac = NoAskController(self.app, launcher.Project('hi', 8000)) ac.InstallDemoByName(demo, destdir, False) self.assertTrue(os.path.basename(demo) in os.listdir(destdir)) for copied_demo in os.listdir(destdir): self.assertTrue( os.path.exists(os.path.join(destdir, copied_demo, 'app.yaml'))) # Now copy another, trying to conflict. ac.InstallDemoByName(demo, destdir, False) self.assertEqual(2, len(os.listdir(destdir))) for copied_demo in os.listdir(destdir): self.assertTrue( os.path.exists(os.path.join(destdir, copied_demo, 'app.yaml'))) # Now for a 3rd to test out counter. ac.InstallDemoByName(demo, destdir, False) self.assertEqual(3, len(os.listdir(destdir))) # Finally, clean up. shutil.rmtree(sourcedir) shutil.rmtree(destdir)
def testUpdateNameOnVerify(self): name = 'starting_name' self.createTempProject(name) p = launcher.Project(self._temp_project, 9000) self.assertEqual(name, p.name) name = 'ending_name' self.createYaml(name, self._temp_project) p.Verify() self.assertEqual(name, p.name) # the new name
def testUniquePort(self): table = launcher.MainTable(self._temp_filename) self.assertTrue(table.UniquePort() > 1024) ports = range(8000, 8020) + range(8021, 8200, 17) for i in range(len(ports)): table.AddProject(launcher.Project('/tmp/himom' + str(i), ports[i])) unused = table.UniquePort() self.assertTrue(unused not in ports[:i + 1]) self.assertTrue(unused > 1024)
def testInvalidProject(self): projects = [] for valid in (False, True, False): p = launcher.Project('/tmp/foo', 8000) p._valid = valid projects.append(p) self.frame._MarkRowValidity = self.frame._listctrl._MarkRowValidity self.frame.RefreshView(projects) self.assertEqual(1, self.frame._listctrl.valid) self.assertEqual(2, self.frame._listctrl.invalid)
def testEndModalClosure(self): project = launcher.Project('path', 9000) sc = launcher.SettingsController(project) for code in (wx.ID_OK, wx.ID_CANCEL): dialog_mock = mox.MockObject(wx.Dialog) dialog_mock.EndModal(code) mox.Replay(dialog_mock) closure = sc.EndModalClosure(dialog_mock, code) closure(None) mox.Verify(dialog_mock)
def testRunState(self): p1 = launcher.Project('/tmp/foo', 8000) for state in launcher.Project.ALL_STATES: p1.runstate = state self.assertEqual(state, p1.runstate) for state in ('hi mom', 1029333, None): def setRunState(): p1.runstate = state self.assertRaises(launcher.ProjectException, setRunState)
def Project(self): """Return a project created from interaction with this dialog. Returns: A launcher.Project, or None. """ if self._dialog_return_value != wx.ID_OK: return None path = self.GetPath() port = self.GetPort() if not (self._SanityCheckPath(path) and self._SanityCheckPort(port)): return None return launcher.Project(path, port)
def Projects(self, n): """Return a list of N unique Projects. Args: n: the number of unique Projects we will generate Returns: A list of unique Projects """ projects = [] for i in range(n): name = '/tmp/himom-%d' % i projects.append(launcher.Project(name, i + 8000)) return projects
def Projects(self, n): """Convenience routine for creating unique projects. Args: n: number of unique projects Returns: A list of N unique projects. """ projects = [] for i in range(n): name = '/tmp/himom-%d' % i projects.append(launcher.Project(name, 8000 + i)) return projects
def testDoDeploy(self): project = launcher.Project('path', 8000, 'project_name') d = launcher.DeployController(None, None, [project]) d._password = '******' self.assertFalse(d._DoDeploy()) # no name d._password = None d._authname = 'joe' self.assertFalse(d._DoDeploy()) # no password projects = [launcher.Project('path', 8000+x, 'name') for x in range(3)] started = [0] for p in projects: def dummy_start(): started[0] += 1 p.start = dummy_start d = launcher.DeployController(None, None, projects) d._authname = 'fred' d._password = '******' d._TextFrameForProject = (lambda x: x) d._TaskThreadForProject = (lambda x: x) self.assertTrue(d._DoDeploy()) self.assertEqual(3, len(d._text_frames)) self.assertEqual(3, len(d._task_threads)) for p in projects: self.assertEqual(3, started[0]) # We're already setup for testing, so while we're here, # let's test _TaskDidStop and DisplayProjectOutput didit = [False] def append_text(line): didit[0] = True projects[0].AppendText = append_text d._TaskDidStop(projects[0]) # appends one last line of text self.assertTrue(didit[0]) self.assertEqual(2, len(d._text_frames)) self.assertEqual(2, len(d._task_threads))
def testParseFlags(self): project = launcher.Project('path', 9000) sc = launcher.SettingsController(project) flagtests = { '': [], '\n\n\n\n\n\n--keyboard': ['--keyboard'], '-d': ['-d'], '--debug': ['--debug'], '-f --foo': ['-f', '--foo'], '--foo -f': ['--foo', '-f'], ' --zoo\n--path=hi mom -d --fred=hi mom --zoo': ['--zoo', '--path=hi mom', '-d', '--fred=hi mom', '--zoo'] } for key in flagtests: flaglist = sc._ParseFlags(key) self.assertEqual(flagtests[key], flaglist)
def testPort(self): """Make sure we can't set the port while running.""" p1 = launcher.Project('/tmp/foo', 8000) self.assertEqual(8000, p1.port) p1.port = 102 self.assertEqual(102, p1.port) p1.runstate = launcher.Project.STATE_RUN def setPort(): p1.port = 8000 self.assertRaises(launcher.ProjectException, setPort) self.assertEqual(102, p1.port) p1.runstate = launcher.Project.STATE_STOP p1.port = 8001 self.assertEqual(8001, p1.port)
def testSetThenGet(self): platform = FakePlatform('pythoncmd', 'dir') pref = launcher.Preferences(self.filename, platform) runtime = RuntimeNoDialog(platform, pref) self.assertFalse(runtime.problem) project = launcher.Project('super-path', '123', False) das = runtime.DevAppServerCommand(project, verify=False) self.assertTrue('pythoncmd' in das) self.assertTrue('photojournalist' not in das) pref[launcher.Preferences.PREF_PYTHON] = 'photojournalist' das = runtime.DevAppServerCommand(project, verify=False) self.assertTrue('pythoncmd' not in das) self.assertTrue('photojournalist' in das) self.assertRaises(launcher.RuntimeException, runtime.DevAppServerCommand, project)
def testEquality(self): p1 = launcher.Project('/tmp/foo', 8000) p2 = launcher.Project('/tmp/foo', 8001) p3 = launcher.Project('/windindicfnodsin', 8000) p4 = launcher.Project('/tmp/foo', 8000) self.assertEqual(p1, p4) # same path and port self.assertNotEqual(p1, p2) # differ by port self.assertNotEqual(p1, p3) # differ by path self.assertNotEqual(p2, p3) # differ by path and port # make sure both __eq__ and __ne__ hit; no guarantee with unittest self.assertTrue(p1 == p4) self.assertTrue(p1 != p3) # Make sure we test with "projects" that exist on disk for dir in ('/bin', 'c:\\'): self.assertEqual(launcher.Project(dir, 8010), launcher.Project(dir, 8010)) self.assertNotEqual(launcher.Project(dir, 8010), launcher.Project(dir, 8011))
def testProjects(self): table = launcher.MainTable(self._temp_filename) projects = [] for i in range(20): projects.append(launcher.Project('/tmp/himom' + str(i), 8000 + i)) # test Add/Remove for p in projects: table.AddProject(p) self.assertEqual(p, table.ProjectAtIndex(0)) table.RemoveProject(p) # Test big table and extraction for p in projects: table.AddProject(p) self.assertEqual(projects[19], table.ProjectAtIndex(19)) self.assertEqual(projects[12], table.ProjectAtIndex(12)) self.assertTrue(table.ProjectCount() >= 20) # Test indexing off the end, which should return None self.assertEqual(None, table.ProjectAtIndex(2817372))
def testAdd(self): """Tests both Add() and AddNew().""" for attr in ('Add', 'AddNew'): p = launcher.Project('/tmp/himom', 8123) # Avoid UI with a NoAskController controller = NoAskController(self.app, p) # Mock table to confirm AddProject() gets called table_mock = mox.MockObject(launcher.MainTable) table_mock.AddProject(p) table_mock._projects = None mox.Replay(table_mock) controller.SetModelsViews(table=table_mock) # UI should be noop, and table.AddProject() should be called in here getattr(controller, attr)(None) mox.Verify(table_mock) # Make sure the path makes it to the controller. c = NoAskController(self.app, None) c.Add(None, '/Path/To/Oblivion') self.assertEqual('/Path/To/Oblivion', c._path)
def testTaskThreadForProject(self): project = launcher.Project('path', 8000, 'project_name') d = launcher.DeployController(launcher.Runtime(), launcher.Preferences(), [project]) d._name = 'fred' d._password = '******' tt = d._TaskThreadForProject(project) self.assertFalse(tt.isAlive()) # confirm stdin works. Use python so we don't need cygwin. # Print out the 'Running application' string so that # taskthread will know to transition from WillStart to DidStart. script = ('import sys; print "Running application http://x:5"; ' 'print sys.stdin.read().strip()') cat_cmd = [sys.executable, '-c', script] tt = d._TaskThreadForProject(project, cat_cmd) output = [''] def collect(line, date=True): output[0] += line tt.LogOutput = collect starting = [0] started = [0] lock = threading.Lock() def _TaskWillStart(): starting[0] = time.time() def _TaskDidStart(): started[0] = time.time() def _TaskDidStop(code): lock.release() tt._TaskWillStart = _TaskWillStart tt._TaskDidStart = _TaskDidStart tt._TaskDidStop = _TaskDidStop lock.acquire() tt.start() lock.acquire() # blocks until _TaskDidStop() releases it lock.release() self.assertNotEqual(0, starting[0]) self.assertNotEqual(0, started[0]) # Make sure the 'started' happens after 'starting' self.assertTrue(started > starting) self.assertTrue('himom' in output[0])
def testNoDefaultsAllPrefsOverride(self): """None for ALL defaults, all pref overrides, and make sure all is happy.""" pref = launcher.Preferences(self.filename, FakePlatform(None, None)) pycmd = '/usr/bin/python' pref[launcher.Preferences.PREF_PYTHON] = pycmd pref[launcher.Preferences.PREF_APPENGINE] = '/tmp/foo/bar/baz' runtime = RuntimeNoDialog(preferences=pref) self.assertFalse(runtime.problem) project = launcher.Project('super-path', '123') # test of DevAppServerCommand() das = runtime.DevAppServerCommand(project, verify=False) self.assertTrue(pycmd in das) self.assertTrue('super-path' in das) self.assertTrue('--port=123' in das) self.assertFalse('--mega-flag' in das) self.assertRaises(launcher.RuntimeException, runtime.DevAppServerCommand, project, verify=True) # test project flags project.flags = ['--mega-flag', '--oops'] das = runtime.DevAppServerCommand(project, verify=False) self.assertTrue('--mega-flag' in das) self.assertTrue('--oops' in das) # test DevAppServerCommand's extra_flags extras = ['--hammertime', '--singsong'] for flag in extras: self.assertFalse(flag in das) das = runtime.DevAppServerCommand(project, extra_flags=extras, verify=False) for flag in extras: self.assertTrue(flag in das) # test of DeployCommand() deploy_cmd = runtime.DeployCommand(project, '*****@*****.**') for s in (pycmd, '[email protected]', 'update', 'super-path'): self.assertTrue(s in deploy_cmd) deploy_cmd = runtime.DeployCommand(project, '*****@*****.**', 'xazzy') self.assertTrue('--server=xazzy' in deploy_cmd)
def InstallDemoByName(self, path, dest_dir=None, prompt=True): """Called by a demo sub-menu item. Copies the specified demo and adds to the current project list. Args: path: A full path to the demo we want to use. dest_dir: The destination directory for the demo to be copied, or None to use a default. prompt: Solicit the user before copying the demo files. Exists for unit tests to avoid a modal dialog. """ # Find a destination path; ensure it is unique. dest_dir = dest_dir or wx.StandardPaths.Get().GetDocumentsDir() basename = os.path.basename(path) existing_files = os.listdir(dest_dir) count = 1 newname = basename while newname in existing_files: newname = '%s-%d' % (basename, count) count += 1 newpath = os.path.join(dest_dir, newname) if prompt: # Ask the user before doing anything. caption = 'Install Google App Engine demo?' message = ( 'Google App Engine Launcher wishes to copy the demo "%s" ' 'to %s' % (basename, newpath)) allow_copy_dialog = wx.MessageDialog( None, message, caption, wx.OK | wx.CANCEL | wx.ICON_QUESTION) if allow_copy_dialog.ShowModal() != wx.ID_OK: return # Copy over, create a project, and add it to our table. shutil.copytree(path, newpath) project = launcher.Project(newpath, self._table.UniquePort()) self._table.AddProject(project) self.RefreshMainView()
def Project(self): """Return a project created from interaction with this dialog. Returns: a launcher.Project, or None. Side effect: Actually creates the project on disk from the template files. """ if self._dialog_return_value != wx.ID_OK: return None path = self.GetPath() # parent directory of project port = self.GetPort() name = self.GetName() if not (self._SanityCheckPort(port) and self._SanityCheckPath(path, check_contents=False)): return None newpath = os.path.join(path, name) if not self._SanityCheckPathDoesNotExist(newpath): return None if not self._CreateProjectOnDisk(newpath, name): return None return launcher.Project(newpath, port)
def testFileSaving(self): # Make a temp file, and have the table save its projects there. table = launcher.MainTable(self._temp_filename) project = launcher.Project('/hurdy/gurdy/bonnie', 1910) table.AddProject(project) project = launcher.Project('/Users/bork/kim', 1975) table.AddProject(project) project = launcher.Project('/annie', 1860) table.AddProject(project) # Make sure paths with spaces are OK. project = launcher.Project('/ekky/ek ky/ekky/ek ky', 1967) table.AddProject(project) # It's valid to have multiple projects with the same name. project = launcher.Project('/little/orphan/annie', 1924) table.AddProject(project) # And for there to be duplicates. project = launcher.Project('/little/orphan/annie', 1924) table.AddProject(project) # Make another table, pointed at that file, and make sure everything # comes back that should. table2 = launcher.MainTable(self._temp_filename) # Reach in and get the projects array and make sure it has the # expected projects in the correct order. self.assertEqual(6, table.ProjectCount()) self.checkProject(table.ProjectAtIndex(0), '/hurdy/gurdy/bonnie', 'bonnie', 1910) self.checkProject(table.ProjectAtIndex(1), '/Users/bork/kim', 'kim', 1975) self.checkProject(table.ProjectAtIndex(2), '/annie', 'annie', 1860) self.checkProject(table.ProjectAtIndex(3), '/ekky/ek ky/ekky/ek ky', 'ek ky', 1967) self.checkProject(table.ProjectAtIndex(4), '/little/orphan/annie', 'annie', 1924) self.checkProject(table.ProjectAtIndex(5), '/little/orphan/annie', 'annie', 1924)
def testCloseHandler(self): """Test our close handler (if not force, hide window and save for later)""" project = launcher.Project('path', 8000, 'name') lc = launcher.LogConsole(project) self.did_hide = False self.did_destroy = False orig_show = lc.Show orig_destroy = lc.Destroy # Override some methods so we can track behavior lc.Show = self.ConfirmedShow lc.Destroy = self.ConfirmedDestroy # Call our wx.EVT_CLOSE handler; CAN be veto'ed lc.Close(force=False) self.assertTrue(self.did_hide) self.assertFalse(self.did_destroy) self.did_hide = False self.did_destroy = False # Call our wx.EVT_CLOSE handler; CANNOT be veto'ed lc.Close(force=True) self.assertFalse(self.did_hide) self.assertTrue(self.did_destroy) # Restore original methods lc.Show = orig_show lc.Destroy = orig_destroy