def test_save_returns_unmatched_rows(self, num_unmatched, num_multiple_matches): """Test that save() returns an UnmatchedRowCollector with the expected rows.""" num_matching = 2 matched_rows = make_matched_rows(num_matching) unmatched_rows = make_unmatched_rows(num_unmatched) multiple_matches_rows = make_multiple_matches_rows(num_multiple_matches) user = AdviserFactory(first_name='Admin', last_name='User') file = make_csv_file_from_dicts( *matched_rows, *unmatched_rows, *multiple_matches_rows, ) file_contents = file.getvalue() form = InteractionCSVForm( files={ 'csv_file': SimpleUploadedFile(file.name, file_contents), }, ) assert form.is_valid() _, unmatched_row_collector = form.save(user) assert unmatched_row_collector.rows == [ *unmatched_rows, *multiple_matches_rows, ]
def test_save_returns_correct_counts(self, num_unmatched, num_multiple_matches): """Test that save() returns the expected counts for each matching status.""" num_matching = 1 matched_rows = make_matched_rows(num_matching) unmatched_rows = make_unmatched_rows(num_unmatched) multiple_matches_rows = make_multiple_matches_rows(num_multiple_matches) user = AdviserFactory(first_name='Admin', last_name='User') file = make_csv_file_from_dicts( *matched_rows, *unmatched_rows, *multiple_matches_rows, ) file_contents = file.getvalue() form = InteractionCSVForm( files={ 'csv_file': SimpleUploadedFile(file.name, file_contents), }, ) assert form.is_valid() matching_counts, _ = form.save(user) assert matching_counts == { ContactMatchingStatus.matched: num_matching, ContactMatchingStatus.unmatched: num_unmatched, ContactMatchingStatus.multiple_matches: num_multiple_matches, }
def test_save_creates_interactions(self, num_unmatched, num_multiple_matches): """Test that save() creates interactions.""" num_matching = 3 matched_rows = make_matched_rows(num_matching) unmatched_rows = make_unmatched_rows(num_unmatched) multiple_matches_rows = make_multiple_matches_rows( num_multiple_matches) user = AdviserFactory(first_name='Admin', last_name='User') file = make_csv_file_from_dicts( *matched_rows, *unmatched_rows, *multiple_matches_rows, ) file_contents = file.getvalue() form = InteractionCSVForm(files={ 'csv_file': SimpleUploadedFile(file.name, file_contents), }, ) assert form.is_valid() form.save(user) created_interactions = list(Interaction.objects.all()) assert len(created_interactions) == num_matching expected_contact_emails = { row['contact_email'] for row in matched_rows } actual_contact_emails = { interaction.contacts.first().email for interaction in created_interactions } # Make sure the test was correctly set up with unique contact emails assert len(actual_contact_emails) == num_matching # Check that the interactions created are the ones we expect # Note: the full saving logic for a row is tested in the InteractionCSVRowForm tests assert expected_contact_emails == actual_contact_emails expected_source = { 'file': { 'name': file.name, 'size': len(file_contents), 'sha256': hashlib.sha256(file_contents).hexdigest(), }, } # `source` has been set (list used rather than a generator for useful failure messages) assert all([ interaction.source == expected_source for interaction in created_interactions ])
def test_to_csv(self): """Test CSV file generation.""" collector = UnmatchedRowCollector() input_rows = make_unmatched_rows(2) for input_row in input_rows: collector.append_row(InteractionCSVForm(data=input_row)) csv_contents = collector.to_raw_csv() with io.BytesIO(csv_contents) as stream: reader = csv.reader(io.TextIOWrapper(stream, encoding='utf-8-sig')) csv_rows = list(reader) assert csv_rows == [ [ 'theme', 'kind', 'date', 'adviser_1', 'contact_email', 'service', 'communication_channel', ], [ input_rows[0]['theme'], input_rows[0]['kind'], input_rows[0]['date'], input_rows[0]['adviser_1'], input_rows[0]['contact_email'], input_rows[0]['service'], input_rows[0]['communication_channel'], ], [ input_rows[1]['theme'], input_rows[1]['kind'], input_rows[1]['date'], input_rows[1]['adviser_1'], input_rows[1]['contact_email'], input_rows[1]['service'], input_rows[1]['communication_channel'], ], ] # Check that the file re-validates (so it can be re-uploaded) form = InteractionCSVForm( files={ 'csv_file': SimpleUploadedFile('test.csv', csv_contents), }, ) assert form.is_valid() assert form.are_all_rows_valid()
def test_get_matching_summary( self, num_matching, num_unmatched, num_multiple_matches, max_returned_rows, ): """Test get_matching_summary() with various inputs.""" input_matched_rows = make_matched_rows(num_matching) unmatched_rows = make_unmatched_rows(num_unmatched) multiple_matches_rows = make_multiple_matches_rows( num_multiple_matches) file = make_csv_file_from_dicts( *input_matched_rows, *unmatched_rows, *multiple_matches_rows, ) form = InteractionCSVForm(files={ 'csv_file': SimpleUploadedFile(file.name, file.getvalue()), }, ) assert form.is_valid() matching_counts, returned_matched_rows = form.get_matching_summary( max_returned_rows) assert matching_counts == { ContactMatchingStatus.matched: num_matching, ContactMatchingStatus.unmatched: num_unmatched, ContactMatchingStatus.multiple_matches: num_multiple_matches, } expected_num_returned_rows = min(num_matching, max_returned_rows) assert len(returned_matched_rows) == expected_num_returned_rows # Check the the rows returned are the ones we expect expected_contact_emails = [ row['contact_email'] for row in input_matched_rows[:expected_num_returned_rows] ] actual_contact_emails = [ row['contacts'][0].email for row in returned_matched_rows ] assert expected_contact_emails == actual_contact_emails
def _create_file_in_cache(token, num_matching, num_unmatched, num_multiple_matches): matched_rows = make_matched_rows(num_matching) unmatched_rows = make_unmatched_rows(num_unmatched) multiple_matches_rows = make_multiple_matches_rows(num_multiple_matches) file = make_csv_file_from_dicts( *matched_rows, *unmatched_rows, *multiple_matches_rows, filename='cache-test.csv', ) with file: compressed_contents = gzip.compress(file.read()) contents_key = _cache_key_for_token(token, CacheKeyType.file_contents) name_key = _cache_key_for_token(token, CacheKeyType.file_name) cache.set(contents_key, compressed_contents) cache.set(name_key, file.name) return matched_rows
def test_get_row_errors_with_duplicate_rows(self): """Test that duplicate rows are tracked and errors returned when encountered.""" matched_rows = make_matched_rows(5) file = make_csv_file_from_dicts( # Duplicate the first row matched_rows[0], *matched_rows, *make_unmatched_rows(5), *make_multiple_matches_rows(5), ) form = InteractionCSVForm( files={ 'csv_file': SimpleUploadedFile(file.name, file.getvalue()), }, ) assert form.is_valid() row_errors = list(form.get_row_error_iterator()) assert row_errors == [ CSVRowError(1, NON_FIELD_ERRORS, '', DUPLICATE_OF_ANOTHER_ROW_MESSAGE), ]