Пример #1
0
    def test_sample_composition_update(self):
        tester = SampleComposition(85)

        # Make sure that the sample composition that we are working with
        # is a control sample
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)

        # Update a well from CONTROL -> EXPERIMENTAL SAMPLE
        tester.update('1.SKM8.640201')
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertEqual(tester.sample_id, '1.SKM8.640201')

        # Update a well from EXPERIMENTAL SAMPLE -> EXPERIMENTAL SAMPLE
        tester.update('1.SKB6.640176')
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertEqual(tester.sample_id, '1.SKB6.640176')

        # Update a well from EXPERIMENTAL SAMPLE -> CONTROL
        tester.update('vibrio positive control')
        self.assertEqual(tester.sample_composition_type,
                         'vibrio positive control')
        self.assertIsNone(tester.sample_id)

        # Update a well from CONROL -> CONTROL
        tester.update('blank')
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
Пример #2
0
 def test_create_control_sample_type(self):
     SampleComposition.create_control_sample_type('testing.control',
                                                  'A test')
     obs = SampleComposition.get_control_sample_types_description()
     exp = [{
         'external_id':
         'blank',
         'description':
         'gDNA extraction blanks. Represents an empty '
         'extraction well.'
     }, {
         'external_id':
         'empty',
         'description':
         'Empty well. Represents an empty well that should '
         'not be included in library preparation.'
     }, {
         'external_id': 'testing.control',
         'description': 'A test'
     }, {
         'external_id':
         'vibrio.positive.control',
         'description':
         'Bacterial isolate control (Vibrio fischeri ES114)'
         '. Represents an extraction well loaded with '
         'Vibrio.'
     }, {
         'external_id':
         'zymo.mock',
         'description':
         'Bacterial community control (Zymo Mock D6306). '
         'Represents an extraction well loaded with Zymo '
         'Mock community.'
     }]
     self.assertEqual(obs, exp)
Пример #3
0
 def test_sample_composition_get_sample_composition_type_id(self):
     self.assertEqual(
         SampleComposition._get_sample_composition_type_id(
             'experimental sample'), 1)
     self.assertEqual(
         SampleComposition._get_sample_composition_type_id('blank'), 2)
     self.assertEqual(
         SampleComposition._get_sample_composition_type_id(
             'vibrio.positive.control'), 3)
Пример #4
0
 def test_patch_sample_plating_process_handler(self):
     obs = SampleComposition(85)
     data = {'op': 'replace', 'path': '/well/8/1/',
             'value': '1.SKM8.640201'}
     response = self.patch('/process/sample_plating/10', data)
     self.assertEqual(response.code, 200)
     self.assertEqual(obs.sample_id, '1.SKM8.640201')
    def test_patch_sample_plating_process_handler_with_specimen_id(self):
        # HACK: the Study object in labman can't modify specimen_id_column
        # hence we do this directly in SQL, if a test fails the transaction
        # will rollback, otherwise we reset the column to NULL.
        sql = """UPDATE qiita.study
                 SET specimen_id_column = %s
                 WHERE study_id = 1"""
        with sql_connection.TRN as TRN:
            TRN.add(sql, ['anonymized_name'])

            obs = SampleComposition(8)
            data = {
                'op': 'replace',
                'path': '/well/8/1/1/sample',
                'value': 'SKM8'
            }
            response = self.patch('/process/sample_plating/11', data)
            self.assertEqual(response.code, 200)
            self.assertEqual(obs.sample_id, '1.SKM8.640201')
            self.assertEqual(obs.specimen_id, 'SKM8')
            self.assertEqual(json_decode(response.body), {
                'sample_id': 'SKM8',
                'previous_plates': [],
                'sample_ok': True
            })

            TRN.add(sql, [None])
Пример #6
0
 def test_gDNA_composition_attributes(self):
     obs = GDNAComposition(1)
     self.assertEqual(obs.sample_composition, SampleComposition(1))
     self.assertEqual(obs.upstream_process, GDNAExtractionProcess(1))
     self.assertEqual(obs.container, Well(3074))
     self.assertEqual(obs.total_volume, 10)
     self.assertIsNone(obs.notes)
     self.assertEqual(obs.composition_id, 3082)
Пример #7
0
 def test_properties(self):
     tester = Well(3073)
     self.assertEqual(tester.plate, Plate(21))
     self.assertEqual(tester.row, 1)
     self.assertEqual(tester.column, 1)
     self.assertEqual(tester.remaining_volume, 10)
     self.assertIsNone(tester.notes)
     self.assertEqual(tester.latest_process, SamplePlatingProcess(11))
     self.assertEqual(tester.container_id, 3082)
     self.assertEqual(tester.composition, SampleComposition(1))
Пример #8
0
 def test_patch_sample_plating_process_handler(self):
     obs = SampleComposition(8)
     data = {'op': 'replace', 'path': '/well/8/1/sample',
             'value': '1.SKM8.640201'}
     response = self.patch('/process/sample_plating/10', data)
     self.assertEqual(response.code, 200)
     self.assertEqual(obs.sample_id, '1.SKM8.640201')
     self.assertEqual(json_decode(response.body),
                      {'sample_id': '1.SKM8.640201',
                       'previous_plates': [],
                       'sample_ok': True})
Пример #9
0
    def test_sample_composition_attributes(self):
        # Test a sample
        obs = SampleComposition(1)
        self.assertEqual(obs.sample_composition_type, 'experimental sample')
        self.assertEqual(obs.sample_id, '1.SKB1.640202')
        self.assertEqual(obs.content, '1.SKB1.640202')
        self.assertEqual(obs.upstream_process, SamplePlatingProcess(10))
        self.assertEqual(obs.container, Well(3073))
        self.assertEqual(obs.total_volume, 10)
        self.assertIsNone(obs.notes)
        obs.notes = 'New Notes'
        self.assertEqual(obs.notes, 'New Notes')
        obs.notes = None
        self.assertIsNone(obs.notes)
        self.assertEqual(obs.composition_id, 3081)
        self.assertEqual(obs.study, Study(1))

        # Test a control sample
        obs = SampleComposition(85)
        self.assertEqual(obs.sample_composition_type, 'blank')
        self.assertIsNone(obs.sample_id)
        self.assertEqual(obs.content, 'blank.21.H1')
        self.assertEqual(obs.upstream_process, SamplePlatingProcess(10))
        self.assertEqual(obs.container, Well(4333))
        self.assertEqual(obs.total_volume, 10)
        self.assertIsNone(obs.notes)
        self.assertEqual(obs.composition_id, 4341)
        self.assertIsNone(obs.study)
Пример #10
0
 def test_composition_factory(self):
     self.assertEqual(Composition.factory(3073), ReagentComposition(1))
     self.assertEqual(Composition.factory(1537), PrimerComposition(1))
     self.assertEqual(Composition.factory(1), PrimerSetComposition(1))
     self.assertEqual(Composition.factory(3081), SampleComposition(1))
     self.assertEqual(Composition.factory(3082), GDNAComposition(1))
     self.assertEqual(Composition.factory(3083),
                      LibraryPrep16SComposition(1))
     self.assertEqual(Composition.factory(3085),
                      NormalizedGDNAComposition(1))
     self.assertEqual(Composition.factory(3086),
                      LibraryPrepShotgunComposition(1))
     self.assertEqual(Composition.factory(3078), PoolComposition(1))
Пример #11
0
    def test_sample_plating_process_handler_patch_request(self):
        user = User('*****@*****.**')
        # Test operation not supported
        regex = ('Operation add not supported. Current supported '
                 'operations: replace')
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'add', '/well/8/1/', '1.SKM8.640201', None)

        # Test incorrect path parameter
        regex = 'Incorrect path parameter'
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/8/1/', '1.SKM8.640201', None)
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/content', '1.SKM8.640201',
                None)

        # Test attribute not found
        regex = 'Attribute content not found'
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/content/8/1/', '1.SKM8.640201', None)

        # Test missing req_value
        regex = 'A new value for the well should be provided'
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/', None, None)
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/', '', None)
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/', '  ', None)

        # Test success
        obs = SampleComposition(85)
        self.assertEqual(obs.sample_composition_type, 'blank')
        self.assertIsNone(obs.sample_id)

        sample_plating_process_handler_patch_request(
            user, 10, 'replace', '/well/8/1/', '1.SKM8.640201', None)
        self.assertEqual(obs.sample_composition_type, 'experimental sample')
        self.assertEqual(obs.sample_id, '1.SKM8.640201')

        sample_plating_process_handler_patch_request(
            user, 10, 'replace', '/well/8/1/', 'blank', None)
        self.assertEqual(obs.sample_composition_type, 'blank')
        self.assertIsNone(obs.sample_id)
Пример #12
0
    def test_patch_without_specimen_id(self):
        # Test success
        tester = SampleComposition(8)
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'blank.Test.plate.1.H1')

        obs = sample_plating_process_handler_patch_request(
            self.user, 11, 'replace', '/well/8/1/1/sample', '1.SKM8.640201',
            None)
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertEqual(tester.sample_id, '1.SKM8.640201')
        self.assertEqual(tester.content, '1.SKM8.640201')
        self.assertEqual(obs, {
            'sample_id': '1.SKM8.640201',
            'previous_plates': [],
            'sample_ok': True
        })

        obs = sample_plating_process_handler_patch_request(
            self.user, 11, 'replace', '/well/8/1/1/sample', 'Unknown', None)
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'Unknown')
        self.assertEqual(obs, {
            'sample_id': 'Unknown',
            'previous_plates': [],
            'sample_ok': False
        })

        obs = sample_plating_process_handler_patch_request(
            self.user, 11, 'replace', '/well/8/1/1/sample', 'blank', None)
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'blank.Test.plate.1.H1')
        self.assertEqual(
            obs, {
                'sample_id': 'blank.Test.plate.1.H1',
                'previous_plates': [],
                'sample_ok': True
            })

        # Test commenting a well
        self.assertIsNone(tester.notes)
        obs = sample_plating_process_handler_patch_request(
            self.user, 11, 'replace', '/well/8/1/1/notes', 'New Notes', None)
        self.assertEqual(tester.notes, 'New Notes')
        obs = sample_plating_process_handler_patch_request(
            self.user, 11, 'replace', '/well/8/1/1/notes', '  ', None)
        self.assertIsNone(tester.notes)
Пример #13
0
    def test_sample_composition_specimen_id(self):
        obs = SampleComposition(1).specimen_id
        # returns the underlying id if no specimen_id_column is set
        self.assertEqual(obs, '1.SKB1.640202')
        # same should be true for blanks
        obs = SampleComposition(8).specimen_id
        self.assertEqual(obs, 'blank.Test.plate.1.H1')

        # HACK: the Study object in labman can't modify specimen_id_column
        # hence we do this directly in SQL, if a test fails the transaction
        # will rollback, otherwise we reset the column to NULL.
        sql = """UPDATE qiita.study
                 SET specimen_id_column = %s
                 WHERE study_id = 1"""
        with sql_connection.TRN as TRN:
            TRN.add(sql, ['anonymized_name'])

            obs = SampleComposition(1).specimen_id
            self.assertEqual(obs, 'SKB1')

            obs = SampleComposition(8).specimen_id
            self.assertEqual(obs, 'blank.Test.plate.1.H1')

            TRN.add(sql, [None])
Пример #14
0
 def test_sample_composition_get_control_samples(self):
     self.assertEqual(SampleComposition.get_control_samples(),
                      ['blank', 'vibrio.positive.control'])
     self.assertEqual(SampleComposition.get_control_samples('l'),
                      ['blank', 'vibrio.positive.control'])
     self.assertEqual(SampleComposition.get_control_samples('bla'),
                      ['blank'])
     self.assertEqual(SampleComposition.get_control_samples('posit'),
                      ['vibrio.positive.control'])
     self.assertEqual(SampleComposition.get_control_samples('vib'),
                      ['vibrio.positive.control'])
     self.assertEqual(SampleComposition.get_control_samples('TrOL'),
                      ['vibrio.positive.control'])
Пример #15
0
def plate_map_handler_get_request(process_id):
    plate_id = None
    if process_id is not None:
        try:
            process = SamplePlatingProcess(process_id)
        except LabmanUnknownIdError:
            raise HTTPError(404,
                            reason="Plating process %s doesn't exist" %
                            process_id)
        plate_id = process.plate.id

    plate_confs = [[pc.id, pc.description, pc.num_rows, pc.num_columns]
                   for pc in PlateConfiguration.iter()
                   if 'template' not in pc.description]
    cdesc = SampleComposition.get_control_sample_types_description()
    return {
        'plate_confs': plate_confs,
        'plate_id': plate_id,
        'process_id': process_id,
        'controls_description': cdesc
    }
Пример #16
0
 def test_post_manage_controls_handler(self):
     response = self.post('/sample/manage_controls', {
         'external_id': 'zzTestControl',
         'description': 'A test control'
     })
     self.assertEqual(response.code, 200)
     obs = SampleComposition.get_control_sample_types_description()
     exp = [{
         'external_id':
         'blank',
         'description':
         'gDNA extraction blanks. Represents an empty '
         'extraction well.'
     }, {
         'external_id':
         'empty',
         'description':
         'Empty well. Represents an empty well that should '
         'not be included in library preparation.'
     }, {
         'external_id':
         'vibrio.positive.control',
         'description':
         'Bacterial isolate control (Vibrio fischeri ES114)'
         '. Represents an extraction well loaded with '
         'Vibrio.'
     }, {
         'external_id':
         'zymo.mock',
         'description':
         'Bacterial community control (Zymo Mock D6306). '
         'Represents an extraction well loaded with Zymo '
         'Mock community.'
     }, {
         'external_id': 'zzTestControl',
         'description': 'A test control'
     }]
     self.assertEqual(obs, exp)
Пример #17
0
 def get(self):
     term = self.get_argument('term', None)
     self.write(json_encode(SampleComposition.get_control_samples(term)))
     self.finish()
Пример #18
0
 def get(self):
     controls = SampleComposition.get_control_sample_types_description()
     self.render('controls.html', controls=controls)
Пример #19
0
    def post(self):
        external_id = self.get_argument('external_id')
        description = self.get_argument('description')

        SampleComposition.create_control_sample_type(external_id, description)
        self.finish()
Пример #20
0
 def get(self):
     control_names = SampleComposition.get_control_samples()
     self.render('plate_search.html',
                 control_names=json_encode(control_names))
Пример #21
0
    def test_sample_plating_process_handler_patch_request(self):
        user = User('*****@*****.**')
        # Test operation not supported
        regex = ('Operation add not supported. Current supported '
                 'operations: replace')
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'add', '/well/8/1/sample', '1.SKM8.640201', None)

        # Test incorrect path parameter
        regex = 'Incorrect path parameter'
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/8/1/', '1.SKM8.640201', None)
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/sample/content',
                '1.SKM8.640201', None)

        # Test attribute not found
        regex = 'Attribute content not found'
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/content/8/1/sample', '1.SKM8.640201',
                None)

        # Test well not found
        regex = 'Well attribute WRONG not found'
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/WRONG', '1.SKM8.640201', None)

        # Test missing req_value
        regex = 'A new value for the well should be provided'
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/sample', None, None)
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/sample', '', None)
        with self.assertRaisesRegex(HTTPError, regex):
            sample_plating_process_handler_patch_request(
                user, 10, 'replace', '/well/8/1/sample', '  ', None)

        # Test success
        tester = SampleComposition(85)
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'blank.21.H1')

        obs = sample_plating_process_handler_patch_request(
            user, 10, 'replace', '/well/8/1/sample', '1.SKM8.640201', None)
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertEqual(tester.sample_id, '1.SKM8.640201')
        self.assertEqual(tester.content, '1.SKM8.640201')
        self.assertEqual(obs, {
            'sample_id': '1.SKM8.640201',
            'previous_plates': [],
            'sample_ok': True
        })

        obs = sample_plating_process_handler_patch_request(
            user, 10, 'replace', '/well/8/1/sample', 'Unknown', None)
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'Unknown')
        self.assertEqual(obs, {
            'sample_id': 'Unknown',
            'previous_plates': [],
            'sample_ok': False
        })

        obs = sample_plating_process_handler_patch_request(
            user, 10, 'replace', '/well/8/1/sample', 'blank', None)
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'blank.21.H1')
        self.assertEqual(obs, {
            'sample_id': 'blank.21.H1',
            'previous_plates': [],
            'sample_ok': True
        })

        # Test commenting a well
        self.assertIsNone(tester.notes)
        obs = sample_plating_process_handler_patch_request(
            user, 10, 'replace', '/well/8/1/notes', 'New Notes', None)
        self.assertEqual(tester.notes, 'New Notes')
        obs = sample_plating_process_handler_patch_request(
            user, 10, 'replace', '/well/8/1/notes', '  ', None)
        self.assertIsNone(tester.notes)
Пример #22
0
    def test_sample_composition_update(self):
        tester = SampleComposition(85)

        # Make sure that the sample composition that we are working with
        # is a control sample
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'blank.21.H1')

        # Update a well from CONTROL -> EXPERIMENTAL SAMPLE
        self.assertEqual(tester.update('1.SKM8.640201'),
                         ('1.SKM8.640201', True))
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertEqual(tester.sample_id, '1.SKM8.640201')
        self.assertEqual(tester.content, '1.SKM8.640201')

        # This test here tests that the code automatically detects when a
        # sample is duplicated in the plate and adds the plate ID and
        # well ID to all duplicates.
        t2 = SampleComposition(86)
        self.assertEqual(t2.update('1.SKM8.640201'),
                         ('1.SKM8.640201.21.H2', True))
        self.assertEqual(t2.sample_composition_type, 'experimental sample')
        self.assertEqual(t2.sample_id, '1.SKM8.640201')
        self.assertEqual(t2.content, '1.SKM8.640201.21.H2')
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertEqual(tester.sample_id, '1.SKM8.640201')
        self.assertEqual(tester.content, '1.SKM8.640201.21.H1')

        # This test here tests that the code automatically detects when a
        # sample is no longer duplicated in the plate and removes the plate
        # id and well id from the sample content
        self.assertEqual(t2.update('blank'), ('blank.21.H2', True))
        self.assertEqual(tester.content, '1.SKM8.640201')

        # Update a well from EXPERIMENTAL SAMPLE -> EXPERIMENTAL SAMPLE
        self.assertEqual(tester.update('1.SKB6.640176'),
                         ('1.SKB6.640176.21.H1', True))
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertEqual(tester.sample_id, '1.SKB6.640176')
        self.assertEqual(tester.content, '1.SKB6.640176.21.H1')

        # Update a well from EXPERIMENTAL SAMPLE -> CONTROL
        self.assertEqual(tester.update('vibrio.positive.control'),
                         ('vibrio.positive.control.21.H1', True))
        self.assertEqual(tester.sample_composition_type,
                         'vibrio.positive.control')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'vibrio.positive.control.21.H1')

        # Update a well from CONROL -> CONTROL
        self.assertEqual(tester.update('blank'), ('blank.21.H1', True))
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'blank.21.H1')

        # Update a well from CONROL -> Unknown
        self.assertEqual(tester.update('Unknown'), ('Unknown', False))
        self.assertEqual(tester.sample_composition_type, 'experimental sample')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'Unknown')

        # Update a well from Unknown -> CONTROL
        self.assertEqual(tester.update('blank'), ('blank.21.H1', True))
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'blank.21.H1')
Пример #23
0
    def test_patch_with_specimen_id(self):
        # Test for initial conditions. If these are not met then the tests will
        # fail
        tester = SampleComposition(8)
        self.assertEqual(tester.sample_composition_type, 'blank')
        self.assertIsNone(tester.sample_id)
        self.assertEqual(tester.content, 'blank.Test.plate.1.H1')

        # HACK: the Study object in labman can't modify specimen_id_column
        # hence we do this directly in SQL, if a test fails the transaction
        # will rollback, otherwise we reset the column to NULL.
        sql = """UPDATE qiita.study
                 SET specimen_id_column = %s
                 WHERE study_id = 1"""
        with sql_connection.TRN as TRN:
            TRN.add(sql, ['anonymized_name'])

            obs = sample_plating_process_handler_patch_request(
                self.user, 11, 'replace', '/well/8/1/1/sample', 'SKM8', None)
            self.assertEqual(tester.sample_composition_type,
                             'experimental sample')
            self.assertEqual(tester.sample_id, '1.SKM8.640201')
            self.assertEqual(tester.content, '1.SKM8.640201')
            self.assertEqual(tester.specimen_id, 'SKM8')
            self.assertEqual(obs, {
                'sample_id': 'SKM8',
                'previous_plates': [],
                'sample_ok': True
            })

            obs = sample_plating_process_handler_patch_request(
                self.user, 11, 'replace', '/well/8/1/1/sample', 'Unknown',
                None)
            self.assertEqual(tester.sample_composition_type,
                             'experimental sample')
            self.assertIsNone(tester.sample_id)
            self.assertEqual(tester.content, 'Unknown')
            self.assertEqual(tester.specimen_id, 'Unknown')
            self.assertEqual(obs, {
                'sample_id': 'Unknown',
                'previous_plates': [],
                'sample_ok': False
            })

            obs = sample_plating_process_handler_patch_request(
                self.user, 11, 'replace', '/well/8/1/1/sample', 'blank', None)
            self.assertEqual(tester.sample_composition_type, 'blank')
            self.assertIsNone(tester.sample_id)
            self.assertEqual(tester.content, 'blank.Test.plate.1.H1')
            self.assertEqual(tester.specimen_id, 'blank.Test.plate.1.H1')
            self.assertEqual(
                obs, {
                    'sample_id': 'blank.Test.plate.1.H1',
                    'previous_plates': [],
                    'sample_ok': True
                })

            # Test commenting a well
            self.assertIsNone(tester.notes)
            obs = sample_plating_process_handler_patch_request(
                self.user, 11, 'replace', '/well/8/1/1/notes', 'New Notes',
                None)
            self.assertEqual(tester.notes, 'New Notes')
            obs = sample_plating_process_handler_patch_request(
                self.user, 11, 'replace', '/well/8/1/1/notes', '  ', None)
            self.assertIsNone(tester.notes)

            TRN.add(sql, [None])