Example #1
0
    def test_delete_prerequisites(self):
        skill_graph = SkillGraph.load()
        src_skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        tgt_skill = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))
        skill_graph.add_prerequisite(tgt_skill.id, src_skill.id)
        skill_graph = SkillGraph.load()
        self.assertEqual(1, len(skill_graph.prerequisites(tgt_skill.id)))

        # delete prerequisite
        actions.login(ADMIN_EMAIL)
        xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(self.XSRF_TOKEN)
        response = self._put(
            version='1',
            name=tgt_skill.name,
            description=tgt_skill.description,
            prerequisite_ids=[],
            xsrf_token=xsrf_token,
            key=tgt_skill.id)

        self.assertEqual(200, response['status'])
        self.assertEqual('Saved.', response['message'])

        skill_graph = SkillGraph.load()
        prerequisites = skill_graph.prerequisites(tgt_skill.id)
        self.assertEqual(0, len(prerequisites))
Example #2
0
    def test_add_prerequisites(self):
        skill_graph = SkillGraph.load()

        src_skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        tgt_skill = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))

        # add a prerequisite
        actions.login(ADMIN_EMAIL)
        xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(self.XSRF_TOKEN)
        response = self._put(
            version='1', name=SKILL_NAME_3,
            description=SKILL_DESC_3,
            prerequisite_ids=[src_skill.id],
            xsrf_token=xsrf_token,
            key=tgt_skill.id)

        self.assertEqual(200, response['status'])
        self.assertEqual('Saved.', response['message'])

        payload = transforms.loads(response['payload'])
        tgt_key = payload['key']

        skill_graph = SkillGraph.load()
        tgt_skill = skill_graph.get(tgt_key)

        self.assertEqual(2, len(skill_graph.skills))
        prerequisites = skill_graph.prerequisites(tgt_key)
        self.assertEqual(1, len(prerequisites))
        self.assertEqual(src_skill.id, prerequisites[0].id)
        self.assertEqual(tgt_skill.name, SKILL_NAME_3)
        self.assertEqual(tgt_skill.description, SKILL_DESC_3)
Example #3
0
    def test_multiple_successors(self):
        skill_graph = SkillGraph.load()

        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))
        skill_3 = skill_graph.add(Skill.build(SKILL_NAME_3, SKILL_DESC_3))

        # Skills 2 and 3 are successors of Skill 1
        skill_graph.add_prerequisite(skill_2.id, skill_1.id)
        skill_graph.add_prerequisite(skill_3.id, skill_1.id)

        skill_graph = SkillGraph.load()
        successor_ids = {s.id for s in skill_graph.successors(skill_1.id)}
        self.assertEqual({skill_2.id, skill_3.id}, successor_ids)
Example #4
0
    def test_get_skill_list(self):
        skill_graph = SkillGraph.load()

        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))
        skill_3 = skill_graph.add(Skill.build(SKILL_NAME_3, SKILL_DESC_3))

        actions.login(ADMIN_EMAIL)
        response = transforms.loads(self.get(self.URL).body)

        self.assertEqual(200, response['status'])
        self.assertIn('xsrf_token', response)

        skill_list = transforms.loads(response['payload'])['skill_list']
        self.assertEqual(3, len(skill_list))

        expected_skill_list = [
            {
                'id': skill_1.id,
                'name': skill_1.name,
                'description': skill_1.description},
            {
                'id': skill_2.id,
                'name': skill_2.name,
                'description': skill_2.description},
            {
                'id': skill_3.id,
                'name': skill_3.name,
                'description': skill_3.description}]
        self.assertEqual(expected_skill_list, skill_list)
Example #5
0
    def test_add_loop_rejected(self):
        """Test that cannot add a skill with a length-1 cycle."""
        skill_graph = SkillGraph.load()

        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))

        with self.assertRaises(AssertionError):
            skill_graph.add_prerequisite(skill_1.id, skill_1.id)
Example #6
0
    def test_add_prerequisite(self):
        skill_graph = SkillGraph.load()

        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))

        # Skill 1 is a prerequisite for Skill 2
        skill_graph.add_prerequisite(skill_2.id, skill_1.id)

        skill_graph = SkillGraph.load()
        self.assertEqual(1, len(skill_graph.prerequisites(skill_2.id)))
        self.assertEqual(
            skill_1.id, skill_graph.prerequisites(skill_2.id)[0].id)

        self.assertEqual(1, len(skill_graph.successors(skill_1.id)))
        self.assertEqual(
            skill_2.id, skill_graph.successors(skill_1.id)[0].id)
Example #7
0
    def test_add_duplicate_prerequisites_rejected(self):
        skill_graph = SkillGraph.load()

        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))

        skill_graph.add_prerequisite(skill_2.id, skill_1.id)
        with self.assertRaises(AssertionError):
            skill_graph.add_prerequisite(skill_2.id, skill_1.id)
Example #8
0
    def test_add_skill_twice_is_rejected(self):
        skill_graph = SkillGraph.load()

        # Add a single skill
        skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        self.assertEqual(1, len(skill_graph.skills))

        # Retrieve the skill by id and add it again
        with self.assertRaises(AssertionError):
            skill_graph.add(skill)
Example #9
0
    def test_delete_prerequisite(self):
        skill_graph = SkillGraph.load()

        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))
        skill_3 = skill_graph.add(Skill.build(SKILL_NAME_3, SKILL_DESC_3))

        # Skills 1 and 2 are prerequisites for Skill 3
        skill_graph.add_prerequisite(skill_3.id, skill_1.id)
        skill_graph.add_prerequisite(skill_3.id, skill_2.id)

        skill_graph = SkillGraph.load()
        self.assertEqual(2, len(skill_graph.prerequisites(skill_3.id)))

        # Delete skill 1 as a prerequisite and expect that only skill 2 is a
        # prerequisite now
        skill_graph.delete_prerequisite(skill_3.id, skill_1.id)

        self.assertEqual(1, len(skill_graph.prerequisites(skill_3.id)))
        self.assertEqual(
            skill_2.id, skill_graph.prerequisites(skill_3.id)[0].id)
Example #10
0
    def test_delete_skill(self):
        # Skill map is initially empty
        skill_graph = SkillGraph.load()
        self.assertEqual(0, len(skill_graph.skills))

        # Add a single skill
        skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        self.assertEqual(1, len(skill_graph.skills))

        # Delete the skill and expect empty
        skill_graph.delete(skill.id)
        self.assertEqual(0, len(skill_graph.skills))
Example #11
0
    def test_add_skill(self):
        # Skill map is initially empty
        skill_graph = SkillGraph.load()
        self.assertEqual(0, len(skill_graph.skills))

        # Add a single skill
        skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        self.assertEqual(1, len(skill_graph.skills))

        # Retrieve the skill by id
        self.assertEqual(SKILL_NAME, skill.name)
        self.assertEqual(SKILL_DESC, skill.description)
Example #12
0
    def test_create_skill(self):
        skill_graph = SkillGraph.load()
        self.assertEqual(0, len(skill_graph.skills))

        actions.login(ADMIN_EMAIL)
        xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(self.XSRF_TOKEN)
        response = self._put(
            version='1', name=SKILL_NAME, description=SKILL_DESC,
            xsrf_token=xsrf_token)
        self.assertEqual(200, response['status'])
        self.assertEqual('Saved.', response['message'])

        payload = transforms.loads(response['payload'])
        key = payload['key']

        skill_graph = SkillGraph.load()
        self.assertEqual(1, len(skill_graph.skills))

        skill = skill_graph.get(key)
        self.assertEqual(key, skill.id)
        self.assertEqual(SKILL_NAME, skill.name)
        self.assertEqual(SKILL_DESC, skill.description)
Example #13
0
    def test_add_missing_prerequisites_rejected(self):
        skill_graph = SkillGraph.load()

        with self.assertRaises(AssertionError):
            skill_graph.add_prerequisite('missing', 'also missing')

        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))

        with self.assertRaises(AssertionError):
            skill_graph.add_prerequisite('missing', skill_1.id)

        with self.assertRaises(AssertionError):
            skill_graph.add_prerequisite(skill_1.id, 'also missing')
Example #14
0
    def test_get_lessons_returns_empty_list_when_no_skills_assigned(self):
        skill_graph = SkillGraph.load()
        skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))

        skill_map = SkillMap.load(self.course)

        # look up lessons by skill id
        lessons = skill_map.get_lessons_for_skill(skill)
        self.assertIsNotNone(lessons)
        self.assertEqual(0, len(lessons))

        # look up lessons by skill
        lessons = skill_map.get_lessons_for_skill(skill)
        self.assertIsNotNone(lessons)
        self.assertEqual(0, len(lessons))
Example #15
0
    def test_topo_sort(self):
        # a
        #  \
        #   d
        #  /  \
        # b    f
        #     /
        # c--e
        skill_graph = SkillGraph.load()
        sa = skill_graph.add(Skill.build('a', ''))
        sb = skill_graph.add(Skill.build('b', ''))
        sd = skill_graph.add(Skill.build('d', ''))
        skill_graph.add_prerequisite(sd.id, sa.id)
        skill_graph.add_prerequisite(sd.id, sb.id)

        sc = skill_graph.add(Skill.build('c', ''))
        se = skill_graph.add(Skill.build('e', ''))
        skill_graph.add_prerequisite(se.id, sc.id)

        sf = skill_graph.add(Skill.build('f', ''))
        skill_graph.add_prerequisite(sf.id, se.id)
        skill_map = SkillMap.load(self.course)
        self.assertEqual(6, len(skill_map.skills()))

        # verify topological co-sets
        expected = {
            0: set([sa.id, sb.id, sc.id]),
            1: set([se.id, sd.id]),
            2: set([sf.id])}
        for ind, co_set in enumerate(skill_map._topo_sort()):
            self.assertEqual(expected[ind], co_set)

        # verify sorting skills by lesson
        expected = ['a', 'b', 'd', 'c', 'e', 'f']
        self.assertEqual(
            expected,
            [s.name for s in skill_map.skills(sort_by='lesson')])

        # verify sorting skills by name
        expected = ['a', 'b', 'c', 'd', 'e', 'f']
        self.assertEqual(
            expected,
            [s.name for s in skill_map.skills(sort_by='name')])

        # verify sorting skills by prerequisites
        expected = ['a', 'b', 'c', 'd', 'e', 'f']
        actual = [s.name for s in skill_map.skills(sort_by='prerequisites')]
        self.assertEqual(expected, actual)
Example #16
0
    def test_skills_table(self):
        skill_graph = SkillGraph.load()
        skill = skill_graph.add(
            Skill.build(name=SKILL_NAME, description=SKILL_DESC))
        response = self.get(self.SKILL_MAP_URL)
        self.assertEqual(200, response.status_int)

        dom = self.parse_html_string(response.body)
        table = dom.find('.//table[@class="skill-map-table"]')
        rows = table.findall('./tbody/tr')
        self.assertEqual(1, len(rows))
        expected_row_data = [skill.name, skill.description, '', '']
        for ind, td in enumerate(rows[0].findall('td')):
            td_text = (''.join(td.itertext())).strip()
            self.assertEqual(expected_row_data[ind], td_text)
        skill_count = table.find('.//span[@class="skill_count"]')
        self.assertEqual('(1)', ''.join(skill_count.itertext()).strip())
Example #17
0
    def test_delete_missing_prerequisites_rejected(self):
        skill_graph = SkillGraph.load()

        with self.assertRaises(AssertionError):
            skill_graph.delete_prerequisite('missing', 'also missing')

        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))

        with self.assertRaises(AssertionError):
            skill_graph.delete_prerequisite('missing', skill_1.id)

        with self.assertRaises(AssertionError):
            skill_graph.delete_prerequisite(skill_1.id, 'also missing')

        # Also reject deletion of a prerequisite if the skill exists but is not
        # currently a prerequisite
        with self.assertRaises(AssertionError):
            skill_graph.delete_prerequisite(skill_1.id, skill_2.id)
Example #18
0
    def test_skills_table_with_prerequisites(self):
        skill_graph = SkillGraph.load()

        src_skill = skill_graph.add(
            Skill.build(name=SKILL_NAME, description=SKILL_DESC))
        tgt_skill = skill_graph.add(
            Skill.build(name=SKILL_NAME_2, description=SKILL_DESC_2))
        skill_graph.add_prerequisite(tgt_skill.id, src_skill.id)

        response = self.get(self.SKILL_MAP_URL)
        self.assertEqual(200, response.status_int)

        dom = self.parse_html_string(response.body)
        table = dom.find('.//table[@class="skill-map-table"]')
        rows = table.findall('./tbody/tr')
        self.assertEqual(2, len(rows))
        expected_row_data = [
            [tgt_skill.name, tgt_skill.description, src_skill.name, ''],
            [src_skill.name, src_skill.description, '', '']]
        for i, row in enumerate(rows):
            for j, td in enumerate(row.findall('td')):
                td_text = (''.join(td.itertext())).strip()
                self.assertEqual(expected_row_data[i][j], td_text)
Example #19
0
    def test_get_lessons_for_skill(self):
        skill_graph = SkillGraph.load()
        skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC))
        skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2))

        # lesson 1 has one skill
        self.lesson1.properties[LESSON_SKILL_LIST_KEY] = [skill_1.id]
        # lesson 2 has no skills
        # lesson 3 has both skills
        self.lesson3.properties[LESSON_SKILL_LIST_KEY] = [
                skill_1.id, skill_2.id]
        self.course.save()

        skill_map = SkillMap.load(self.course)

        lessons = skill_map.get_lessons_for_skill(skill_1)
        self.assertEqual(2, len(lessons))
        self.assertEqual(self.lesson1.lesson_id, lessons[0].lesson_id)
        self.assertEqual(self.lesson3.lesson_id, lessons[1].lesson_id)

        lessons = skill_map.get_lessons_for_skill(skill_2)
        self.assertEqual(1, len(lessons))
        self.assertEqual(self.lesson3.lesson_id, lessons[0].lesson_id)