Пример #1
0
class CoursesAPITests(ACJAPITestCase):
    def setUp(self):
        super(CoursesAPITests, self).setUp()
        self.data = BasicTestData()

    def _verify_course_info(self, course_expected, course_actual):
        self.assertEqual(course_expected.name, course_actual['name'],
                         "Expected course name does not match actual.")
        self.assertEqual(course_expected.id, course_actual['id'],
                         "Expected course id does not match actual.")
        self.assertTrue(course_expected.criteriaandcourses,
                        "Course is missing a criteria")

    def test_get_single_course(self):
        course_api_url = '/api/courses/' + str(self.data.get_course().id)

        # Test login required
        rv = self.client.get(course_api_url)
        self.assert401(rv)

        # Test root get course
        with self.login('root'):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        # Test enroled users get course info
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        with self.login(self.data.get_authorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        # Test unenroled user not permitted to get info
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        with self.login(self.data.get_unauthorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        # Test get invalid course
        with self.login("root"):
            rv = self.client.get('/api/courses/38940450')
            self.assert404(rv)

    def test_get_all_courses(self):
        course_api_url = '/api/courses'

        # Test login required
        rv = self.client.get(course_api_url)
        self.assert401(rv)

        # Test only root can get a list of all courses
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        with self.login(self.data.get_authorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        with self.login("root"):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(),
                                     rv.json['objects'][0])

    def test_create_course(self):
        course_expected = {
            'name': 'ExpectedCourse1',
            'description': 'Test Course One Description Test'
        }
        # Test login required
        rv = self.client.post('/api/courses',
                              data=json.dumps(course_expected),
                              content_type='application/json')
        self.assert401(rv)
        # Test unauthorized user
        with self.login(self.data.get_authorized_student().username):
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course_expected),
                                  content_type='application/json')
            self.assert403(rv)

        # Test course creation
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course_expected),
                                  content_type='application/json')
            self.assert200(rv)
            # Verify return
            course_actual = rv.json
            self.assertEqual(course_expected['name'], course_actual['name'])
            self.assertEqual(course_expected['description'],
                             course_actual['description'])

            # Verify the course is created in db
            course_in_db = Courses.query.get(course_actual['id'])
            self.assertEqual(course_in_db.name, course_actual['name'])
            self.assertEqual(course_in_db.description,
                             course_actual['description'])

            # create course with criteria
            course = course_expected.copy()
            course['name'] = 'ExpectedCourse2'
            course['criteria'] = [{'id': 1}]
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course),
                                  content_type='application/json')
            self.assert200(rv)
            course_actual = rv.json

            # Verify the course is created in db
            course_in_db = Courses.query.get(course_actual['id'])
            self.assertEqual(len(course_in_db.criteriaandcourses), 1)
            self.assertEqual(course_in_db.criteriaandcourses[0].criteria_id,
                             course['criteria'][0]['id'])

    def test_create_duplicate_course(self):
        with self.login(self.data.get_authorized_instructor().username):
            course_existing = self.data.get_course()
            course_expected = {
                'name': course_existing.name,
                'description': course_existing.description
            }
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course_expected),
                                  content_type='application/json')
            self.assert400(rv)

    def test_create_course_with_bad_data_format(self):
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post('/api/courses',
                                  data=json.dumps({'description': 'd'}),
                                  content_type='application/json')
            self.assert400(rv)

    def test_edit_course(self):
        expected = {
            'id': self.data.get_course().id,
            'name': 'ExpectedCourse',
            'description': 'Test Description'
        }
        url = '/api/courses/' + str(self.data.get_course().id)

        # test login required
        rv = self.client.post(url,
                              data=json.dumps(expected),
                              content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert403(rv)

            # test unmatched course id
            rv = self.client.post('/api/courses/' +
                                  str(self.data.get_secondary_course().id),
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert400(rv)

        with self.login(self.data.get_authorized_instructor().username):
            # test invalid course id
            rv = self.client.post('/api/courses/999',
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert404(rv)

            # test authorized user
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert200(rv)
            db.session.expire_all()
            self.assertEqual(expected['id'], rv.json['id'])
            self.assertEqual(expected['name'], rv.json['name'])
            self.assertEqual(expected['description'], rv.json['description'])

            # test add criteria
            course = expected.copy()
            course['criteria'] = [{'id': 1}]
            rv = self.client.post(url,
                                  data=json.dumps(course),
                                  content_type='application/json')
            self.assert200(rv)

            db.session.expire_all()
            course_in_db = Courses.query.get(course['id'])
            self.assertEqual(len(course_in_db.criteriaandcourses), 1)
            self.assertEqual(course_in_db.criteriaandcourses[0].criteria_id,
                             course['criteria'][0]['id'])

            # test remove criteria
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert200(rv)

            # expire all instances in session and force session to query from db
            db.session.expire_all()
            course_in_db = Courses.query.get(course['id'])
            self.assertEqual(len(course_in_db.criteriaandcourses), 0)
Пример #2
0
class CoursesAPITests(ACJAPITestCase):
    def setUp(self):
        super(CoursesAPITests, self).setUp()
        self.data = BasicTestData()

    def _verify_course_info(self, course_expected, course_actual):
        self.assertEqual(course_expected.name, course_actual["name"], "Expected course name does not match actual.")
        self.assertEqual(course_expected.id, course_actual["id"], "Expected course id does not match actual.")
        self.assertTrue(course_expected.criteriaandcourses, "Course is missing a criteria")

    def test_get_single_course(self):
        course_api_url = "/api/courses/" + str(self.data.get_course().id)

        # Test login required
        rv = self.client.get(course_api_url)
        self.assert401(rv)

        # Test root get course
        with self.login("root"):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        # Test enroled users get course info
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        with self.login(self.data.get_authorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        # Test unenroled user not permitted to get info
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        with self.login(self.data.get_unauthorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        # Test get invalid course
        with self.login("root"):
            rv = self.client.get("/api/courses/38940450")
            self.assert404(rv)

    def test_get_all_courses(self):
        course_api_url = "/api/courses"

        # Test login required
        rv = self.client.get(course_api_url)
        self.assert401(rv)

        # Test only root can get a list of all courses
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        with self.login(self.data.get_authorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        with self.login("root"):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json["objects"][0])

    def test_create_course(self):
        course_expected = {"name": "ExpectedCourse1", "description": "Test Course One Description Test"}
        # Test login required
        rv = self.client.post("/api/courses", data=json.dumps(course_expected), content_type="application/json")
        self.assert401(rv)
        # Test unauthorized user
        with self.login(self.data.get_authorized_student().username):
            rv = self.client.post("/api/courses", data=json.dumps(course_expected), content_type="application/json")
            self.assert403(rv)

        # Test course creation
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post("/api/courses", data=json.dumps(course_expected), content_type="application/json")
            self.assert200(rv)
            # Verify return
            course_actual = rv.json
            self.assertEqual(course_expected["name"], course_actual["name"])
            self.assertEqual(course_expected["description"], course_actual["description"])

            # Verify the course is created in db
            course_in_db = Courses.query.get(course_actual["id"])
            self.assertEqual(course_in_db.name, course_actual["name"])
            self.assertEqual(course_in_db.description, course_actual["description"])

            # create course with criteria
            course = course_expected.copy()
            course["name"] = "ExpectedCourse2"
            course["criteria"] = [{"id": 1}]
            rv = self.client.post("/api/courses", data=json.dumps(course), content_type="application/json")
            self.assert200(rv)
            course_actual = rv.json

            # Verify the course is created in db
            course_in_db = Courses.query.get(course_actual["id"])
            self.assertEqual(len(course_in_db.criteriaandcourses), 1)
            self.assertEqual(course_in_db.criteriaandcourses[0].criteria_id, course["criteria"][0]["id"])

    def test_create_duplicate_course(self):
        with self.login(self.data.get_authorized_instructor().username):
            course_existing = self.data.get_course()
            course_expected = {"name": course_existing.name, "description": course_existing.description}
            rv = self.client.post("/api/courses", data=json.dumps(course_expected), content_type="application/json")
            self.assert400(rv)

    def test_create_course_with_bad_data_format(self):
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post(
                "/api/courses", data=json.dumps({"description": "d"}), content_type="application/json"
            )
            self.assert400(rv)

    def test_edit_course(self):
        expected = {"id": self.data.get_course().id, "name": "ExpectedCourse", "description": "Test Description"}
        url = "/api/courses/" + str(self.data.get_course().id)

        # test login required
        rv = self.client.post(url, data=json.dumps(expected), content_type="application/json")
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url, data=json.dumps(expected), content_type="application/json")
            self.assert403(rv)

            # test unmatched course id
            rv = self.client.post(
                "/api/courses/" + str(self.data.get_secondary_course().id),
                data=json.dumps(expected),
                content_type="application/json",
            )
            self.assert400(rv)

        with self.login(self.data.get_authorized_instructor().username):
            # test invalid course id
            rv = self.client.post("/api/courses/999", data=json.dumps(expected), content_type="application/json")
            self.assert404(rv)

            # test authorized user
            rv = self.client.post(url, data=json.dumps(expected), content_type="application/json")
            self.assert200(rv)
            db.session.expire_all()
            self.assertEqual(expected["id"], rv.json["id"])
            self.assertEqual(expected["name"], rv.json["name"])
            self.assertEqual(expected["description"], rv.json["description"])

            # test add criteria
            course = expected.copy()
            course["criteria"] = [{"id": 1}]
            rv = self.client.post(url, data=json.dumps(course), content_type="application/json")
            self.assert200(rv)

            db.session.expire_all()
            course_in_db = Courses.query.get(course["id"])
            self.assertEqual(len(course_in_db.criteriaandcourses), 1)
            self.assertEqual(course_in_db.criteriaandcourses[0].criteria_id, course["criteria"][0]["id"])

            # test remove criteria
            rv = self.client.post(url, data=json.dumps(expected), content_type="application/json")
            self.assert200(rv)

            # expire all instances in session and force session to query from db
            db.session.expire_all()
            course_in_db = Courses.query.get(course["id"])
            self.assertEqual(len(course_in_db.criteriaandcourses), 0)
Пример #3
0
class CoursesAPITests(ComPAIRAPITestCase):
    def setUp(self):
        super(CoursesAPITests, self).setUp()
        self.data = BasicTestData()

    def _verify_course_info(self, course_expected, course_actual):
        self.assertEqual(
            course_expected.name, course_actual['name'],
            "Expected course name does not match actual.")
        self.assertEqual(
            course_expected.uuid, course_actual['id'],
            "Expected course id does not match actual.")
        self.assertEqual(
            course_expected.description, course_actual['description'],
            "Expected course description does not match actual.")
        self.assertEqual(
            course_expected.year, course_actual['year'],
            "Expected course description does not match actual.")
        self.assertEqual(
            course_expected.term, course_actual['term'],
            "Expected course description does not match actual.")
        self.assertEqual(
            course_expected.available, course_actual['available'],
            "Expected course availability does not match actual.")

    def test_get_single_course(self):
        course_api_url = '/api/courses/' + self.data.get_course().uuid

        # Test login required
        rv = self.client.get(course_api_url)
        self.assert401(rv)

        # Test root get course
        with self.login('root'):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        # Test enroled users get course info
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        with self.login(self.data.get_authorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        # Test unenroled user not permitted to get info
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        with self.login(self.data.get_unauthorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        # Test get invalid course
        with self.login("root"):
            rv = self.client.get('/api/courses/38940450')
            self.assert404(rv)

    def test_create_course(self):
        course_expected = {
            'name': 'ExpectedCourse1',
            'year': 2015,
            'term': 'Winter',
            'start_date': None,
            'end_date': None,
            'description': 'Test Course One Description Test'
        }
        # Test login required
        rv = self.client.post(
            '/api/courses',
            data=json.dumps(course_expected), content_type='application/json')
        self.assert401(rv)
        # Test unauthorized user
        with self.login(self.data.get_authorized_student().username):
            rv = self.client.post(
                '/api/courses',
                data=json.dumps(course_expected), content_type='application/json')
            self.assert403(rv)

        # Test course creation
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post(
                '/api/courses',
                data=json.dumps(course_expected), content_type='application/json')
            self.assert200(rv)
            # Verify return
            course_actual = rv.json
            self.assertEqual(course_expected['name'], course_actual['name'])
            self.assertEqual(course_expected['year'], course_actual['year'])
            self.assertEqual(course_expected['term'], course_actual['term'])
            self.assertEqual(course_expected['description'], course_actual['description'])
            self.assertTrue(course_actual['available'])

            # Verify the course is created in db
            course_in_db = Course.query.filter_by(uuid=course_actual['id']).first()
            self.assertEqual(course_in_db.name, course_actual['name'])
            self.assertEqual(course_in_db.year, course_actual['year'])
            self.assertEqual(course_in_db.term, course_actual['term'])
            self.assertEqual(course_in_db.description, course_actual['description'])
            self.assertTrue(course_in_db.available)

            # Verify instructor added to course
            user_course = UserCourse.query \
                .filter_by(
                    user_id=self.data.get_authorized_instructor().id,
                    course_uuid=course_actual['id']
                ) \
                .one_or_none()
            self.assertIsNotNone(user_course)

            # Starts in the future
            now = datetime.datetime.utcnow()
            course_expected['start_date'] = (now + datetime.timedelta(days=7)).isoformat() + 'Z',
            course_expected['end_date'] = None
            rv = self.client.post('/api/courses', data=json.dumps(course_expected), content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['available'])

            # Ended in the past
            course_expected['start_date'] = None
            course_expected['end_date'] = (now - datetime.timedelta(days=7)).isoformat() + 'Z',
            rv = self.client.post('/api/courses', data=json.dumps(course_expected), content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['available'])

            # Is currently available
            course_expected['start_date'] = (now - datetime.timedelta(days=7)).isoformat() + 'Z',
            course_expected['end_date'] = (now + datetime.timedelta(days=7)).isoformat() + 'Z',
            rv = self.client.post('/api/courses', data=json.dumps(course_expected), content_type='application/json')
            self.assert200(rv)
            self.assertTrue(rv.json['available'])

    def test_create_course_with_bad_data_format(self):
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post(
                '/api/courses',
                data=json.dumps({'description': 'd'}), content_type='application/json')
            self.assert400(rv)

    def test_edit_course(self):
        expected = {
            'id': self.data.get_course().uuid,
            'name': 'ExpectedCourse',
            'year': 2015,
            'term': 'Winter',
            'start_date': None,
            'end_date': None,
            'description': 'Test Description'
        }
        url = '/api/courses/' + self.data.get_course().uuid

        # test login required
        rv = self.client.post(url, data=json.dumps(expected), content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url, data=json.dumps(expected), content_type='application/json')
            self.assert403(rv)

            # test unmatched course id
            rv = self.client.post(
                '/api/courses/' + self.data.get_secondary_course().uuid,
                data=json.dumps(expected), content_type='application/json')
            self.assert400(rv)

        with self.login(self.data.get_authorized_instructor().username):
            # test invalid course id
            rv = self.client.post('/api/courses/999', data=json.dumps(expected), content_type='application/json')
            self.assert404(rv)

            # test authorized user
            rv = self.client.post(url, data=json.dumps(expected), content_type='application/json')
            self.assert200(rv)
            db.session.expire_all()
            self.assertEqual(expected['id'], rv.json['id'])
            self.assertEqual(expected['name'], rv.json['name'])
            self.assertEqual(expected['description'], rv.json['description'])
            self.assertTrue(rv.json['available'])

            # Starts in the future
            now = datetime.datetime.utcnow()
            expected['start_date'] = (now + datetime.timedelta(days=7)).isoformat() + 'Z',
            expected['end_date'] = None
            rv = self.client.post(url, data=json.dumps(expected), content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['available'])

            # Ended in the past
            expected['start_date'] = None
            expected['end_date'] = (now - datetime.timedelta(days=7)).isoformat() + 'Z',
            rv = self.client.post(url, data=json.dumps(expected), content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['available'])

            # Is currently available
            expected['start_date'] = (now - datetime.timedelta(days=7)).isoformat() + 'Z',
            expected['end_date'] = (now + datetime.timedelta(days=7)).isoformat() + 'Z',
            rv = self.client.post(url, data=json.dumps(expected), content_type='application/json')
            self.assert200(rv)
            self.assertTrue(rv.json['available'])

    def test_delete_course(self):
        course_uuid = self.data.get_course().uuid
        url = '/api/courses/' + course_uuid

        # test login required
        rv = self.client.delete(url)
        self.assert401(rv)

        # test unauthorized users
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.delete(url)
            self.assert403(rv)

        with self.login(self.data.get_authorized_student().username):
            rv = self.client.delete(url)
            self.assert403(rv)

        with self.login(self.data.get_authorized_ta().username):
            rv = self.client.delete(url)
            self.assert403(rv)

        with self.login(self.data.get_authorized_instructor().username):
            # test invalid course id
            rv = self.client.delete('/api/courses/999')
            self.assert404(rv)

            # test deletion by authorized insturctor
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(course_uuid, rv.json['id'])

            # test course is deleted
            rv = self.client.delete(url)
            self.assert404(rv)

        course2 = self.data.create_course()
        url = '/api/courses/' + course2.uuid

        with self.login('root'):
            # test deletion by system admin
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(course2.uuid, rv.json['id'])

            # test course is deleted
            rv = self.client.delete(url)
            self.assert404(rv)


    def test_duplicate_course_simple(self):
        url = '/api/courses/' + self.data.get_course().uuid + '/duplicate'
        expected = {
            'name': 'duplicate course',
            'year': 2015,
            'term': 'Winter',
            'start_date': None,
            'end_date': None
        }
        # test login required
        rv = self.client.post(url, content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url, data=json.dumps(expected), content_type='application/json')
            self.assert403(rv)

        with self.login(self.data.get_authorized_instructor().username):
            # test invalid course id
            rv = self.client.post('/api/courses/999/duplicate', data=json.dumps(expected), content_type='application/json')
            self.assert404(rv)

            # test year missing
            invalid_expected = {
                'term': 'Winter'
            }
            rv = self.client.post('/api/courses/999/duplicate', data=json.dumps(invalid_expected), content_type='application/json')
            self.assert404(rv)

            # test term missing
            invalid_expected = {
                'year': 2015
            }
            rv = self.client.post('/api/courses/999/duplicate', data=json.dumps(invalid_expected), content_type='application/json')
            self.assert404(rv)

            # test authorized user
            original_course = self.data.get_course()
            rv = self.client.post(url, data=json.dumps(expected), content_type='application/json')
            self.assert200(rv)

            # verify course duplicated correctly
            self.assertNotEqual(original_course.uuid, rv.json['id'])
            self.assertEqual(expected['name'], rv.json['name'])
            self.assertEqual(expected['year'], rv.json['year'])
            self.assertEqual(expected['term'], rv.json['term'])
            self.assertEqual(expected['start_date'], rv.json['start_date'])
            self.assertEqual(expected['end_date'], rv.json['end_date'])
            self.assertEqual(original_course.description, rv.json['description'])

            # verify instructor added to duplicate course
            user_course = UserCourse.query \
                .filter_by(
                    user_id=self.data.get_authorized_instructor().id,
                    course_uuid=rv.json['id']
                ) \
                .one_or_none()
            self.assertIsNotNone(user_course)
Пример #4
0
class CoursesAPITests(ComPAIRAPITestCase):
    def setUp(self):
        super(CoursesAPITests, self).setUp()
        self.data = BasicTestData()

    def _verify_course_info(self, course_expected, course_actual):
        self.assertEqual(course_expected.name, course_actual['name'],
                         "Expected course name does not match actual.")
        self.assertEqual(course_expected.uuid, course_actual['id'],
                         "Expected course id does not match actual.")
        self.assertEqual(course_expected.year, course_actual['year'],
                         "Expected course year does not match actual.")
        self.assertEqual(course_expected.term, course_actual['term'],
                         "Expected course term does not match actual.")
        self.assertEqual(
            course_expected.sandbox, course_actual['sandbox'],
            "Expected course sandbox flag does not match actual.")
        self.assertEqual(
            course_expected.available, course_actual['available'],
            "Expected course availability does not match actual.")

    def test_get_single_course(self):
        course_api_url = '/api/courses/' + self.data.get_course().uuid

        # Test login required
        rv = self.client.get(course_api_url)
        self.assert401(rv)

        # Test root get course
        with self.login('root'):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        # Test enroled users get course info
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        with self.login(self.data.get_authorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert200(rv)
            self._verify_course_info(self.data.get_course(), rv.json)

        # Test unenroled user not permitted to get info
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        with self.login(self.data.get_unauthorized_student().username):
            rv = self.client.get(course_api_url)
            self.assert403(rv)

        # Test get invalid course
        with self.login("root"):
            rv = self.client.get('/api/courses/38940450')
            self.assert404(rv)

    def test_create_course(self):
        course_expected = {
            'name': 'ExpectedCourse1',
            'year': 2015,
            'term': 'Winter',
            'sandbox': False,
            'start_date': None,
            'end_date': None
        }
        # Test login required
        rv = self.client.post('/api/courses',
                              data=json.dumps(course_expected),
                              content_type='application/json')
        self.assert401(rv)
        # Test unauthorized user
        with self.login(self.data.get_authorized_student().username):
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course_expected),
                                  content_type='application/json')
            self.assert403(rv)

        # Test course creation
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course_expected),
                                  content_type='application/json')
            self.assert200(rv)
            # Verify return
            course_actual = rv.json
            self.assertEqual(course_expected['name'], course_actual['name'])
            self.assertEqual(course_expected['year'], course_actual['year'])
            self.assertEqual(course_expected['term'], course_actual['term'])
            self.assertEqual(course_expected['sandbox'],
                             course_actual['sandbox'])
            self.assertTrue(course_actual['available'])

            # Verify the course is created in db
            course_in_db = Course.query.filter_by(
                uuid=course_actual['id']).first()
            self.assertEqual(course_in_db.name, course_actual['name'])
            self.assertEqual(course_in_db.year, course_actual['year'])
            self.assertEqual(course_in_db.term, course_actual['term'])
            self.assertEqual(course_in_db.sandbox, course_actual['sandbox'])
            self.assertTrue(course_in_db.available)

            # Verify instructor added to course
            user_course = UserCourse.query \
                .filter_by(
                    user_id=self.data.get_authorized_instructor().id,
                    course_uuid=course_actual['id']
                ) \
                .one_or_none()
            self.assertIsNotNone(user_course)

            # Starts in the future
            now = datetime.datetime.utcnow()
            course_expected['start_date'] = (
                now + datetime.timedelta(days=7)).isoformat() + 'Z',
            course_expected['end_date'] = None
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course_expected),
                                  content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['available'])

            # Ended in the past
            course_expected['start_date'] = None
            course_expected['end_date'] = (
                now - datetime.timedelta(days=7)).isoformat() + 'Z',
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course_expected),
                                  content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['available'])

            # Is currently available
            course_expected['start_date'] = (
                now - datetime.timedelta(days=7)).isoformat() + 'Z',
            course_expected['end_date'] = (
                now + datetime.timedelta(days=7)).isoformat() + 'Z',
            rv = self.client.post('/api/courses',
                                  data=json.dumps(course_expected),
                                  content_type='application/json')
            self.assert200(rv)
            self.assertTrue(rv.json['available'])

    def test_create_course_with_bad_data_format(self):
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post('/api/courses',
                                  data=json.dumps({'year': 'd'}),
                                  content_type='application/json')
            self.assert400(rv)

    def test_edit_course(self):
        expected = {
            'id': self.data.get_course().uuid,
            'name': 'ExpectedCourse',
            'year': 2015,
            'term': 'Winter',
            'sandbox': False,
            'start_date': None,
            'end_date': None
        }
        url = '/api/courses/' + self.data.get_course().uuid

        # test login required
        rv = self.client.post(url,
                              data=json.dumps(expected),
                              content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert403(rv)

            # test unmatched course id
            rv = self.client.post('/api/courses/' +
                                  self.data.get_secondary_course().uuid,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert400(rv)

        with self.login(self.data.get_authorized_instructor().username):
            # test invalid course id
            rv = self.client.post('/api/courses/999',
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert404(rv)

            # test authorized user
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert200(rv)
            db.session.expire_all()
            self.assertEqual(expected['id'], rv.json['id'])
            self.assertEqual(expected['name'], rv.json['name'])
            self.assertTrue(rv.json['available'])

            # Starts in the future
            now = datetime.datetime.utcnow()
            expected['start_date'] = (
                now + datetime.timedelta(days=7)).isoformat() + 'Z',
            expected['end_date'] = None
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['available'])

            # Ended in the past
            expected['start_date'] = None
            expected['end_date'] = (
                now - datetime.timedelta(days=7)).isoformat() + 'Z',
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['available'])

            # Is currently available
            expected['start_date'] = (
                now - datetime.timedelta(days=7)).isoformat() + 'Z',
            expected['end_date'] = (
                now + datetime.timedelta(days=7)).isoformat() + 'Z',
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert200(rv)
            self.assertTrue(rv.json['available'])

    def test_delete_course(self):
        course_uuid = self.data.get_course().uuid
        url = '/api/courses/' + course_uuid

        # test login required
        rv = self.client.delete(url)
        self.assert401(rv)

        # test unauthorized users
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.delete(url)
            self.assert403(rv)

        with self.login(self.data.get_authorized_student().username):
            rv = self.client.delete(url)
            self.assert403(rv)

        with self.login(self.data.get_authorized_ta().username):
            rv = self.client.delete(url)
            self.assert403(rv)

        with self.login(self.data.get_authorized_instructor().username):
            # test invalid course id
            rv = self.client.delete('/api/courses/999')
            self.assert404(rv)

            # test deletion by authorized insturctor
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(course_uuid, rv.json['id'])

            # test course is deleted
            rv = self.client.delete(url)
            self.assert404(rv)

        course2 = self.data.create_course()
        url = '/api/courses/' + course2.uuid

        with self.login('root'):
            # test deletion by system admin
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(course2.uuid, rv.json['id'])

            # test course is deleted
            rv = self.client.delete(url)
            self.assert404(rv)

    def test_duplicate_course_simple(self):
        url = '/api/courses/' + self.data.get_course().uuid + '/duplicate'
        expected = {
            'name': 'duplicate course',
            'year': 2015,
            'term': 'Winter',
            'sandbox': False,
            'start_date': None,
            'end_date': None
        }
        # test login required
        rv = self.client.post(url, content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert403(rv)

        with self.login(self.data.get_authorized_instructor().username):
            # test invalid course id
            rv = self.client.post('/api/courses/999/duplicate',
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert404(rv)

            # test year missing
            invalid_expected = {'term': 'Winter'}
            rv = self.client.post('/api/courses/999/duplicate',
                                  data=json.dumps(invalid_expected),
                                  content_type='application/json')
            self.assert404(rv)

            # test term missing
            invalid_expected = {'year': 2015}
            rv = self.client.post('/api/courses/999/duplicate',
                                  data=json.dumps(invalid_expected),
                                  content_type='application/json')
            self.assert404(rv)

            # test authorized user
            original_course = self.data.get_course()
            rv = self.client.post(url,
                                  data=json.dumps(expected),
                                  content_type='application/json')
            self.assert200(rv)

            # verify course duplicated correctly
            self.assertNotEqual(original_course.uuid, rv.json['id'])
            self.assertEqual(expected['name'], rv.json['name'])
            self.assertEqual(expected['year'], rv.json['year'])
            self.assertEqual(expected['term'], rv.json['term'])
            self.assertEqual(expected['sandbox'], rv.json['sandbox'])
            self.assertEqual(expected['start_date'], rv.json['start_date'])
            self.assertEqual(expected['end_date'], rv.json['end_date'])

            # verify instructor added to duplicate course
            user_course = UserCourse.query \
                .filter_by(
                    user_id=self.data.get_authorized_instructor().id,
                    course_uuid=rv.json['id']
                ) \
                .one_or_none()
            self.assertIsNotNone(user_course)