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)
+