Exemple #1
0
def run_analysis(user, analysis):
    """Run the commands within an Analysis object and sends user messages"""
    analysis.status = "running"
    all_good = True
    pubsub = r_server.pubsub()
    pubsub.subscribe(user)
    for job_id in analysis.jobs:
        job = Job(job_id)
        if job.status == 'queued':
            name, command = job.command
            options = job.options
            # create json base for websocket messages
            msg = {
                "analysis": analysis.id,
                "msg": None,
                "command": "%s: %s" % (job.datatype, name)
            }

            o_fmt = ' '.join(['%s %s' % (k, v) for k, v in options.items()])
            c_fmt = str("%s %s" % (command, o_fmt))

            # send running message to user wait page
            job.status = 'running'
            msg["msg"] = "Running"
            r_server.rpush(user + ":messages", dumps(msg))
            r_server.publish(user, dumps(msg))

            # run the command
            try:
                qiita_compute.submit_sync(c_fmt)
            except Exception as e:
                all_good = False
                job.status = 'error'
                msg["msg"] = "ERROR"
                r_server.rpush(user + ":messages", dumps(msg))
                r_server.publish(user, dumps(msg))
                print("Failed compute on job id %d: %s\n%s" %
                      (job_id, e, c_fmt))
                continue

            msg["msg"] = "Completed"
            r_server.rpush(user + ":messages", dumps(msg))
            r_server.publish(user, dumps(msg))
            # FIX THIS Should not be hard coded
            job.add_results([(options["--output_dir"], "directory")])
            job.status = 'completed'

    # send websockets message that we are done
    msg["msg"] = "allcomplete"
    msg["command"] = ""
    r_server.rpush(user + ":messages", dumps(msg))
    r_server.publish(user, dumps(msg))
    pubsub.unsubscribe()
    # set final analysis status
    if all_good:
        analysis.status = "completed"
    else:
        analysis.status = "error"
Exemple #2
0
def system_call_from_job(job_id, **kwargs):
    """Executes a system call described by a Job

    Parameters
    ----------
    job_id : int
        The job object ID
    """
    job = Job(job_id)
    name, command = job.command
    options = job.options

    cmd = [command]
    cmd.extend(flatten(options.items()))
    cmd_fmt = ' '.join((str(i) for i in cmd))

    try:
        so, se, status = system_call(cmd_fmt)
    except Exception as e:
        job.set_error(str(e))
        raise

    # FIX THIS add_results should not be hard coded  Issue #269
    job.add_results([(job.options["--output_dir"], "directory")])
Exemple #3
0
def system_call_from_job(job_id, **kwargs):
    """Executes a system call described by a Job

    Parameters
    ----------
    job_id : int
        The job object ID
    """
    job = Job(job_id)
    name, command = job.command
    options = job.options

    cmd = [command]
    cmd.extend(flatten(options.items()))
    cmd_fmt = ' '.join((str(i) for i in cmd))

    try:
        so, se, status = system_call(cmd_fmt)
    except Exception as e:
        job.set_error(str(e))
        raise

    # FIX THIS add_results should not be hard coded  Issue #269
    job.add_results([(job.options["--output_dir"], "directory")])
Exemple #4
0
class JobTest(TestCase):
    """Tests that the job object works as expected"""

    def setUp(self):
        self.job = Job(1)
        self.options = {"option1": False, "option2": 25, "option3": "NEW"}
        self._delete_path = []
        self._delete_dir = []
        _, self._job_folder = get_mountpoint("job")[0]

    def tearDown(self):
        # needs to be this way because map does not play well with remove and
        # rmtree for python3
        for item in self._delete_path:
            remove(item)
        for item in self._delete_dir:
            rmtree(item)

    def test_exists(self):
        """tests that existing job returns true"""
        # need to insert matching sample data into analysis 2
        self.conn_handler.execute(
            "DELETE FROM qiita.analysis_sample WHERE analysis_id = 2")
        self.conn_handler.execute(
            "INSERT INTO qiita.analysis_sample "
            "(analysis_id, processed_data_id, sample_id) VALUES "
            "(2, 1,'1.SKB8.640193'), (2, 1,'1.SKD8.640184'), "
            "(2, 1,'1.SKB7.640196'), (2, 1,'1.SKM9.640192'), "
            "(2, 1,'1.SKM4.640180')")
        self.assertTrue(Job.exists("18S", "Beta Diversity",
                                   {"--otu_table_fp": 1,
                                    "--mapping_fp": 1}, Analysis(1)))

    def test_exists_return_jobid(self):
        """tests that existing job returns true"""
        # need to insert matching sample data into analysis 2
        self.conn_handler.execute(
            "DELETE FROM qiita.analysis_sample WHERE analysis_id = 2")
        self.conn_handler.execute(
            "INSERT INTO qiita.analysis_sample "
            "(analysis_id, processed_data_id, sample_id) VALUES "
            "(2, 1,'1.SKB8.640193'), (2, 1,'1.SKD8.640184'), "
            "(2, 1,'1.SKB7.640196'), (2, 1,'1.SKM9.640192'), "
            "(2, 1,'1.SKM4.640180')")
        exists, jid = Job.exists("18S", "Beta Diversity",
                                 {"--otu_table_fp": 1, "--mapping_fp": 1},
                                 Analysis(1), return_existing=True)
        self.assertTrue(exists)
        self.assertEqual(jid, Job(2))

    def test_exists_noexist_options(self):
        """tests that non-existant job with bad options returns false"""
        # need to insert matching sample data into analysis 2
        # makes sure failure is because options and not samples
        self.conn_handler.execute(
            "DELETE FROM qiita.analysis_sample WHERE analysis_id = 2")
        self.conn_handler.execute(
            "INSERT INTO qiita.analysis_sample "
            "(analysis_id, processed_data_id, sample_id) VALUES "
            "(2, 1,'1.SKB8.640193'), (2, 1,'1.SKD8.640184'), "
            "(2, 1,'1.SKB7.640196'), (2, 1,'1.SKM9.640192'), "
            "(2, 1,'1.SKM4.640180')")
        self.assertFalse(Job.exists("18S", "Beta Diversity",
                                    {"--otu_table_fp": 1,
                                     "--mapping_fp": 27}, Analysis(1)))

    def test_exists_noexist_return_jobid(self):
        """tests that non-existant job with bad samples returns false"""
        exists, jid = Job.exists(
            "16S", "Beta Diversity",
            {"--otu_table_fp": 1, "--mapping_fp": 27}, Analysis(1),
            return_existing=True)
        self.assertFalse(exists)
        self.assertEqual(jid, None)

    def test_get_commands(self):
        exp = [
            Command('Summarize Taxa', 'summarize_taxa_through_plots.py',
                    '{"--otu_table_fp":null}', '{}',
                    '{"--mapping_category":null, "--mapping_fp":null,'
                    '"--sort":null}', '{"--output_dir":null}'),
            Command('Beta Diversity', 'beta_diversity_through_plots.py',
                    '{"--otu_table_fp":null,"--mapping_fp":null}', '{}',
                    '{"--tree_fp":null,"--color_by_all_fields":null,'
                    '"--seqs_per_sample":null}', '{"--output_dir":null}'),
            Command('Alpha Rarefaction', 'alpha_rarefaction.py',
                    '{"--otu_table_fp":null,"--mapping_fp":null}', '{}',
                    '{"--tree_fp":null,"--num_steps":null,''"--min_rare_depth"'
                    ':null,"--max_rare_depth":null,'
                    '"--retain_intermediate_files":false}',
                    '{"--output_dir":null}')
            ]
        self.assertEqual(Job.get_commands(), exp)

    def test_delete_files(self):
        try:
            Job.delete(1)
            with self.assertRaises(QiitaDBUnknownIDError):
                Job(1)

            obs = self.conn_handler.execute_fetchall(
                "SELECT * FROM qiita.filepath WHERE filepath_id = 12 OR "
                "filepath_id = 19")
            self.assertEqual(obs, [])

            obs = self.conn_handler.execute_fetchall(
                "SELECT * FROM qiita.job_results_filepath WHERE job_id = 1")
            self.assertEqual(obs, [])

            obs = self.conn_handler.execute_fetchall(
                "SELECT * FROM qiita.analysis_job WHERE job_id = 1")
            self.assertEqual(obs, [])

            self.assertFalse(exists(join(self._job_folder,
                             "1_job_result.txt")))
        finally:
            f = join(self._job_folder, "1_job_result.txt")
            if not exists(f):
                with open(f, 'w') as f:
                    f.write("job1result.txt")

    def test_delete_folders(self):
        try:
            Job.delete(2)
            with self.assertRaises(QiitaDBUnknownIDError):
                Job(2)

            obs = self.conn_handler.execute_fetchall(
                "SELECT * FROM qiita.filepath WHERE filepath_id = 13")
            self.assertEqual(obs, [])

            obs = self.conn_handler.execute_fetchall(
                "SELECT * FROM qiita.job_results_filepath WHERE job_id = 2")
            self.assertEqual(obs, [])

            obs = self.conn_handler.execute_fetchall(
                "SELECT * FROM qiita.analysis_job WHERE job_id = 2")
            self.assertEqual(obs, [])

            self.assertFalse(exists(join(self._job_folder, "2_test_folder")))
        finally:
            # put the test data back
            basedir = self._job_folder
            if not exists(join(basedir, "2_test_folder")):
                mkdir(join(basedir, "2_test_folder"))
                mkdir(join(basedir, "2_test_folder", "subdir"))
                with open(join(basedir, "2_test_folder",
                               "testfile.txt"), 'w') as f:
                    f.write("DATA")
                with open(join(basedir, "2_test_folder",
                               "testres.htm"), 'w') as f:
                    f.write("DATA")
                with open(join(basedir, "2_test_folder",
                               "subdir", "subres.html"), 'w') as f:
                    f.write("DATA")

    def test_create(self):
        """Makes sure creation works as expected"""
        # make first job
        new = Job.create("18S", "Alpha Rarefaction", {"opt1": 4}, Analysis(1))
        self.assertEqual(new.id, 4)
        # make sure job inserted correctly
        obs = self.conn_handler.execute_fetchall("SELECT * FROM qiita.job "
                                                 "WHERE job_id = 4")
        exp = [[4, 2, 1, 3, '{"opt1":4}', None]]
        self.assertEqual(obs, exp)
        # make sure job added to analysis correctly
        obs = self.conn_handler.execute_fetchall("SELECT * FROM "
                                                 "qiita.analysis_job WHERE "
                                                 "job_id = 4")
        exp = [[1, 4]]
        self.assertEqual(obs, exp)

        # make second job with diff datatype and command to test column insert
        new = Job.create("16S", "Beta Diversity", {"opt1": 4}, Analysis(1))
        self.assertEqual(new.id, 5)
        # make sure job inserted correctly
        obs = self.conn_handler.execute_fetchall("SELECT * FROM qiita.job "
                                                 "WHERE job_id = 5")
        exp = [[5, 1, 1, 2, '{"opt1":4}', None]]
        self.assertEqual(obs, exp)
        # make sure job added to analysis correctly
        obs = self.conn_handler.execute_fetchall("SELECT * FROM "
                                                 "qiita.analysis_job WHERE "
                                                 "job_id = 5")
        exp = [[1, 5]]
        self.assertEqual(obs, exp)

    def test_create_exists(self):
        """Makes sure creation doesn't duplicate a job"""
        with self.assertRaises(QiitaDBDuplicateError):
            Job.create("18S", "Beta Diversity",
                       {"--otu_table_fp": 1, "--mapping_fp": 1},
                       Analysis(1))

    def test_create_exists_return_existing(self):
        """Makes sure creation doesn't duplicate a job by returning existing"""
        Analysis.create(User("*****@*****.**"), "new", "desc")
        self.conn_handler.execute(
            "INSERT INTO qiita.analysis_sample "
            "(analysis_id, processed_data_id, sample_id) VALUES "
            "(3, 1, '1.SKB8.640193'), (3, 1, '1.SKD8.640184'), "
            "(3, 1, '1.SKB7.640196'), (3, 1, '1.SKM9.640192'), "
            "(3, 1, '1.SKM4.640180')")
        new = Job.create("18S", "Beta Diversity",
                         {"--otu_table_fp": 1, "--mapping_fp": 1},
                         Analysis(3), return_existing=True)
        self.assertEqual(new.id, 2)

    def test_retrieve_datatype(self):
        """Makes sure datatype retrieval is correct"""
        self.assertEqual(self.job.datatype, '18S')

    def test_retrieve_command(self):
        """Makes sure command retrieval is correct"""
        self.assertEqual(self.job.command, ['Summarize Taxa',
                                            'summarize_taxa_through_plots.py'])

    def test_retrieve_options(self):
        self.assertEqual(self.job.options, {
            '--otu_table_fp': 1,
            '--output_dir': join(
                self._job_folder,
                '1_summarize_taxa_through_plots.py_output_dir')})

    def test_set_options(self):
        new = Job.create("18S", "Alpha Rarefaction", {"opt1": 4}, Analysis(1))
        new.options = self.options
        self.options['--output_dir'] = join(self._job_folder,
                                            '4_alpha_rarefaction.'
                                            'py_output_dir')
        self.assertEqual(new.options, self.options)

    def test_retrieve_results(self):
        self.assertEqual(self.job.results, ["1_job_result.txt"])

    def test_retrieve_results_folder(self):
        job = Job(2)
        self.assertEqual(job.results, ['2_test_folder/testres.htm',
                                       '2_test_folder/subdir/subres.html'])

    def test_retrieve_results_empty(self):
        new = Job.create("18S", "Beta Diversity", {"opt1": 4}, Analysis(1))
        self.assertEqual(new.results, [])

    def test_set_error(self):
        before = datetime.now()
        self.job.set_error("TESTERROR")
        after = datetime.now()
        self.assertEqual(self.job.status, "error")

        error = self.job.error

        self.assertEqual(error.severity, 2)
        self.assertEqual(error.msg, 'TESTERROR')
        self.assertTrue(before < error.time < after)

    def test_retrieve_error_blank(self):
        self.assertEqual(self.job.error, None)

    def test_set_error_completed(self):
        self.job.status = "error"
        with self.assertRaises(QiitaDBStatusError):
            self.job.set_error("TESTERROR")

    def test_retrieve_error_exists(self):
        self.job.set_error("TESTERROR")
        self.assertEqual(self.job.error.msg, "TESTERROR")

    def test_add_results(self):
        self.job.add_results([(join(self._job_folder, "1_job_result.txt"),
                             "plain_text")])

        # make sure files attached to job properly
        obs = self.conn_handler.execute_fetchall(
            "SELECT * FROM qiita.job_results_filepath WHERE job_id = 1")

        self.assertEqual(obs, [[1, 12], [1, 19]])

    def test_add_results_dir(self):
        # Create a test directory
        test_dir = join(self._job_folder, "2_test_folder")

        # add folder to job
        self.job.add_results([(test_dir, "directory")])

        # make sure files attached to job properly
        obs = self.conn_handler.execute_fetchall(
            "SELECT * FROM qiita.job_results_filepath WHERE job_id = 1")
        self.assertEqual(obs, [[1, 12], [1, 19]])

    def test_add_results_completed(self):
        self.job.status = "completed"
        with self.assertRaises(QiitaDBStatusError):
            self.job.add_results([("/fake/dir/", "directory")])