Add tests for the core github_sync functionality
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
from git import Repo
|
||||
from contentstore import import_from_xml
|
||||
from fs.osfs import OSFS
|
||||
import logging
|
||||
import os
|
||||
from xmodule.modulestore import Location
|
||||
from django.conf import settings
|
||||
|
||||
from django.conf import settings
|
||||
from fs.osfs import OSFS
|
||||
from git import Repo, PushInfo
|
||||
|
||||
from contentstore import import_from_xml
|
||||
from xmodule.modulestore import Location
|
||||
|
||||
from .exceptions import GithubSyncError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def import_from_github(repo_settings):
|
||||
"""
|
||||
@@ -53,4 +59,17 @@ def export_to_github(course, repo_path, commit_message):
|
||||
|
||||
origin = git_repo.remotes.origin
|
||||
if settings.MITX_FEATURES['GITHUB_PUSH']:
|
||||
origin.push()
|
||||
push_infos = origin.push()
|
||||
if len(push_infos) > 1:
|
||||
log.error('Unexpectedly pushed multiple heads: {infos}'.format(
|
||||
infos="\n".join(str(info.summary) for info in push_infos)
|
||||
))
|
||||
|
||||
if push_infos[0].flags & PushInfo.ERROR:
|
||||
log.error('Failed push: flags={p.flags}, local_ref={p.local_ref}, '
|
||||
'remote_ref_string={p.remote_ref_string}, '
|
||||
'remote_ref={p.remote_ref}, old_commit={p.old_commit}, '
|
||||
'summary={p.summary})'.format(p=push_infos[0]))
|
||||
raise GithubSyncError('Failed to push: {info}'.format(
|
||||
info=str(push_infos[0].summary)
|
||||
))
|
||||
|
||||
2
cms/djangoapps/github_sync/exceptions.py
Normal file
2
cms/djangoapps/github_sync/exceptions.py
Normal file
@@ -0,0 +1,2 @@
|
||||
class GithubSyncError(Exception):
|
||||
pass
|
||||
96
cms/djangoapps/github_sync/tests/__init__.py
Normal file
96
cms/djangoapps/github_sync/tests/__init__.py
Normal file
@@ -0,0 +1,96 @@
|
||||
from django.test import TestCase
|
||||
from path import path
|
||||
import shutil
|
||||
from github_sync import import_from_github, export_to_github, repo_path_from_location
|
||||
from git import Repo
|
||||
from django.conf import settings
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore import Location
|
||||
from override_settings import override_settings
|
||||
from github_sync.exceptions import GithubSyncError
|
||||
|
||||
|
||||
class GithubSyncTestCase(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.working_dir = path(settings.TEST_ROOT)
|
||||
self.repo_dir = self.working_dir / 'local_repo'
|
||||
self.remote_dir = self.working_dir / 'remote_repo'
|
||||
shutil.copytree('common/test/data/toy', self.remote_dir)
|
||||
|
||||
remote = Repo.init(self.remote_dir)
|
||||
remote.git.add(A=True)
|
||||
remote.git.commit(m='Initial commit')
|
||||
remote.git.config("receive.denyCurrentBranch", "ignore")
|
||||
|
||||
modulestore().collection.drop()
|
||||
|
||||
self.import_revision, self.import_course = import_from_github({
|
||||
'path': self.repo_dir,
|
||||
'origin': self.remote_dir,
|
||||
'branch': 'master',
|
||||
'org': 'org',
|
||||
'course': 'course'
|
||||
})
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.repo_dir)
|
||||
shutil.rmtree(self.remote_dir)
|
||||
|
||||
def test_initialize_repo(self):
|
||||
"""
|
||||
Test that importing from github will create a repo if the repo doesn't already exist
|
||||
"""
|
||||
self.assertEquals(1, len(Repo(self.repo_dir).head.reference.log()))
|
||||
|
||||
def test_import_contents(self):
|
||||
"""
|
||||
Test that the import loads the correct course into the modulestore
|
||||
"""
|
||||
self.assertEquals('Toy Course', self.import_course.metadata['display_name'])
|
||||
self.assertIn(
|
||||
Location('i4x://org/course/chapter/Overview'),
|
||||
[child.location for child in self.import_course.get_children()])
|
||||
self.assertEquals(1, len(self.import_course.get_children()))
|
||||
|
||||
@override_settings(MITX_FEATURES={'GITHUB_PUSH': False})
|
||||
def test_export_no_pash(self):
|
||||
"""
|
||||
Test that with the GITHUB_PUSH feature disabled, no content is pushed to the remote
|
||||
"""
|
||||
export_to_github(self.import_course, self.repo_dir, 'Test no-push')
|
||||
self.assertEquals(1, Repo(self.remote_dir).head.commit.count())
|
||||
|
||||
@override_settings(MITX_FEATURES={'GITHUB_PUSH': True})
|
||||
def test_export_push(self):
|
||||
"""
|
||||
Test that with GITHUB_PUSH enabled, content is pushed to the remote
|
||||
"""
|
||||
self.import_course.metadata['display_name'] = 'Changed display name'
|
||||
export_to_github(self.import_course, self.repo_dir, 'Test push')
|
||||
self.assertEquals(2, Repo(self.remote_dir).head.commit.count())
|
||||
|
||||
@override_settings(MITX_FEATURES={'GITHUB_PUSH': True})
|
||||
def test_export_conflict(self):
|
||||
"""
|
||||
Test that if there is a conflict when pushing to the remote repo, nothing is pushed and an exception is raised
|
||||
"""
|
||||
self.import_course.metadata['display_name'] = 'Changed display name'
|
||||
|
||||
remote = Repo(self.remote_dir)
|
||||
remote.git.commit(allow_empty=True, m="Testing conflict commit")
|
||||
|
||||
self.assertRaises(GithubSyncError, export_to_github, self.import_course, self.repo_dir, 'Test push')
|
||||
self.assertEquals(2, remote.head.reference.commit.count())
|
||||
self.assertEquals("Testing conflict commit\n", remote.head.reference.commit.message)
|
||||
|
||||
|
||||
@override_settings(REPOS={'namea': {'path': 'patha', 'org': 'orga', 'course': 'coursea'},
|
||||
'nameb': {'path': 'pathb', 'org': 'orgb', 'course': 'courseb'}})
|
||||
class RepoPathLookupTestCase(TestCase):
|
||||
def test_successful_lookup(self):
|
||||
self.assertEquals('patha', repo_path_from_location('i4x://orga/coursea/course/foo'))
|
||||
self.assertEquals('pathb', repo_path_from_location('i4x://orgb/courseb/course/foo'))
|
||||
|
||||
def test_failed_lookup(self):
|
||||
self.assertEquals(None, repo_path_from_location('i4x://c/c/course/foo'))
|
||||
@@ -17,10 +17,18 @@ for app in os.listdir(PROJECT_ROOT / 'djangoapps'):
|
||||
NOSE_ARGS += ['--cover-package', app]
|
||||
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
|
||||
|
||||
TEST_ROOT = 'test_root'
|
||||
|
||||
MODULESTORE = {
|
||||
'host': 'localhost',
|
||||
'db': 'mongo_base',
|
||||
'collection': 'key_store',
|
||||
'default': {
|
||||
'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore',
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.raw_module.RawDescriptor',
|
||||
'host': 'localhost',
|
||||
'db': 'test_xmodule',
|
||||
'collection': 'modulestore',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DATABASES = {
|
||||
|
||||
@@ -29,3 +29,4 @@ django_nose
|
||||
nosexcover
|
||||
rednose
|
||||
GitPython >= 0.3
|
||||
django-override-settings
|
||||
|
||||
2
test_root/.gitignore
vendored
Normal file
2
test_root/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
local_repo
|
||||
remote_repo
|
||||
Reference in New Issue
Block a user