예제 #1
0
    def _testExternal(self, moduleName, pyFiles, virtualenv=False):
        dirPath = self._createTempDir()
        if virtualenv:
            self.assertTrue(inVirtualEnv())
            # --never-download prevents silent upgrades to pip, wheel and setuptools
            subprocess.check_call([
                'virtualenv', '--never-download', '--python', exactPython,
                dirPath
            ])
            sitePackages = os.path.join(dirPath, 'lib', exactPython,
                                        'site-packages')
            # tuple assignment is necessary to make this line immediately precede the try:
            oldPrefix, sys.prefix, dirPath = sys.prefix, dirPath, sitePackages
        else:
            oldPrefix = None
        try:
            for relPath in pyFiles:
                path = os.path.join(dirPath, relPath)
                mkdir_p(os.path.dirname(path))
                with open(path, 'w') as f:
                    f.write('pass\n')
            sys.path.append(dirPath)
            try:
                userScript = importlib.import_module(moduleName)
                try:
                    self._test(userScript.__name__,
                               expectedContents=pyFiles,
                               allowExtraContents=True)
                finally:
                    del userScript
                    while moduleName:
                        del sys.modules[moduleName]
                        self.assertFalse(moduleName in sys.modules)
                        moduleName = '.'.join(moduleName.split('.')[:-1])

            finally:
                sys.path.remove(dirPath)
        finally:
            if oldPrefix:
                sys.prefix = oldPrefix
예제 #2
0
    def testDockerClean(self,
                        disableCaching=True,
                        detached=True,
                        rm=True,
                        deferParam=None):
        """
        Run the test container that creates a file in the work dir, and sleeps
        for 5 minutes.
        Ensure that the calling job gets SIGKILLed after a minute, leaving
        behind the spooky/ghost/zombie container. Ensure that the container is
        killed on batch system shutdown (through the deferParam mechanism).
        """

        # We need to test the behaviour of `deferParam` with `rm` and
        # `detached`. We do not look at the case where `rm` and `detached` are
        # both True.  This is the truth table for the different combinations at
        # the end of the test. R = Running, X = Does not exist, E = Exists but
        # not running.
        #              None     FORGO     STOP    RM
        #    rm        X         R         X      X
        # detached     R         R         E      X
        #  Neither     R         R         E      X

        data_dir = os.path.join(self.tempDir, 'data')
        working_dir = os.path.join(self.tempDir, 'working')
        test_file = os.path.join(working_dir, 'test.txt')

        mkdir_p(data_dir)
        mkdir_p(working_dir)

        options = Job.Runner.getDefaultOptions(
            os.path.join(self.tempDir, 'jobstore'))
        options.logLevel = self.dockerTestLogLevel
        options.workDir = working_dir
        options.clean = 'always'
        options.disableCaching = disableCaching

        # No base64 logic since it might create a name starting with a `-`.
        container_name = uuid.uuid4().hex
        A = Job.wrapJobFn(_testDockerCleanFn, working_dir, detached, rm,
                          deferParam, container_name)
        try:
            Job.Runner.startToil(A, options)
        except FailedJobsException:
            # The file created by spooky_container would remain in the directory
            # and since it was created inside the container, it would have had
            # uid and gid == 0 (root) which may cause problems when docker
            # attempts to clean up the jobstore.
            file_stats = os.stat(test_file)
            assert file_stats.st_gid != 0
            assert file_stats.st_uid != 0

            if (rm and (deferParam != FORGO)) or deferParam == RM:
                # These containers should not exist
                assert containerIsRunning(container_name) is None, \
                    'Container was not removed.'

            elif deferParam == STOP:
                # These containers should exist but be non-running
                assert containerIsRunning(container_name) == False, \
                    'Container was not stopped.'

            else:
                # These containers will be running
                assert containerIsRunning(container_name) == True, \
                    'Container was not running.'
        client = docker.from_env(version='auto')
        dockerKill(container_name, client)
        try:
            os.remove(test_file)
        except:
            pass
예제 #3
0
 def testSubprocessDockerClean(self, caching=True):
     """
     Run the test container that creates a file in the work dir, and sleeps for 5 minutes.  Ensure
     that the calling job gets SIGKILLed after a minute, leaving behind the spooky/ghost/zombie
     container. Ensure that the container is killed on batch system shutdown (through the defer
     mechanism).
     This inherently also tests _docker
     :returns: None
     """
     # We need to test the behaviour of `defer` with `rm` and `detached`. We do not look at the case
     # where `rm` and `detached` are both True.  This is the truth table for the different
     # combinations at the end of the test. R = Running, X = Does not exist, E = Exists but not
     # running.
     #              None     FORGO     STOP    RM
     #    rm        X         R         X      X
     # detached     R         R         E      X
     #  Neither     R         R         E      X
     assert os.getuid() != 0, "Cannot test this if the user is root."
     data_dir = os.path.join(self.tempDir, 'data')
     work_dir = os.path.join(self.tempDir, 'working')
     test_file = os.path.join(data_dir, 'test.txt')
     mkdir_p(data_dir)
     mkdir_p(work_dir)
     options = Job.Runner.getDefaultOptions(
         os.path.join(self.tempDir, 'jobstore'))
     options.logLevel = 'INFO'
     options.workDir = work_dir
     options.clean = 'always'
     if not caching:
         options.disableCaching = True
     for rm in (True, False):
         for detached in (True, False):
             if detached and rm:
                 continue
             for defer in (FORGO, STOP, RM, None):
                 # Not using base64 logic here since it might create a name starting with a `-`.
                 container_name = uuid.uuid4().hex
                 A = Job.wrapJobFn(_testSubprocessDockerCleanFn, data_dir,
                                   detached, rm, defer, container_name)
                 try:
                     Job.Runner.startToil(A, options)
                 except FailedJobsException:
                     # The file created by spooky_container would remain in the directory, and since
                     # it was created inside the container, it would have had uid and gid == 0 (root)
                     # upon creation. If the defer mechanism worked, it should now be non-zero and we
                     # check for that.
                     file_stats = os.stat(test_file)
                     assert file_stats.st_gid != 0
                     assert file_stats.st_uid != 0
                     if (rm and defer != FORGO) or defer == RM:
                         # These containers should not exist
                         assert containerIsRunning(container_name) is None, \
                             'Container was not removed.'
                     elif defer == STOP:
                         # These containers should exist but be non-running
                         assert containerIsRunning(container_name) == False, \
                             'Container was not stopped.'
                     else:
                         # These containers will be running
                         assert containerIsRunning(container_name) == True, \
                             'Container was not running.'
                 finally:
                     # Prepare for the next test.
                     _dockerKill(container_name, RM)
                     os.remove(test_file)