diff --git a/crc/api/workflow_sync.py b/crc/api/workflow_sync.py index 4915af0f..68cd9fd2 100644 --- a/crc/api/workflow_sync.py +++ b/crc/api/workflow_sync.py @@ -97,7 +97,7 @@ def sync_all_changed_workflows(remote): def sync_changed_files(remote,workflow_spec_id): # make sure that spec is local before syncing files - specdict = WorkflowSyncService.get_remote_workfow_spec(remote,workflow_spec_id) + specdict = WorkflowSyncService.get_remote_workflow_spec(remote,workflow_spec_id) localspec = session.query(WorkflowSpecModel).filter(WorkflowSpecModel.id == workflow_spec_id).first() if localspec is None: @@ -173,6 +173,8 @@ def get_changed_files(remote,workflow_spec_id,as_df=False): # get the local thumbprints & make sure that 'workflow_spec_id' is a column, not an index local = get_workflow_spec_files_dataframe(workflow_spec_id).reset_index() local['md5_hash'] = local['md5_hash'].astype('str') + remote_files['md5_hash'] = remote_files['md5_hash'].astype('str') + different = remote_files.merge(local, right_on=['filename','md5_hash'], left_on=['filename','md5_hash'], @@ -205,7 +207,7 @@ def get_changed_files(remote,workflow_spec_id,as_df=False): # get an exclusive or list of workflow ids - that is we want lists of files that are # on one machine or the other, but not both - remote_spec_ids = remote[['filename']] + remote_spec_ids = remote_files[['filename']] local_spec_ids = local[['filename']] left = remote_spec_ids[~remote_spec_ids['filename'].isin(local_spec_ids['filename'])] right = local_spec_ids[~local_spec_ids['filename'].isin(remote_spec_ids['filename'])] diff --git a/tests/base_test.py b/tests/base_test.py index e32bbd9b..4f2306a2 100644 --- a/tests/base_test.py +++ b/tests/base_test.py @@ -207,7 +207,7 @@ class BaseTest(unittest.TestCase): @staticmethod def workflow_sync_response(file_name): filepath = os.path.join(app.root_path, '..', 'tests', 'data', 'workflow_sync_responses', file_name) - with open(filepath, 'r') as myfile: + with open(filepath, 'rb') as myfile: data = myfile.read() return data diff --git a/tests/data/random_fact/random_fact2.bpmn b/tests/data/random_fact/random_fact2.bpmn new file mode 100644 index 00000000..bd0a9ef5 --- /dev/null +++ b/tests/data/random_fact/random_fact2.bpmn @@ -0,0 +1,200 @@ + + + + + SequenceFlow_0c7wlth + + + # h1 Heading 8-) +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +--- + +*** + + +## Typographic replacements + +"double quotes" and 'single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Strikethrough~~ + + +## Blockquotes + + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar + +## Tables + +| Option | Description | +| ------ | ----------- | +| data | path to data files to supply the data that will be passed into templates. | +| engine | engine to be used for processing templates. Handlebars is the default. | +| ext | extension to be used for dest files. | + +Right aligned columns + +| Option | Description | +| ------:| -----------:| +| data | path to data files to supply the data that will be passed into templates. | +| engine | engine to be used for processing templates. Handlebars is the default. | +| ext | extension to be used for dest files. | + + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + +## Images + +![Minion](https://octodex.github.com/images/minion.png) +![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat") + + + + + + + + + + + + + + + + SequenceFlow_0c7wlth + SequenceFlow_0641sh6 + + + + + + + + + SequenceFlow_0641sh6 + SequenceFlow_0t29gjo + FactService = fact_service() + + + # Great Job! +You have completed the random fact generator. +You chose to receive a random fact of the type: "{{type}}" + +Your random fact is: +{{details}} + SequenceFlow_0t29gjo + + + + + + User sets the Fact.type to cat, norris, or buzzword + + + + Makes an API  call to get a fact of the required type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/workflow_sync_responses/random_fact2.bpmn b/tests/data/workflow_sync_responses/random_fact2.bpmn new file mode 100644 index 00000000..f502a238 --- /dev/null +++ b/tests/data/workflow_sync_responses/random_fact2.bpmn @@ -0,0 +1,104 @@ + + + + + SequenceFlow_0c7wlth + + + # h1 Heading 8-) + NEW_FILE_ADDED + +![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat") + + + + + + + + + + + + + + + + SequenceFlow_0c7wlth + SequenceFlow_0641sh6 + + + + + + + + + SequenceFlow_0641sh6 + SequenceFlow_0t29gjo + FactService = fact_service() + + + # Great Job! +You have completed the random fact generator. +You chose to receive a random fact of the type: "{{type}}" + +Your random fact is: +{{details}} + SequenceFlow_0t29gjo + + + + + + User sets the Fact.type to cat, norris, or buzzword + + + + Makes an API  call to get a fact of the required type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_workflow_sync.py b/tests/test_workflow_sync.py index f2c68719..eb0cd1b5 100644 --- a/tests/test_workflow_sync.py +++ b/tests/test_workflow_sync.py @@ -2,12 +2,18 @@ from unittest.mock import patch from crc import db from tests.base_test import BaseTest -from crc.api.workflow_sync import get_all_spec_state, get_changed_workflows +from crc.api.workflow_sync import get_all_spec_state, \ + get_changed_workflows, \ + get_workflow_spec_files, \ + get_changed_files, \ + get_workflow_specification, \ + sync_changed_files from crc.models.workflow import WorkflowSpecModel -import json from datetime import datetime from crc.services.file_service import FileService + + class TestWorkflowSync(BaseTest): @patch('crc.services.workflow_sync.WorkflowSyncService.get_all_remote_workflows') @@ -73,3 +79,78 @@ class TestWorkflowSync(BaseTest): response = get_changed_workflows('localhost:0000') #endpoint is not used due to mock self.assertIsNotNone(response) self.assertEqual(response,[]) + + + @patch('crc.services.workflow_sync.WorkflowSyncService.get_remote_workflow_spec_files') + def test_file_differences(self, mock_get): + self.load_example_data() + othersys = get_workflow_spec_files('random_fact') + othersys[1]['date_created'] = str(datetime.now()) + othersys[1]['md5_hash'] = '12345' + mock_get.return_value = othersys + response = get_changed_files('localhost:0000','random_fact',as_df=False) #endpoint is not used due to mock + self.assertIsNotNone(response) + self.assertEqual(len(response),1) + self.assertEqual(response[0]['filename'], 'random_fact2.bpmn') + self.assertEqual(response[0]['location'], 'remote') + self.assertEqual(response[0]['new'], False) + + + @patch('crc.services.workflow_sync.WorkflowSyncService.get_remote_workflow_spec_files') + def test_file_differences(self, mock_get): + self.load_example_data() + othersys = get_workflow_spec_files('random_fact') + othersys[1]['date_created'] = str(datetime.now()) + othersys[1]['md5_hash'] = '12345' + mock_get.return_value = othersys + response = get_changed_files('localhost:0000','random_fact',as_df=False) #endpoint is not used due to mock + self.assertIsNotNone(response) + self.assertEqual(len(response),1) + self.assertEqual(response[0]['filename'], 'random_fact2.bpmn') + self.assertEqual(response[0]['location'], 'remote') + self.assertEqual(response[0]['new'], False) + + @patch('crc.services.workflow_sync.WorkflowSyncService.get_remote_file_by_hash') + @patch('crc.services.workflow_sync.WorkflowSyncService.get_remote_workflow_spec_files') + @patch('crc.services.workflow_sync.WorkflowSyncService.get_remote_workflow_spec') + def test_file_differences(self, workflow_mock, spec_files_mock, file_data_mock): + self.load_example_data() + remote_workflow = get_workflow_specification('random_fact') + self.assertEqual(remote_workflow['display_name'],'Random Fact') + remote_workflow['description'] = 'This Workflow came from Remote' + remote_workflow['display_name'] = 'Remote Workflow' + workflow_mock.return_value = remote_workflow + othersys = get_workflow_spec_files('random_fact') + othersys[1]['date_created'] = str(datetime.now()) + othersys[1]['md5_hash'] = '12345' + spec_files_mock.return_value = othersys + file_data_mock.return_value = self.workflow_sync_response('random_fact2.bpmn') + response = sync_changed_files('localhost:0000','random_fact') # endpoint not used due to mock + self.assertIsNotNone(response) + self.assertEqual(len(response),1) + self.assertEqual(response[0], 'random_fact2.bpmn') + files = FileService.get_spec_data_files('random_fact') + md5sums = [str(f.md5_hash) for f in files] + self.assertEqual('21bb6f9e-0af7-0ab2-0fc7-ec0f94787e58' in md5sums, True) + new_local_workflow = get_workflow_specification('random_fact') + self.assertEqual(new_local_workflow['display_name'],'Remote Workflow') + + + + @patch('crc.services.workflow_sync.WorkflowSyncService.get_remote_workflow_spec_files') + @patch('crc.services.workflow_sync.WorkflowSyncService.get_remote_workflow_spec') + def test_file_deleted(self, workflow_mock, spec_files_mock): + self.load_example_data() + remote_workflow = get_workflow_specification('random_fact') + workflow_mock.return_value = remote_workflow + othersys = get_workflow_spec_files('random_fact') + del(othersys[1]) + spec_files_mock.return_value = othersys + response = sync_changed_files('localhost:0000','random_fact') # endpoint not used due to mock + self.assertIsNotNone(response) + # when we delete a local file, we do not return that it was deleted - just + # a list of updated files. We may want to change this in the future. + self.assertEqual(len(response),0) + files = FileService.get_spec_data_files('random_fact') + self.assertEqual(len(files),1) +