502 lines
13 KiB
Python
502 lines
13 KiB
Python
#!/usr/bin/env python
|
|
|
|
"""Unit test driver for checkout_externals
|
|
|
|
Note: this script assume the path to the checkout_externals.py module is
|
|
already in the python path.
|
|
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import unicode_literals
|
|
from __future__ import print_function
|
|
|
|
import unittest
|
|
|
|
from manic.repository_svn import SvnRepository
|
|
from manic.externals_status import ExternalStatus
|
|
from manic.externals_description import ExternalsDescription
|
|
from manic.externals_description import ExternalsDescriptionDict
|
|
from manic.global_constants import EMPTY_STR
|
|
|
|
# pylint: disable=W0212
|
|
|
|
SVN_INFO_MOSART = """Path: components/mosart
|
|
Working Copy Root Path: /Users/andreb/projects/ncar/git-conversion/clm-dev-experimental/components/mosart
|
|
URL: https://svn-ccsm-models.cgd.ucar.edu/mosart/trunk_tags/mosart1_0_26
|
|
Relative URL: ^/mosart/trunk_tags/mosart1_0_26
|
|
Repository Root: https://svn-ccsm-models.cgd.ucar.edu
|
|
Repository UUID: fe37f545-8307-0410-aea5-b40df96820b5
|
|
Revision: 86711
|
|
Node Kind: directory
|
|
Schedule: normal
|
|
Last Changed Author: erik
|
|
Last Changed Rev: 86031
|
|
Last Changed Date: 2017-07-07 12:28:10 -0600 (Fri, 07 Jul 2017)
|
|
"""
|
|
SVN_INFO_CISM = """
|
|
Path: components/cism
|
|
Working Copy Root Path: /Users/andreb/projects/ncar/git-conversion/clm-dev-experimental/components/cism
|
|
URL: https://svn-ccsm-models.cgd.ucar.edu/glc/trunk_tags/cism2_1_37
|
|
Relative URL: ^/glc/trunk_tags/cism2_1_37
|
|
Repository Root: https://svn-ccsm-models.cgd.ucar.edu
|
|
Repository UUID: fe37f545-8307-0410-aea5-b40df96820b5
|
|
Revision: 86711
|
|
Node Kind: directory
|
|
Schedule: normal
|
|
Last Changed Author: sacks
|
|
Last Changed Rev: 85704
|
|
Last Changed Date: 2017-06-15 05:59:28 -0600 (Thu, 15 Jun 2017)
|
|
"""
|
|
|
|
|
|
class TestSvnRepositoryCheckURL(unittest.TestCase):
|
|
"""Verify that the svn_check_url function is working as expected.
|
|
"""
|
|
|
|
def setUp(self):
|
|
"""Setup reusable svn repository object
|
|
"""
|
|
self._name = 'component'
|
|
rdata = {ExternalsDescription.PROTOCOL: 'svn',
|
|
ExternalsDescription.REPO_URL:
|
|
'https://svn-ccsm-models.cgd.ucar.edu/',
|
|
ExternalsDescription.TAG:
|
|
'mosart/trunk_tags/mosart1_0_26',
|
|
}
|
|
|
|
data = {self._name:
|
|
{
|
|
ExternalsDescription.REQUIRED: False,
|
|
ExternalsDescription.PATH: 'junk',
|
|
ExternalsDescription.EXTERNALS: '',
|
|
ExternalsDescription.REPO: rdata,
|
|
},
|
|
}
|
|
|
|
model = ExternalsDescriptionDict(data)
|
|
repo = model[self._name][ExternalsDescription.REPO]
|
|
self._repo = SvnRepository('test', repo)
|
|
|
|
def test_check_url_same(self):
|
|
"""Test that we correctly identify that the correct URL.
|
|
"""
|
|
svn_output = SVN_INFO_MOSART
|
|
expected_url = self._repo.url()
|
|
result, current_version = \
|
|
self._repo._check_url(svn_output, expected_url)
|
|
self.assertEqual(result, ExternalStatus.STATUS_OK)
|
|
self.assertEqual(current_version, 'mosart/trunk_tags/mosart1_0_26')
|
|
|
|
def test_check_url_different(self):
|
|
"""Test that we correctly reject an incorrect URL.
|
|
"""
|
|
svn_output = SVN_INFO_CISM
|
|
expected_url = self._repo.url()
|
|
result, current_version = \
|
|
self._repo._check_url(svn_output, expected_url)
|
|
self.assertEqual(result, ExternalStatus.MODEL_MODIFIED)
|
|
self.assertEqual(current_version, 'glc/trunk_tags/cism2_1_37')
|
|
|
|
def test_check_url_none(self):
|
|
"""Test that we can handle an empty string for output, e.g. not an svn
|
|
repo.
|
|
|
|
"""
|
|
svn_output = EMPTY_STR
|
|
expected_url = self._repo.url()
|
|
result, current_version = \
|
|
self._repo._check_url(svn_output, expected_url)
|
|
self.assertEqual(result, ExternalStatus.UNKNOWN)
|
|
self.assertEqual(current_version, '')
|
|
|
|
|
|
class TestSvnRepositoryCheckSync(unittest.TestCase):
|
|
"""Test whether the SvnRepository svn_check_sync functionality is
|
|
correct.
|
|
|
|
"""
|
|
|
|
def setUp(self):
|
|
"""Setup reusable svn repository object
|
|
"""
|
|
self._name = "component"
|
|
rdata = {ExternalsDescription.PROTOCOL: 'svn',
|
|
ExternalsDescription.REPO_URL:
|
|
'https://svn-ccsm-models.cgd.ucar.edu/',
|
|
ExternalsDescription.TAG:
|
|
'mosart/trunk_tags/mosart1_0_26',
|
|
}
|
|
|
|
data = {self._name:
|
|
{
|
|
ExternalsDescription.REQUIRED: False,
|
|
ExternalsDescription.PATH: 'junk',
|
|
ExternalsDescription.EXTERNALS: EMPTY_STR,
|
|
ExternalsDescription.REPO: rdata,
|
|
},
|
|
}
|
|
|
|
model = ExternalsDescriptionDict(data)
|
|
repo = model[self._name][ExternalsDescription.REPO]
|
|
self._repo = SvnRepository('test', repo)
|
|
|
|
@staticmethod
|
|
def _svn_info_empty(*_):
|
|
"""Return an empty info string. Simulates svn info failing.
|
|
"""
|
|
return ''
|
|
|
|
@staticmethod
|
|
def _svn_info_synced(*_):
|
|
"""Return an info sting that is synced with the setUp data
|
|
"""
|
|
return SVN_INFO_MOSART
|
|
|
|
@staticmethod
|
|
def _svn_info_modified(*_):
|
|
"""Return and info string that is modified from the setUp data
|
|
"""
|
|
return SVN_INFO_CISM
|
|
|
|
def test_repo_dir_not_exist(self):
|
|
"""Test that a directory that doesn't exist returns an error status
|
|
|
|
Note: the Repository classes should be prevented from ever
|
|
working on an empty directory by the _Source object.
|
|
|
|
"""
|
|
stat = ExternalStatus()
|
|
self._repo._check_sync(stat, 'junk')
|
|
self.assertEqual(stat.sync_state, ExternalStatus.STATUS_ERROR)
|
|
# check_dir should only modify the sync_state, not clean_state
|
|
self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
|
|
|
|
def test_repo_dir_exist_no_svn_info(self):
|
|
"""Test that an empty info string returns an unknown status
|
|
"""
|
|
stat = ExternalStatus()
|
|
# Now we over-ride the _svn_info method on the repo to return
|
|
# a known value without requiring access to svn.
|
|
self._repo._svn_info = self._svn_info_empty
|
|
self._repo._check_sync(stat, '.')
|
|
self.assertEqual(stat.sync_state, ExternalStatus.UNKNOWN)
|
|
# check_dir should only modify the sync_state, not clean_state
|
|
self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
|
|
|
|
def test_repo_dir_synced(self):
|
|
"""Test that a valid info string that is synced to the repo in the
|
|
externals description returns an ok status.
|
|
|
|
"""
|
|
stat = ExternalStatus()
|
|
# Now we over-ride the _svn_info method on the repo to return
|
|
# a known value without requiring access to svn.
|
|
self._repo._svn_info = self._svn_info_synced
|
|
self._repo._check_sync(stat, '.')
|
|
self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK)
|
|
# check_dir should only modify the sync_state, not clean_state
|
|
self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
|
|
|
|
def test_repo_dir_modified(self):
|
|
"""Test that a valid svn info string that is out of sync with the
|
|
externals description returns a modified status.
|
|
|
|
"""
|
|
stat = ExternalStatus()
|
|
# Now we over-ride the _svn_info method on the repo to return
|
|
# a known value without requiring access to svn.
|
|
self._repo._svn_info = self._svn_info_modified
|
|
self._repo._check_sync(stat, '.')
|
|
self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED)
|
|
# check_dir should only modify the sync_state, not clean_state
|
|
self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
|
|
|
|
|
|
class TestSVNStatusXML(unittest.TestCase):
|
|
"""Test parsing of svn status xml output
|
|
"""
|
|
SVN_STATUS_XML_DIRTY_ALL = '''
|
|
<status>
|
|
<target
|
|
path=".">
|
|
<entry
|
|
path="ChangeLog">
|
|
<wc-status
|
|
item="missing"
|
|
revision="86711"
|
|
props="none">
|
|
<commit
|
|
revision="85703">
|
|
<author>sacks</author>
|
|
<date>2017-06-15T11:59:00.355419Z</date>
|
|
</commit>
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="README.parallelization">
|
|
<wc-status
|
|
props="none"
|
|
item="modified"
|
|
revision="86711">
|
|
<commit
|
|
revision="43811">
|
|
<author>sacks</author>
|
|
<date>2013-02-07T16:17:56.412878Z</date>
|
|
</commit>
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="SVN_EXTERNAL_DIRECTORIES">
|
|
<wc-status
|
|
item="deleted"
|
|
revision="86711"
|
|
props="none">
|
|
<commit
|
|
revision="84725">
|
|
<author>sacks</author>
|
|
<date>2017-05-01T16:48:27.893741Z</date>
|
|
</commit>
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="glimmer-cism">
|
|
<wc-status
|
|
item="external"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="junk.txt">
|
|
<wc-status
|
|
item="unversioned"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="stuff.txt">
|
|
<wc-status
|
|
props="none"
|
|
item="added"
|
|
revision="-1">
|
|
</wc-status>
|
|
</entry>
|
|
</target>
|
|
</status>'''
|
|
|
|
SVN_STATUS_XML_DIRTY_MISSING = '''
|
|
<status>
|
|
<target
|
|
path=".">
|
|
<entry
|
|
path="ChangeLog">
|
|
<wc-status
|
|
item="missing"
|
|
revision="86711"
|
|
props="none">
|
|
<commit
|
|
revision="85703">
|
|
<author>sacks</author>
|
|
<date>2017-06-15T11:59:00.355419Z</date>
|
|
</commit>
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="glimmer-cism">
|
|
<wc-status
|
|
item="external"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
</target>
|
|
</status>'''
|
|
|
|
SVN_STATUS_XML_DIRTY_MODIFIED = '''
|
|
<status>
|
|
<target
|
|
path=".">
|
|
<entry
|
|
path="README.parallelization">
|
|
<wc-status
|
|
props="none"
|
|
item="modified"
|
|
revision="86711">
|
|
<commit
|
|
revision="43811">
|
|
<author>sacks</author>
|
|
<date>2013-02-07T16:17:56.412878Z</date>
|
|
</commit>
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="glimmer-cism">
|
|
<wc-status
|
|
item="external"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
</target>
|
|
</status>'''
|
|
|
|
SVN_STATUS_XML_DIRTY_DELETED = '''
|
|
<status>
|
|
<target
|
|
path=".">
|
|
<entry
|
|
path="SVN_EXTERNAL_DIRECTORIES">
|
|
<wc-status
|
|
item="deleted"
|
|
revision="86711"
|
|
props="none">
|
|
<commit
|
|
revision="84725">
|
|
<author>sacks</author>
|
|
<date>2017-05-01T16:48:27.893741Z</date>
|
|
</commit>
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="glimmer-cism">
|
|
<wc-status
|
|
item="external"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
</target>
|
|
</status>'''
|
|
|
|
SVN_STATUS_XML_DIRTY_UNVERSION = '''
|
|
<status>
|
|
<target
|
|
path=".">
|
|
<entry
|
|
path="glimmer-cism">
|
|
<wc-status
|
|
item="external"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="junk.txt">
|
|
<wc-status
|
|
item="unversioned"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
</target>
|
|
</status>'''
|
|
|
|
SVN_STATUS_XML_DIRTY_ADDED = '''
|
|
<status>
|
|
<target
|
|
path=".">
|
|
<entry
|
|
path="glimmer-cism">
|
|
<wc-status
|
|
item="external"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="stuff.txt">
|
|
<wc-status
|
|
props="none"
|
|
item="added"
|
|
revision="-1">
|
|
</wc-status>
|
|
</entry>
|
|
</target>
|
|
</status>'''
|
|
|
|
SVN_STATUS_XML_CLEAN = '''
|
|
<status>
|
|
<target
|
|
path=".">
|
|
<entry
|
|
path="glimmer-cism">
|
|
<wc-status
|
|
item="external"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
<entry
|
|
path="junk.txt">
|
|
<wc-status
|
|
item="unversioned"
|
|
props="none">
|
|
</wc-status>
|
|
</entry>
|
|
</target>
|
|
</status>'''
|
|
|
|
def test_xml_status_dirty_missing(self):
|
|
"""Verify that svn status output is consindered dirty when there is a
|
|
missing file.
|
|
|
|
"""
|
|
svn_output = self.SVN_STATUS_XML_DIRTY_MISSING
|
|
is_dirty = SvnRepository.xml_status_is_dirty(
|
|
svn_output)
|
|
self.assertTrue(is_dirty)
|
|
|
|
def test_xml_status_dirty_modified(self):
|
|
"""Verify that svn status output is consindered dirty when there is a
|
|
modified file.
|
|
"""
|
|
svn_output = self.SVN_STATUS_XML_DIRTY_MODIFIED
|
|
is_dirty = SvnRepository.xml_status_is_dirty(
|
|
svn_output)
|
|
self.assertTrue(is_dirty)
|
|
|
|
def test_xml_status_dirty_deleted(self):
|
|
"""Verify that svn status output is consindered dirty when there is a
|
|
deleted file.
|
|
"""
|
|
svn_output = self.SVN_STATUS_XML_DIRTY_DELETED
|
|
is_dirty = SvnRepository.xml_status_is_dirty(
|
|
svn_output)
|
|
self.assertTrue(is_dirty)
|
|
|
|
def test_xml_status_dirty_unversion(self):
|
|
"""Verify that svn status output ignores unversioned files when making
|
|
the clean/dirty decision.
|
|
|
|
"""
|
|
svn_output = self.SVN_STATUS_XML_DIRTY_UNVERSION
|
|
is_dirty = SvnRepository.xml_status_is_dirty(
|
|
svn_output)
|
|
self.assertFalse(is_dirty)
|
|
|
|
def test_xml_status_dirty_added(self):
|
|
"""Verify that svn status output is consindered dirty when there is a
|
|
added file.
|
|
"""
|
|
svn_output = self.SVN_STATUS_XML_DIRTY_ADDED
|
|
is_dirty = SvnRepository.xml_status_is_dirty(
|
|
svn_output)
|
|
self.assertTrue(is_dirty)
|
|
|
|
def test_xml_status_dirty_all(self):
|
|
"""Verify that svn status output is consindered dirty when there are
|
|
multiple dirty files..
|
|
|
|
"""
|
|
svn_output = self.SVN_STATUS_XML_DIRTY_ALL
|
|
is_dirty = SvnRepository.xml_status_is_dirty(
|
|
svn_output)
|
|
self.assertTrue(is_dirty)
|
|
|
|
def test_xml_status_dirty_clean(self):
|
|
"""Verify that svn status output is consindered clean when there are
|
|
no 'dirty' files. This means accepting untracked and externals.
|
|
|
|
"""
|
|
svn_output = self.SVN_STATUS_XML_CLEAN
|
|
is_dirty = SvnRepository.xml_status_is_dirty(
|
|
svn_output)
|
|
self.assertFalse(is_dirty)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|