示例#1
0
    def test_worker_raises_key_error(self):
        """
        Test that a KeyError is raised if the attributes of a Deployment model,
        that uniquely identifies a record, are not passed.
        """

        worker_payload_1 = {
            'application': 'adsws',
            'environment': 'staging',
        }
        worker_payload_2 = {
            'environment': 'production',
            'commit': 'latest-commit',
        }
        worker_payload_3 = {
            'application': 'graphics',
        }
        worker_payload_4 = {
            'commit': 'latest-commit',
        }
        worker_payload_5 = {
            'environment': 'staging'
        }
        payloads = [worker_payload_1, worker_payload_2, worker_payload_3,
                    worker_payload_4, worker_payload_5]

        worker = DatabaseWriterWorker()

        for payload in payloads:
            with self.assertRaises(KeyError):
                worker.process_payload(payload)
示例#2
0
    def test_worker_raises_key_error(self):
        """
        Test that a KeyError is raised if the attributes of a Deployment model,
        that uniquely identifies a record, are not passed.
        """

        worker_payload_1 = {"application": "adsws", "environment": "staging"}
        worker_payload_2 = {"environment": "production", "version": "latest-commit"}
        worker_payload_3 = {"application": "graphics"}
        worker_payload_4 = {"version": "latest-commit"}
        worker_payload_5 = {"environment": "staging"}
        payloads = [worker_payload_1, worker_payload_2, worker_payload_3, worker_payload_4, worker_payload_5]

        worker = DatabaseWriterWorker()

        for payload in payloads:
            with self.assertRaises(KeyError):
                worker.process_payload(payload)
示例#3
0
    def test_worker_updates_deployed_status(self):
        """
        When a new service is successful in being deployed, it should update any
        other service with the same env/app combination to not being deployed.
        There is most likely a smarter way to do this....
        """

        first_payload = {
            'application': 'staging',
            'environment': 'adsws',
            'commit': 'first-commit',
            'tag': 'first-tag',
            'deployed': True,
            'tested': False
        }
        second_payload = {
            'application': 'staging',
            'environment': 'adsws',
            'commit': 'second-commit',
            'tag': 'second-tag',
            'deployed': True,
            'tested': False
        }

        worker = DatabaseWriterWorker()
        worker.process_payload(first_payload)

        with self.app.session_scope() as session:
            deployment = session.query(Deployment).filter(
                Deployment.commit == 'first-commit'
            ).one()
            self.assertTrue(deployment.deployed)

        worker.process_payload(second_payload)
        with self.app.session_scope() as session:
            deployment_2 = session.query(Deployment).filter(
                Deployment.commit == 'second-commit'
            ).one()
            self.assertTrue(deployment_2.deployed)

            deployment_1 = session.query(Deployment).filter(
                Deployment.commit == 'first-commit'
            ).one()
            self.assertFalse(deployment_1.deployed)
示例#4
0
    def test_worker_overwrites_entry(self):
        """
        Test that the worker overwrites the relevant data in the database
        """

        # Stub the database entry
        with self.app.session_scope() as session:
            deployment = Deployment(
                application='staging',
                environment='adsws',
                commit='latest-commit',
                tag='latest-tag',
                deployed=True,
                tested=False
            )
            session.add(deployment)
            session.commit()

        worker_payload = {
            'application': 'staging',
            'environment': 'adsws',
            'commit': 'latest-commit',
            'tag': 'latest-tag',
            'deployed': True,
            'tested': True,
        }

        worker = DatabaseWriterWorker()
        worker.process_payload(worker_payload)

        with self.app.session_scope() as session:
            deployment = session.query(Deployment).filter(
                Deployment.application == 'staging',
                Deployment.environment == 'adsws',
                Deployment.commit == 'latest-commit'
            ).one()

            self.assertTrue(deployment.tested)
            self.assertTrue(
                deployment.date_last_modified > deployment.date_created
            )
示例#5
0
    def test_worker_writes_to_database(self):
        """
        Test that the worker writes the relevant data to the database
        """
        worker_payload = {
            "application": "staging",
            "environment": "adsws",
            "version": "latest-commit",
            "deployed": True,
            "tested": False,
        }

        worker = DatabaseWriterWorker()
        worker.process_payload(worker_payload)

        with self.app.session_scope() as session:
            deployment = (
                session.query(Deployment)
                .filter(
                    Deployment.application == "staging",
                    Deployment.environment == "adsws",
                    Deployment.version == "latest-commit",
                )
                .one()
            )

            for key in worker_payload:

                expected_value = worker_payload[key]
                stored_value = getattr(deployment, key)

                self.assertEqual(
                    expected_value,
                    stored_value,
                    msg='Attr "{}", expected value: "{}" != stored value: "{}"'.format(
                        key, expected_value, stored_value
                    ),
                )

            self.assertIsInstance(deployment.date_created, datetime)
            self.assertIsInstance(deployment.date_last_modified, datetime)
示例#6
0
    def test_worker_writes_to_database(self):
        """
        Test that the worker writes the relevant data to the database
        """
        worker_payload = {
            'application': 'staging',
            'environment': 'adsws',
            'commit': 'latest-commit',
            'tag': 'latest-tag',
            'deployed': True,
            'tested': False,
        }

        worker = DatabaseWriterWorker()
        worker.process_payload(worker_payload)

        with self.app.session_scope() as session:
            deployment = session.query(Deployment).filter(
                Deployment.application == 'staging',
                Deployment.environment == 'adsws',
                Deployment.commit == 'latest-commit'
            ).one()

            for key in worker_payload:

                expected_value = worker_payload[key]
                stored_value = getattr(deployment, key)

                self.assertEqual(
                    expected_value,
                    stored_value,
                    msg='Attr "{}", expected value: "{}" != stored value: "{}"'
                        .format(key, expected_value, stored_value)
                )

            self.assertIsInstance(deployment.date_created, datetime)
            self.assertIsInstance(deployment.date_last_modified, datetime)
示例#7
0
    def test_worker_overwrites_entry(self):
        """
        Test that the worker overwrites the relevant data in the database
        """

        # Stub the database entry
        with self.app.session_scope() as session:
            deployment = Deployment(
                application="staging", environment="adsws", version="latest-commit", deployed=True, tested=False
            )
            session.add(deployment)
            session.commit()

        worker_payload = {
            "application": "staging",
            "environment": "adsws",
            "version": "latest-commit",
            "deployed": True,
            "tested": True,
        }

        worker = DatabaseWriterWorker()
        worker.process_payload(worker_payload)

        with self.app.session_scope() as session:
            deployment = (
                session.query(Deployment)
                .filter(
                    Deployment.application == "staging",
                    Deployment.environment == "adsws",
                    Deployment.version == "latest-commit",
                )
                .one()
            )

            self.assertTrue(deployment.tested)
            self.assertTrue(deployment.date_last_modified > deployment.date_created)
示例#8
0
    def test_worker_updates_deployed_status(self):
        """
        When a new service is successful in being deployed, it should update any
        other service with the same env/app combination to not being deployed.
        There is most likely a smarter way to do this....
        """

        first_payload = {
            "application": "staging",
            "environment": "adsws",
            "version": "first-commit",
            "deployed": True,
            "tested": False,
        }
        second_payload = {
            "application": "staging",
            "environment": "adsws",
            "version": "second-commit",
            "deployed": True,
            "tested": False,
        }

        worker = DatabaseWriterWorker()
        worker.process_payload(first_payload)

        with self.app.session_scope() as session:
            deployment = session.query(Deployment).filter(Deployment.version == "first-commit").one()
            self.assertTrue(deployment.deployed)

        worker.process_payload(second_payload)
        with self.app.session_scope() as session:
            deployment_2 = session.query(Deployment).filter(Deployment.version == "second-commit").one()
            self.assertTrue(deployment_2.deployed)

            deployment_1 = session.query(Deployment).filter(Deployment.version == "first-commit").one()
            self.assertFalse(deployment_1.deployed)
示例#9
0
    def test_before_deploy_fails(self, mock_is_timedout):
        """
        Test that the correct database entires are made by BeforeDeploy worker
        when the worker fails on its actions
        """
        # Worker receives a packet, most likely from the webapp
        # Example packet:
        #
        #  {
        #    'application': 'staging',
        #    '....': '....',
        #  }
        #
        #
        packet = {
            'environment': 'staging',
            'application': 'adsws',
            'version': 'v1.0.0',
        }

        # Override the run test returned value. This means the logic of the test
        # does not have to be mocked
        mock_is_timedout.return_value = True

        with MiniRabbit(RABBITMQ_URL) as w:
            w.publish(route='in', exchange='test', payload=json.dumps(packet))

        # Worker runs the tests
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'in',
            'publish': 'ads.deploy.deploy',
            'header_frame': None,
            'error': 'error',
            'status': 'database',
            'TEST_RUN': True
        }
        before_deploy_worker = BeforeDeploy(params=params)
        before_deploy_worker.run()
        before_deploy_worker.connection.close()

        # Worker sends a packet to the next worker
        with MiniRabbit(RABBITMQ_URL) as w:
            self.assertEqual(w.message_count('in'), 0)
            self.assertEqual(w.message_count('ads.deploy.deploy'), 0)
            self.assertEqual(w.message_count('database'), 1)
            self.assertEqual(w.message_count('error'), 1)

        # Start the DB Writer worker
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'database',
            'TEST_RUN': True
        }
        db_worker = DatabaseWriterWorker(params=params)
        db_worker.app = self.app
        db_worker.run()
        db_worker.connection.close()

        with self.app.session_scope() as session:

            all_deployments = session.query(Deployment).all()
            self.assertEqual(
                len(all_deployments),
                1,
                msg='More (or less) than 1 deployment entry: {}'
                    .format(all_deployments)
            )
            deployment = all_deployments[0]

            for key in packet:
                self.assertEqual(
                    packet[key],
                    getattr(deployment, key)
                )
            self.assertEqual(deployment.deployed, False)
            self.assertEqual(
                deployment.msg,
                'BeforeDeploy: waiting too long for the environment to come up'
            )
示例#10
0
    def test_before_deploy_receives_restart(self, mock_executioner):
        """
        Test that the correct database entires are made by BeforeDeploy worker
        when the worker succeeds on its actions
        """
        # Worker receives a packet, most likely from the webapp
        # Example packet:
        #
        #  {
        #    'application': 'staging',
        #    '....': '....',
        #  }a
        #
        #
        packet = {
            'environment': 'staging',
            'application': 'adsws',
            'action': 'restart'
        }

        # Override the run test returned value. This means the logic of the test
        # does not have to be mocked
        mock_r = mock.Mock(retcode=0)
        mock_r.out.splitlines.return_value = []

        mock_x = mock_executioner.return_value
        mock_x.cmd.return_value = mock_r

        with MiniRabbit(RABBITMQ_URL) as w:
            w.publish(route='in', exchange='test', payload=json.dumps(packet))

        # Worker runs the tests
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'in',
            'publish': 'ads.deploy.deploy',
            'header_frame': None,
            'status': 'database',
            'error': 'error',
            'status': 'database',
            'TEST_RUN': True
        }
        before_deploy_worker = BeforeDeploy(params=params)
        before_deploy_worker.run()
        before_deploy_worker.connection.close()

        # Worker sends a packet to the next worker
        with MiniRabbit(RABBITMQ_URL) as w:
            self.assertEqual(w.message_count('in'), 0)
            self.assertEqual(w.message_count('ads.deploy.deploy'), 0)
            self.assertEqual(w.message_count('ads.deploy.restart'), 1)
            self.assertEqual(w.message_count('database'), 1)
            self.assertEqual(w.message_count('error'), 0)

        # Start the DB Writer worker
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'database',
            'TEST_RUN': True
        }
        db_worker = DatabaseWriterWorker(params=params)
        db_worker.app = self.app
        db_worker.run()
        db_worker.connection.close()

        # remove irrelevant keys before checking things
        packet.pop('action')

        # check database entries
        with self.app.session_scope() as session:

            all_deployments = session.query(Deployment).all()
            self.assertEqual(
                len(all_deployments),
                1,
                msg='More (or less) than 1 deployment entry: {}'
                    .format(all_deployments)
            )
            deployment = all_deployments[0]

            for key in packet:
                self.assertEqual(
                    packet[key],
                    getattr(deployment, key)
                )
            self.assertEqual(deployment.deployed, None)
            self.assertEqual(
                deployment.msg,
                'Deploy to be restarted'
            )
    def test_db_writes_on_test_pass(self, mocked_run_test):
        """
        Check that the database is being written to when a test passes
        """
        # Stub data
        packet = {
            'application': 'adsws',
            'environment': 'staging',
            'tag': 'v1.0.0',
            'commit': 'gf9gd8f',
        }
        expected_packet = packet.copy()
        expected_packet['tested'] = True
        mocked_run_test.return_value = expected_packet

        # Start the IntegrationTester worker
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'in',
            'publish': 'out',
            'status': 'database',
            'TEST_RUN': True
        }

        # Push to rabbitmq
        with MiniRabbit(RABBITMQ_URL) as w:
            w.publish(route='in', exchange='test', payload=json.dumps(packet))

        test_worker = IntegrationTestWorker(params=params)
        test_worker.run()
        test_worker.connection.close()

        # Assert there is a packet on the publish queue
        with MiniRabbit(RABBITMQ_URL) as w:
            self.assertEqual(w.message_count('out'), 1)
            self.assertEqual(w.message_count('database'), 1)

        # Start the DB Writer worker
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'database',
            'TEST_RUN': True
        }
        db_worker = DatabaseWriterWorker(params=params)
        db_worker.app = self.app
        db_worker.run()
        db_worker.connection.close()

        with self.app.session_scope() as session:

            all_deployments = session.query(Deployment).all()
            self.assertEqual(
                len(all_deployments),
                1,
                msg='More (or less) than 1 deployment entry: {}'
                    .format(all_deployments)
            )
            deployment = all_deployments[0]

            for key in packet:
                self.assertEqual(
                    packet[key],
                    getattr(deployment, key)
                )
            self.assertEqual(deployment.tested, True)
示例#12
0
    def test_before_deploy_fails(self, mock_is_timedout):
        """
        Test that the correct database entires are made by BeforeDeploy worker
        when the worker fails on its actions
        """
        # Worker receives a packet, most likely from the webapp
        # Example packet:
        #
        #  {
        #    'application': 'staging',
        #    '....': '....',
        #  }
        #
        #
        packet = {"environment": "staging", "application": "adsws", "tag": "v1.0.0", "commit": "gf9gd8f"}

        # Override the run test returned value. This means the logic of the test
        # does not have to be mocked
        mock_is_timedout.return_value = True

        with MiniRabbit(RABBITMQ_URL) as w:
            w.publish(route="in", exchange="test", payload=json.dumps(packet))

        # Worker runs the tests
        params = {
            "RABBITMQ_URL": RABBITMQ_URL,
            "exchange": "test",
            "subscribe": "in",
            "publish": "ads.deploy.deploy",
            "header_frame": None,
            "error": "error",
            "status": "database",
            "TEST_RUN": True,
        }
        before_deploy_worker = BeforeDeploy(params=params)
        before_deploy_worker.run()
        before_deploy_worker.connection.close()

        # Worker sends a packet to the next worker
        with MiniRabbit(RABBITMQ_URL) as w:
            self.assertEqual(w.message_count("in"), 0)
            self.assertEqual(w.message_count("ads.deploy.deploy"), 0)
            self.assertEqual(w.message_count("database"), 1)
            self.assertEqual(w.message_count("error"), 1)

        # Start the DB Writer worker
        params = {"RABBITMQ_URL": RABBITMQ_URL, "exchange": "test", "subscribe": "database", "TEST_RUN": True}
        db_worker = DatabaseWriterWorker(params=params)
        db_worker.app = self.app
        db_worker.run()
        db_worker.connection.close()

        with self.app.session_scope() as session:

            all_deployments = session.query(Deployment).all()
            self.assertEqual(
                len(all_deployments), 1, msg="More (or less) than 1 deployment entry: {}".format(all_deployments)
            )
            deployment = all_deployments[0]

            for key in packet:
                self.assertEqual(packet[key], getattr(deployment, key))
            self.assertEqual(deployment.deployed, False)
            self.assertEqual(deployment.msg, "BeforeDeploy: waiting too long for the environment to come up")
示例#13
0
    def test_before_deploy_receives_restart(self, mock_executioner):
        """
        Test that the correct database entires are made by BeforeDeploy worker
        when the worker succeeds on its actions
        """
        # Worker receives a packet, most likely from the webapp
        # Example packet:
        #
        #  {
        #    'application': 'staging',
        #    '....': '....',
        #  }a
        #
        #
        packet = {
            "environment": "staging",
            "application": "adsws",
            "tag": "v1.0.0",
            "commit": "gf9gd8f",
            "action": "restart",
        }

        # Override the run test returned value. This means the logic of the test
        # does not have to be mocked
        mock_r = mock.Mock(retcode=0)
        mock_r.out.splitlines.return_value = []

        mock_x = mock_executioner.return_value
        mock_x.cmd.return_value = mock_r

        with MiniRabbit(RABBITMQ_URL) as w:
            w.publish(route="in", exchange="test", payload=json.dumps(packet))

        # Worker runs the tests
        params = {
            "RABBITMQ_URL": RABBITMQ_URL,
            "exchange": "test",
            "subscribe": "in",
            "publish": "ads.deploy.deploy",
            "header_frame": None,
            "status": "database",
            "error": "error",
            "status": "database",
            "TEST_RUN": True,
        }
        before_deploy_worker = BeforeDeploy(params=params)
        before_deploy_worker.run()
        before_deploy_worker.connection.close()

        # Worker sends a packet to the next worker
        with MiniRabbit(RABBITMQ_URL) as w:
            self.assertEqual(w.message_count("in"), 0)
            self.assertEqual(w.message_count("ads.deploy.deploy"), 0)
            self.assertEqual(w.message_count("ads.deploy.restart"), 1)
            self.assertEqual(w.message_count("database"), 1)
            self.assertEqual(w.message_count("error"), 0)

        # Start the DB Writer worker
        params = {"RABBITMQ_URL": RABBITMQ_URL, "exchange": "test", "subscribe": "database", "TEST_RUN": True}
        db_worker = DatabaseWriterWorker(params=params)
        db_worker.app = self.app
        db_worker.run()
        db_worker.connection.close()

        # remove irrelevant keys before checking things
        packet.pop("action")

        # check database entries
        with self.app.session_scope() as session:

            all_deployments = session.query(Deployment).all()
            self.assertEqual(
                len(all_deployments), 1, msg="More (or less) than 1 deployment entry: {}".format(all_deployments)
            )
            deployment = all_deployments[0]

            for key in packet:
                self.assertEqual(packet[key], getattr(deployment, key))
            self.assertEqual(deployment.deployed, None)
            self.assertEqual(deployment.msg, "Deploy to be restarted")
示例#14
0
    def test_restart_fails(self, mock_executioner):
        """
        Test that when a restart is requested, and the restart worker fails,
        the messages are updated
        """
        # Worker receives a packet, most likely from the webapp
        # Example packet:
        #
        #  {
        #    'application': 'staging',
        #    '....': '....',
        #  }
        #
        #
        packet = {
            'environment': 'staging',
            'application': 'adsws',
            'tag': 'v1.0.0',
            'commit': 'gf9gd8f',
        }

        # Override the run test returned value. This means the logic of the test
        # does not have to be mocked. retcode = 1 means it has failed
        mock_r = mock.MagicMock(retcode=1)
        mock_r.__str__.return_value = 'restart failed'

        mock_x = mock_executioner.return_value
        mock_x.cmd.return_value = mock_r

        with MiniRabbit(RABBITMQ_URL) as w:
            w.publish(route='in', exchange='test', payload=json.dumps(packet))

        # Worker runs the tests
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'in',
            'publish': 'out',
            'header_frame': None,
            'error': 'error',
            'status': 'database',
            'TEST_RUN': True
        }
        restart_worker = Restart(params=params)
        restart_worker.run()
        restart_worker.connection.close()

        # Worker sends a packet to the next worker
        with MiniRabbit(RABBITMQ_URL) as w:
            self.assertEqual(w.message_count('in'), 0)
            self.assertEqual(w.message_count('out'), 0)
            self.assertEqual(w.message_count('database'), 2)
            self.assertEqual(w.message_count('error'), 1)

        # Start the DB Writer worker
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'database',
            'TEST_RUN': True
        }

        # First message should be starting of the deployment
        db_worker = DatabaseWriterWorker(params=params)
        db_worker.app = self.app
        db_worker.run()
        with self.app.session_scope() as session:
            deployment = session.query(Deployment)\
                .filter(Deployment.commit == 'gf9gd8f').one()
            self.assertEqual(
                deployment.msg,
                'staging-adsws restart-soft starts'
            )
            self.assertIsNone(deployment.deployed)

        db_worker.run()
        with self.app.session_scope() as session:
            deployment = session.query(Deployment)\
                .filter(Deployment.commit == 'gf9gd8f').one()

            for key in packet:
                self.assertEqual(
                    packet[key],
                    getattr(deployment, key)
                )
            self.assertFalse(deployment.deployed)
            self.assertEqual(
                deployment.msg,
                'restart failed'
            )
示例#15
0
    def test_deploy_fails(self, mock_executioner):
        """
        Test that when the deploy fails the correct entries are sent and stored
        in the backend database
        """
        # Worker receives a packet, most likely from the webapp
        # Example packet:
        #
        #  {
        #    'application': 'staging',
        #    'environment': 'adsws',
        #    'version': 'v1.0.3'
        #  }
        #
        #
        packet = {
            'environment': 'adsws',
            'application': 'staging',
            'version': 'v1.0.0'
        }

        # Stub the database with some early entries
        first_deployment = Deployment(
            environment=packet['environment'],
            application=packet['application'],
            version='v0.0.1',
            deployed=True
        )
        with self.app.session_scope() as session:
            session.add(first_deployment)
            session.commit()

        # Override the run test returned value. This means the logic of the test
        # does not have to be mocked. retcode = 1 means it has failed
        mock_r = mock.Mock(retcode=1, command='r-command', err='r-err',
                           out='r-out')

        mock_x = mock_executioner.return_value
        mock_x.cmd.return_value = mock_r

        with MiniRabbit(RABBITMQ_URL) as w:
            w.publish(route='in', exchange='test', payload=json.dumps(packet))

        # Worker runs the tests
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'in',
            'publish': 'out',
            'header_frame': None,
            'error': 'error',
            'status': 'database',
            'TEST_RUN': True
        }
        deploy_worker = Deploy(params=params)
        deploy_worker.run()
        deploy_worker.connection.close()

        # Worker sends a packet to the next worker
        with MiniRabbit(RABBITMQ_URL) as w:
            self.assertEqual(w.message_count('in'), 0)
            self.assertEqual(w.message_count('out'), 0)
            self.assertEqual(w.message_count('database'), 2)
            self.assertEqual(w.message_count('error'), 1)

        # Start the DB Writer worker
        params = {
            'RABBITMQ_URL': RABBITMQ_URL,
            'exchange': 'test',
            'subscribe': 'database',
            'TEST_RUN': True
        }

        # First message should be starting of the deployment
        db_worker = DatabaseWriterWorker(params=params)
        db_worker.app = self.app
        db_worker.run()
        with self.app.session_scope() as session:
            deployment = session.query(Deployment)\
                .filter(Deployment.version == 'v1.0.0').one()
            self.assertEqual(
                deployment.msg,
                'staging-adsws deployment starts'
            )
            self.assertIsNone(deployment.deployed)

            deployment = session.query(Deployment)\
                .filter(Deployment.version == 'v0.0.1').one()
            self.assertTrue(deployment.deployed)

        db_worker.run()
        with self.app.session_scope() as session:
            deployment = session.query(Deployment)\
                .filter(Deployment.version == 'v1.0.0').one()

            for key in packet:
                self.assertEqual(
                    packet[key],
                    getattr(deployment, key)
                )
            self.assertFalse(deployment.deployed)
            self.assertEqual(
                deployment.msg,
                'deployment failed; command: r-command, reason: r-err, stdout: r-out'
            )

            deployment = session.query(Deployment)\
                .filter(Deployment.version == 'v0.0.1').one()

            self.assertTrue(deployment.deployed)