def patch_collection_instrument(instrument_id):
    file = request.files["file"]
    if file.filename == "":
        raise RasError("Missing filename", 400)

    CollectionInstrument().patch_seft_instrument(instrument_id, file)

    return make_response(PATCH_SUCCESSFUL, 200)
def collection_instrument_by_id(instrument_id):
    # The /collectioninstrument/id/<id> endpoint needs to be removed once things that call it are replaced by
    # the simpler /<id> call above it
    instrument_json = CollectionInstrument().get_instrument_json(instrument_id)

    if instrument_json:
        return make_response(jsonify(instrument_json), 200)

    return make_response(COLLECTION_INSTRUMENT_NOT_FOUND, 404)
def link_collection_instrument(instrument_id, exercise_id):
    CollectionInstrument().link_instrument_to_exercise(instrument_id,
                                                       exercise_id)
    response = publish_uploaded_collection_instrument(exercise_id,
                                                      instrument_id)
    if response.status_code != 200:
        log.error("Failed to publish upload message",
                  instrument_id=instrument_id,
                  collection_exercise_id=exercise_id)
        raise RasError("Failed to publish upload message", 500)
    return make_response(LINK_SUCCESSFUL, 200)
    def test_patch_seft_instrument_instrument_not_found(self, get_instrument):
        get_instrument.return_value = None
        session = MagicMock()
        instrument = CollectionInstrument()

        with self.assertRaises(RasError) as error:
            instrument.patch_seft_instrument.__wrapped__(instrument, self.instrument_id, self.file, session)

        expected = ["Instrument not found"]
        expected_status = 400
        self.assertEqual(expected, error.exception.errors)
        self.assertEqual(expected_status, error.exception.status_code)
    def test_patch_seft_instrument_invalid_uuid(self):
        test_input = "not-a-uuid"
        session = MagicMock()
        instrument = CollectionInstrument()

        with self.assertRaises(RasError) as error:
            instrument.patch_seft_instrument.__wrapped__(instrument, test_input, self.file, session)

        expected = [f"Value is not a valid UUID ({test_input})"]
        expected_status = 400
        self.assertEqual(expected, error.exception.errors)
        self.assertEqual(expected_status, error.exception.status_code)
def download_csv(exercise_id):
    csv = CollectionInstrument().get_instruments_by_exercise_id_csv(
        exercise_id)

    if csv:
        response = make_response(csv, 200)
        response.headers[
            "Content-Disposition"] = "attachment; filename=instruments_for_{exercise_id}.csv".format(
                exercise_id=exercise_id)
        response.headers["Content-type"] = "text/csv"
        return response

    return make_response(NO_INSTRUMENT_FOR_EXERCISE, 404)
def instrument_data(instrument_id):
    data, file_name = CollectionInstrument().get_instrument_data(instrument_id)

    if data and file_name:
        response = make_response(data, 200)
        response.headers[
            "Content-Disposition"] = "attachment; filename={}".format(
                file_name)
        response.headers[
            "Content-type"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    else:
        response = make_response(COLLECTION_INSTRUMENT_NOT_FOUND, 404)

    return response
    def test_patch_seft_instrument_instrument_not_seft(self, get_instrument):
        instrument_model = InstrumentModel()
        instrument_model.type = "EQ"
        get_instrument.return_value = instrument_model
        session = MagicMock()
        instrument = CollectionInstrument()

        with self.assertRaises(RasError) as error:
            instrument.patch_seft_instrument.__wrapped__(instrument, self.instrument_id, self.file, session)

        expected = ["Not a SEFT instrument"]
        expected_status = 400
        self.assertEqual(expected, error.exception.errors)
        self.assertEqual(expected_status, error.exception.status_code)
def upload_collection_instrument(exercise_id, ru_ref=None):
    file = request.files["file"]
    classifiers = request.args.get("classifiers")
    instrument = CollectionInstrument().upload_to_bucket(
        exercise_id, file, ru_ref=ru_ref, classifiers=classifiers)

    if not publish_uploaded_collection_instrument(exercise_id,
                                                  instrument.instrument_id):
        log.error(
            "Failed to publish upload message",
            instrument_id=instrument.instrument_id,
            collection_exercise_id=exercise_id,
            ru_ref=ru_ref,
        )
        raise RasError("Failed to publish upload message", 500)
    return make_response(UPLOAD_SUCCESSFUL, 200)
 def setUp(self):
     self.collection_instrument = CollectionInstrument()
     self.instrument_id = self.add_instrument_data()
class TestCollectionInstrument(TestClient):
    """ Collection Instrument unit tests"""
    def setUp(self):
        self.collection_instrument = CollectionInstrument()
        self.instrument_id = self.add_instrument_data()

    def test_get_instrument_by_search_string_collection_exercise_id(self):

        # Given there is an instrument in the db
        # When a collection exercise id is used to find that instrument
        instrument = self.collection_instrument.get_instrument_by_search_string(
            '{\"COLLECTION_EXERCISE\": \"db0711c3-0ac8-41d3-ae0e-567e5ea1ef87\"}'
        )

        # Then that instrument is returned
        self.assertIn(str(self.instrument_id), json.dumps(str(instrument)))

    def test_get_instrument_by_search_string_survey_id(self):
        # Given there is an instrument in the db
        # When the survey id is used to find that instrument
        instrument = self.collection_instrument.get_instrument_by_search_string(
            '{\"SURVEY_ID\": \"cb0711c3-0ac8-41d3-ae0e-567e5ea1ef87\"}')

        # Then that instrument is returned
        self.assertIn(str(self.instrument_id), json.dumps(str(instrument)))

    def test_get_instrument_by_search_string_type(self):
        # Given there is an instrument in the db
        # When the type is used to find that instrument
        instrument = self.collection_instrument.get_instrument_by_search_string(
            '{\"TYPE\": \"SEFT\"}')

        # Then that instrument is returned
        self.assertIn(str(self.instrument_id), json.dumps(str(instrument)))

    def test_get_instrument_by_search_string_empty_search(self):

        # Given there is an instrument in the db
        # When an empty search string is used
        instrument = self.collection_instrument.get_instrument_by_search_string(
        )

        # Then that instrument is returned
        self.assertIn(str(self.instrument_id), json.dumps(str(instrument)))

    def test_get_instrument_by_search_string_invalid_search_value(self):

        # Given that a valid classifier is used but with an invalid value (should be uuid)
        # When the function is called
        # Than a RasDatabaseError is raised
        with self.assertRaises(RasDatabaseError):
            self.collection_instrument.get_instrument_by_search_string(
                '{\"COLLECTION_EXERCISE\": \"invalid_uuid\"}')

    def test_get_instrument_by_incorrect_id(self):

        # Given there is an instrument in the db
        # When an incorrect instrument id is used to find that instrument
        instrument = self.collection_instrument.get_instrument_json(
            'db0711c3-0ac8-41d3-ae0e-567e5ea1ef87')

        # Then that instrument is not found
        self.assertEqual(instrument, None)

    def test_initialise_messaging(self):
        with patch('pika.BlockingConnection'):
            self.collection_instrument.initialise_messaging()

    def test_initialise_messaging_rabbit_fails(self):
        with self.assertRaises(AMQPConnectionError):
            with patch('pika.BlockingConnection',
                       side_effect=AMQPConnectionError):
                self.collection_instrument.initialise_messaging()

    def test_publish_uploaded_collection_instrument(self):

        # Given there is an instrument in the db
        # When publishing to a rabbit exchange that a collection instrument has been uploaded
        c_id = 'db0711c3-0ac8-41d3-ae0e-567e5ea1ef87'
        with patch('pika.BlockingConnection'):
            result = publish_uploaded_collection_instrument(
                c_id, self.instrument_id)

        # Then the message is successfully published
        self.assertTrue(result)

    def test_publish_uploaded_collection_instrument_rabbit_fails(self):

        # Given there is an instrument in the db
        # When publishing to a rabbit exchange that a collection instrument has been uploaded
        c_id = 'db0711c3-0ac8-41d3-ae0e-567e5ea1ef87'

        with patch(
                'application.controllers.rabbit_helper.DurableExchangePublisher.publish_message',
                side_effect=PublishMessageError):
            result = publish_uploaded_collection_instrument(
                c_id, self.instrument_id)

        # Then the message is not successfully published
        self.assertFalse(result)

    @staticmethod
    @with_db_session
    def add_instrument_data(session=None):
        instrument = InstrumentModel(ci_type='SEFT')
        seft_file = SEFTModel(instrument_id=instrument.instrument_id,
                              file_name='test_file')
        exercise = ExerciseModel(
            exercise_id='db0711c3-0ac8-41d3-ae0e-567e5ea1ef87')
        business = BusinessModel(ru_ref='test_ru_ref')
        instrument.seft_file = seft_file
        instrument.exercises.append(exercise)
        instrument.businesses.append(business)
        survey = SurveyModel(survey_id='cb0711c3-0ac8-41d3-ae0e-567e5ea1ef87')
        instrument.survey = survey
        session.add(instrument)
        return instrument.instrument_id
def unlink_collection_instrument(instrument_id, exercise_id):
    CollectionInstrument().unlink_instrument_from_exercise(
        instrument_id, exercise_id)
    return make_response(UNLINK_SUCCESSFUL, 200)
def upload_collection_instrument_without_collection_exercise():
    classifiers = request.args.get("classifiers")
    survey_id = request.args.get("survey_id")
    CollectionInstrument().upload_instrument_with_no_collection_exercise(
        survey_id, classifiers=classifiers)
    return make_response(UPLOAD_SUCCESSFUL, 200)
def count_collection_instruments_by_search_string():
    search_string = request.args.get("searchString")
    instruments = CollectionInstrument().get_instrument_by_search_string(
        search_string)
    return make_response(str(len(instruments)), 200)
def collection_instrument_by_search_string():
    search_string = request.args.get("searchString")
    limit = request.args.get("limit")
    instruments = CollectionInstrument().get_instrument_by_search_string(
        search_string, limit)
    return make_response(jsonify(instruments), 200)
class TestCollectionInstrument(TestClient):
    """Collection Instrument unit tests"""

    def setUp(self):
        self.collection_instrument = CollectionInstrument()
        self.instrument_id = self.add_instrument_data()

    def test_get_instrument_by_search_string_collection_exercise_id(self):
        # Given there is an instrument in the db
        # When a collection exercise id is used to find that instrument
        instrument = self.collection_instrument.get_instrument_by_search_string(
            '{"COLLECTION_EXERCISE": "db0711c3-0ac8-41d3-ae0e-567e5ea1ef87"}'
        )

        # Then that instrument is returned
        self.assertIn(str(self.instrument_id), json.dumps(str(instrument)))

    def test_get_instrument_by_search_string_survey_id(self):
        # Given there is an instrument in the db
        # When the survey id is used to find that instrument
        instrument = self.collection_instrument.get_instrument_by_search_string(
            '{"SURVEY_ID": "cb0711c3-0ac8-41d3-ae0e-567e5ea1ef87"}'
        )

        # Then that instrument is returned
        self.assertIn(str(self.instrument_id), json.dumps(str(instrument)))

    def test_get_instrument_by_search_string_type(self):
        # Given there is an instrument in the db
        # When the type is used to find that instrument
        instrument = self.collection_instrument.get_instrument_by_search_string('{"TYPE": "SEFT"}')

        # Then that instrument is returned
        self.assertIn(str(self.instrument_id), json.dumps(str(instrument)))

    def test_get_instrument_by_search_string_empty_search(self):
        # Given there is an instrument in the db
        # When an empty search string is used
        instrument = self.collection_instrument.get_instrument_by_search_string()

        # Then that instrument is returned
        self.assertIn(str(self.instrument_id), json.dumps(str(instrument)))

    def test_get_instrument_by_search_string_invalid_search_value(self):
        # Given that a valid classifier is used but with an invalid value (should be uuid)
        # When the function is called
        # Than a RasDatabaseError is raised
        with self.assertRaises(RasDatabaseError):
            self.collection_instrument.get_instrument_by_search_string('{"COLLECTION_EXERCISE": "invalid_uuid"}')

    def test_get_instrument_by_incorrect_id(self):
        # Given there is an instrument in the db
        # When an incorrect instrument id is used to find that instrument
        instrument = self.collection_instrument.get_instrument_json("db0711c3-0ac8-41d3-ae0e-567e5ea1ef87")

        # Then that instrument is not found
        self.assertEqual(instrument, None)

    @requests_mock.mock()
    def test_publish_uploaded_collection_instrument(self, mock_request):
        mock_request.post(url_collection_instrument_link_url, status_code=200)
        # Given there is an instrument in the db
        c_id = "db0711c3-0ac8-41d3-ae0e-567e5ea1ef87"
        result = publish_uploaded_collection_instrument(c_id, self.instrument_id)

        # Then the message is successfully published
        self.assertEqual(result.status_code, 200)

    @requests_mock.mock()
    def test_publish_uploaded_collection_instrument_fails(self, mock_request):
        mock_request.post(url_collection_instrument_link_url, status_code=500)
        # Given there is an instrument in the db
        c_id = "db0711c3-0ac8-41d3-ae0e-567e5ea1ef87"
        with self.assertRaises(Exception):
            publish_uploaded_collection_instrument(c_id, self.instrument_id)

    @staticmethod
    @with_db_session
    def add_instrument_data(session=None):
        instrument = InstrumentModel(ci_type="SEFT")
        seft_file = SEFTModel(instrument_id=instrument.instrument_id, file_name="test_file")
        exercise = ExerciseModel(exercise_id="db0711c3-0ac8-41d3-ae0e-567e5ea1ef87")
        business = BusinessModel(ru_ref="test_ru_ref")
        instrument.seft_file = seft_file
        instrument.exercises.append(exercise)
        instrument.businesses.append(business)
        survey = SurveyModel(survey_id="cb0711c3-0ac8-41d3-ae0e-567e5ea1ef87")
        instrument.survey = survey
        session.add(instrument)
        return instrument.instrument_id