def setUp(self): ''' Setup and populate a local and "remote" test Git repository ''' path = getcwd() # Get rid of any old garbage if exists(TEST_RM_GIT): rmtree(TEST_RM_GIT) if exists(TEST_LOC_GIT): rmtree(TEST_LOC_GIT) # Create a new remote repository args = ['git', 'init', '--bare', TEST_RM_GIT] subprocess.check_call(args) chdir(TEST_RM_GIT) args = ['git', 'config', 'user.name', 'Jonathan Gossage'] subprocess.check_call(args) args = ['git', 'config', 'user.email', 'jgossage@xxx'] subprocess.check_call(args) # Clone a local copy of the "remote" repository chdir('..') args = ['git', 'clone', '--no-hardlinks', abspath(TEST_RM_GIT), TEST_LOC_GIT] subprocess.check_call(args) chdir(TEST_LOC_GIT) args = ['git', 'config', 'user.name', 'Jonathan Gossage'] subprocess.check_call(args) args = ['git', 'config', 'user.email', 'jgossage@xxx'] subprocess.check_call(args) # Create some files in each directory dirs = (PROJECTS, RELEASES, STORIES, SPRINTS, TASKS) for d in dirs: mkdir(d) for f in range(10): self.createFile(join(d, 'File' + str(f))) # Check in the content we just created and push to remote args = ['git', 'add'] + list(dirs) subprocess.check_call(args) args = ['git', 'commit', '-m "Initial commit"' ] subprocess.check_call(args) args = ['git', 'push', 'origin', 'master'] subprocess.check_call(args) chdir('..') # Create the Git Manager that will be used for the tests self._queue = Queue.Queue(0) self._manager = GitManager(join(path, TEST_LOC_GIT), None, self._queue, logging) self._manager.start() return
def __init__(self): self._git = None self._collaborationFrom = None self._collaborationTo = None self._no_collaboration = False self._localrepo = Config().datastore if Config().datastore else None self._response_queue = Queue.Queue(0) pymt.event.EventDispatcher.__init__(self) self._outstanding_events = 0 # Create the asynchronous objects if self._localrepo: self._git = GitManager(self._localrepo, not Config().sharedRepoNotAvailable, self._response_queue, log=Log) if not Config().collaborationNotAvailable: self._collaborationFrom = ServerManager(\ response_queue=self._response_queue, host='0.0.0.0', port=Config().local_port, log=Log) self._collaborationTo = ToCollaboration(\ self._response_queue, host='0.0.0.0', port=Config().collaboration_port, log=Log) else: self._no_collaboration = True # These are the events we will dispatch self.register_event_type(ON_GITSAVE) self.register_event_type(ON_GITCOMMIT) self.register_event_type(ON_GITMV) self.register_event_type(ON_GITRM) self.register_event_type(ON_GITHUBNOTIFICATION) self.register_event_type(ON_SUBSCRIPTION_RESPONSE) # We will get notified from the main event loop on each loop # iteration pymt.base.getWindow().push_handlers(self) # Start the asynchronous processing threads if self._localrepo: self._git.start() if not self._no_collaboration: self._collaborationFrom.start() self._collaborationTo.start() self.subscribe(True)
class Test(unittest.TestCase): ''' This test is self-contained and can be run from within Eclipse ''' def createFile(self, path, lines=10): with open(path, 'w') as f: for _ in range(lines): f.write(('*' * 50) + '\n') def modifyFile(self, path, line=5): with open(path, 'r+') as f: for _ in range(line): f.readline() f.write(('+' * 50) + '\n') pass def setUp(self): ''' Setup and populate a local and "remote" test Git repository ''' path = getcwd() # Get rid of any old garbage if exists(TEST_RM_GIT): rmtree(TEST_RM_GIT) if exists(TEST_LOC_GIT): rmtree(TEST_LOC_GIT) # Create a new remote repository args = ['git', 'init', '--bare', TEST_RM_GIT] subprocess.check_call(args) chdir(TEST_RM_GIT) args = ['git', 'config', 'user.name', 'Jonathan Gossage'] subprocess.check_call(args) args = ['git', 'config', 'user.email', 'jgossage@xxx'] subprocess.check_call(args) # Clone a local copy of the "remote" repository chdir('..') args = ['git', 'clone', '--no-hardlinks', abspath(TEST_RM_GIT), TEST_LOC_GIT] subprocess.check_call(args) chdir(TEST_LOC_GIT) args = ['git', 'config', 'user.name', 'Jonathan Gossage'] subprocess.check_call(args) args = ['git', 'config', 'user.email', 'jgossage@xxx'] subprocess.check_call(args) # Create some files in each directory dirs = (PROJECTS, RELEASES, STORIES, SPRINTS, TASKS) for d in dirs: mkdir(d) for f in range(10): self.createFile(join(d, 'File' + str(f))) # Check in the content we just created and push to remote args = ['git', 'add'] + list(dirs) subprocess.check_call(args) args = ['git', 'commit', '-m "Initial commit"' ] subprocess.check_call(args) args = ['git', 'push', 'origin', 'master'] subprocess.check_call(args) chdir('..') # Create the Git Manager that will be used for the tests self._queue = Queue.Queue(0) self._manager = GitManager(join(path, TEST_LOC_GIT), None, self._queue, logging) self._manager.start() return def tearDown(self): # Get rid of the test apparatus try: self._manager.shutdown() # Wait until manager shuts down finally: if exists(TEST_RM_GIT): rmtree(TEST_RM_GIT) if exists(TEST_LOC_GIT): rmtree(TEST_LOC_GIT) def testSave1(self): ''' Add a single file to the data-store and verify that it can be saved Pass the file explicitly ''' f = join(TEST_LOC_GIT, STORIES, 'Story1') self.createFile(f) self._manager.save([join(STORIES, 'Story1')], 'Test commit 1') ret = self._queue.get(True, 2400) self.assertTrue(ret[0] == GIT_RESPONSE) self.assertTrue(ret[1][0] == SAVE) print('Stdout:') for l in ret[1][1][1]: print(l) print('Stderr:') for l in ret[1][1][2]: print(l) self.assertTrue(ret[1][1][0] == 0) if len(ret[1][1][3]) != 0: self.assertTrue(join(STORIES, 'Story1') in ret[1][1][3]) # Add three files and modify an existing file # Let Git recognise the modified stuff implicitly self.createFile(join(TEST_LOC_GIT, TASKS, 'Task1')) self.createFile(join(TEST_LOC_GIT, PROJECTS, 'Project1')) self.createFile(join(TEST_LOC_GIT, SPRINTS, 'Sprint1')) self.modifyFile(join(TEST_LOC_GIT, STORIES, 'Story1')) self._manager.save(None, 'Test commit 2') try: ret = self._queue.get(True, 10) self.assertTrue(ret[0] == GIT_RESPONSE) self.assertTrue(ret[1][0] == SAVE) print('Stdout:') for l in ret[1][1][1]: print(l) print('Stderr:') for l in ret[1][1][2]: print(l) self.assertTrue(ret[1][1][0] == 0) except Queue.Empty: self.assertTrue(False)
class Async(pymt.event.EventDispatcher): def __init__(self): self._git = None self._collaborationFrom = None self._collaborationTo = None self._no_collaboration = False self._localrepo = Config().datastore if Config().datastore else None self._response_queue = Queue.Queue(0) pymt.event.EventDispatcher.__init__(self) self._outstanding_events = 0 # Create the asynchronous objects if self._localrepo: self._git = GitManager(self._localrepo, not Config().sharedRepoNotAvailable, self._response_queue, log=Log) if not Config().collaborationNotAvailable: self._collaborationFrom = ServerManager(\ response_queue=self._response_queue, host='0.0.0.0', port=Config().local_port, log=Log) self._collaborationTo = ToCollaboration(\ self._response_queue, host='0.0.0.0', port=Config().collaboration_port, log=Log) else: self._no_collaboration = True # These are the events we will dispatch self.register_event_type(ON_GITSAVE) self.register_event_type(ON_GITCOMMIT) self.register_event_type(ON_GITMV) self.register_event_type(ON_GITRM) self.register_event_type(ON_GITHUBNOTIFICATION) self.register_event_type(ON_SUBSCRIPTION_RESPONSE) # We will get notified from the main event loop on each loop # iteration pymt.base.getWindow().push_handlers(self) # Start the asynchronous processing threads if self._localrepo: self._git.start() if not self._no_collaboration: self._collaborationFrom.start() self._collaborationTo.start() self.subscribe(True) def logAsyncInfo(self, ret): if ret is None: return msg = ret[1] # Log stdout messages if len(msg) <= 1: pass if msg[1]: for l in msg[1]: Log.info(l) # Log stderr messages if msg[2]: for l in msg[2]: if msg[0] == 0: Log.info(l) else: Log.error(l) def on_gitsave(self, ret): self._outstanding_events -= 1 Log.debug('Git save completed - outstanding events %s'\ % self._outstanding_events) assert(self._outstanding_events >= 0) self.logAsyncInfo(ret) def on_gitcommit(self, ret): self._outstanding_events -= 1 Log.debug('Git commit completed - outstanding events %s'\ % self._outstanding_events) assert(self._outstanding_events >= 0) self.logAsyncInfo(ret) def on_gitmv(self, ret): self._outstanding_events -= 1 Log.debug('Git mv completed - outstanding events %s'\ % self._outstanding_events) assert(self._outstanding_events >= 0) self.logAsyncInfo(ret) def on_gitrm(self, ret): self._outstanding_events -= 1 Log.debug('Git rm completed - outstanding events %s'\ % self._outstanding_events) assert(self._outstanding_events >= 0) self.logAsyncInfo(ret) def on_githubnotification(self, ret): msg = ret[1] Log.debug('Handle Github notification') user = Config().collaborationUser need_pull = False for c in msg['commits']: if user != c['author']['email']: need_pull = True if need_pull: self.save(None, 'Received notification of new content from Github') def on_subscriptionresponse(self, ret): self._outstanding_events -= 1 assert(self._outstanding_events >= 0) msg = ret[1] Log.debug('Got subscription response: %s'\ % 'accepted' if msg[0] == httplib.OK else 'rejected') if msg[0] != httplib.OK: if len(msg) > 2 and len(msg[2]) > 2 and msg[2][2] is not None: Log.error('Problematic HTTP response: %s' % str(msg[2])) else: Log.error('Subscription call failed: result: %i reason: %s' % (msg[0], str(msg[1]))) def on_update(self): ''' The main event loop is telling us to check if we have anything queued from any of our asynchronous processes. If so let our subscribers know ''' try: while True: # drain the event queue ret = self._response_queue.get(False) # Dispatch the event to the registered handlers Log.debug('About to dispatch %s' % str(ret)) self.dispatch_event(handler_mapper[ret[0]][ret[1][0]], ret[1]) except Queue.Empty: pass def isEmpty(self): return self._response_queue.empty() def save(self, files, message): if not self._localrepo: return # Local repo not present - don't do anything Git related self._outstanding_events += 1 self._git.save(files, message) def commit(self, files, message): if not self._localrepo: return self._outstanding_events += 1 Log.debug('About to run Git commit: %s' % self._outstanding_events) self._git.commit(files, message) def mv(self, old, new): self._outstanding_events += 1 Log.debug('About to run Git mv: %s' % self._outstanding_events) self._git.mv(old, new) def rm(self, target): self._outstanding_events += 1 Log.debug('About to run Git rm: %s' % self._outstanding_events) self._git.rm(target) def subscribe(self, on): if self._no_collaboration: return msg = self._collaborationTo.constructSubscriptionMsg(\ on, Config().gitSubscription, Config().collaborationResponseUrl, Config().local_port, Config().collaborationUser, testing=Config().testingServer) Log.debug('About to change subscription status %s' % on) self._outstanding_events += 1 self._collaborationTo.subscribe(msg, Config().collaborationServerUrl, Config().collaboration_port, Log.warning) def shutdown(self): # We need to handle any outstanding events before we shutdown try: if self._collaborationTo: # Unsubscribe from the collaboration server self.subscribe(False) while self._git and self._outstanding_events > 0: try: ret = self._response_queue.get(True, SHUTDOWN_TIMEOUT) Log.debug('Async return in shutdown: %s' % str(ret)) if not ret or not ret[1]: continue if ret[1][0] == SHUTDOWN: continue # No event handler for shutdown self.dispatch_event(handler_mapper[ret[0]][ret[1][0]], ret[1]) except Queue.Empty: self._outstanding_events = 0 finally: if self._collaborationFrom and not self._collaborationFrom.broken: self._collaborationFrom.server.shutdown() self._collaborationFrom = None if self._collaborationTo: self._collaborationTo.shutdown() self._collaborationTo = None if self._git: ret = self._git.shutdown() self._git = None # Prevent recursive shutdown if ret is not None: self.logAsyncInfo(ret[1]) self._outstanding_events = 0