#!/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 = '''
sacks
2017-06-15T11:59:00.355419Z
sacks
2013-02-07T16:17:56.412878Z
sacks
2017-05-01T16:48:27.893741Z
'''
SVN_STATUS_XML_DIRTY_MISSING = '''
sacks
2017-06-15T11:59:00.355419Z
'''
SVN_STATUS_XML_DIRTY_MODIFIED = '''
sacks
2013-02-07T16:17:56.412878Z
'''
SVN_STATUS_XML_DIRTY_DELETED = '''
sacks
2017-05-01T16:48:27.893741Z
'''
SVN_STATUS_XML_DIRTY_UNVERSION = '''
'''
SVN_STATUS_XML_DIRTY_ADDED = '''
'''
SVN_STATUS_XML_CLEAN = '''
'''
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()