|
| 1 | +import base64 |
| 2 | +import os.path |
| 3 | +import shutil |
| 4 | +import tempfile |
| 5 | + |
| 6 | +from flask.testing import FlaskClient |
| 7 | + |
| 8 | +from lms.lmsdb import models |
| 9 | +from lms.lmsweb import config, webapp |
| 10 | +from tests import conftest |
| 11 | + |
| 12 | + |
| 13 | +POST_NEW_REPOSITORY_BUFFER = \ |
| 14 | + b'00ab0000000000000000000000000000000000000000 ' \ |
| 15 | + b'c1d42352fc88ae88fde7713c23232d7d0703849a refs/heads/master\x00 ' \ |
| 16 | + b'report-status-v2 side-band-64k object-format=sha1 ' \ |
| 17 | + b'agent=git/2.30.10000PACK\x00\x00\x00\x02\x00\x00\x00\x03\x9d\nx' \ |
| 18 | + b'\x9c\x95\xccA\n\xc3 \x10@\xd1\xbd\xa7p_(3\x8e\x9a\x04J\xe8\xae' \ |
| 19 | + b'\x07\xe8\t\xa6\x99\xd1\n\x9a\x80\xd8\xfb7\xd0\x13t\xfb\xe1\xfd' \ |
| 20 | + b'\xd1U\xed$@\xc2\x92\x92\xdf\xd2\x1c\xf1\x15@\x84=\x12\xba\xa4' \ |
| 21 | + b'\xea\xe6e\x89\x88\x12\x12\x1a\xfe\x8c\xf7\xd1\xed\x83\xab}\x96=k' \ |
| 22 | + b'\xb7\xb7\xcc\xd5\x93\xbb\xe7\xc6\xa5^\xb7\xa3\xad\x16#\x91\x9b' \ |
| 23 | + b'\xc0\x07\xb2\x17 \x00s\xd6V\xc6\xd0\xbf\xa1){)\xe34\xbf\x83\xf9' \ |
| 24 | + b'\x02\xa5\x1f3_\xa0\x02x\x9c340031Q(\xc8,Id(M^\xc86;\xe0\xd1\x1d' \ |
| 25 | + b'\xefZ\x8bP\x17\x8eU\xd2\x17\xcb\xb6\xc6\x01\x00\xab:\x0b\xe64x' \ |
| 26 | + b'\x9c+O\xcc\xe6\x02\x00\x03\xe3\x01NvHX\x85>M\xf7I\xd6\x7fGZ' \ |
| 27 | + b'\x0e^\xc8\x82Q\xe3\xcb\xd9' |
| 28 | + |
| 29 | + |
| 30 | +POST_CLONE_REPOSITORY_BUFFER = \ |
| 31 | + b'0098want c1d42352fc88ae88fde7713c23232d7d0703849a multi_ack_detailed' \ |
| 32 | + b' no-done side-band-64k thin-pack ofs-delta deepen-since deepen-not' \ |
| 33 | + b' agent=git/2.30.1\n00000009done\n' |
| 34 | + |
| 35 | + |
| 36 | +class TestSendSolutionFromGit: |
| 37 | + INFO_URL = 'info/refs' |
| 38 | + GET_METHOD = FlaskClient.get.__name__ |
| 39 | + POST_METHOD = FlaskClient.post.__name__ |
| 40 | + |
| 41 | + temp_folder = None |
| 42 | + |
| 43 | + @classmethod |
| 44 | + def setup_class(cls): |
| 45 | + cls.temp_folder = tempfile.mkdtemp() |
| 46 | + |
| 47 | + def setup_method(self, method): |
| 48 | + config._REPOSITORY_FOLDER = os.path.join(self.temp_folder, method.__name__) |
| 49 | + |
| 50 | + @classmethod |
| 51 | + def teardown_class(cls): |
| 52 | + if cls.temp_folder and os.path.exists(cls.temp_folder): |
| 53 | + shutil.rmtree(cls.temp_folder) |
| 54 | + |
| 55 | + @staticmethod |
| 56 | + def _get_formatted_git_url(exercise: models.Exercise, rel_path: str) -> str: |
| 57 | + return f'/git/{exercise.id}.git/{rel_path}' |
| 58 | + |
| 59 | + @staticmethod |
| 60 | + def _send_git_request( |
| 61 | + username: str, |
| 62 | + method_name: str, |
| 63 | + url: str, |
| 64 | + data=None, |
| 65 | + service=None, |
| 66 | + password=conftest.FAKE_PASSWORD, |
| 67 | + ): |
| 68 | + client = webapp.test_client() |
| 69 | + encoded_credentials = base64.b64encode(f'{username}:{password}'.encode()).decode() |
| 70 | + headers = ( |
| 71 | + ('Authorization', f'Basic {encoded_credentials}'), |
| 72 | + ) |
| 73 | + query_string = None |
| 74 | + if service is not None: |
| 75 | + query_string = {'service': service} |
| 76 | + return getattr(client, method_name)(url, query_string=query_string, headers=headers, data=data) |
| 77 | + |
| 78 | + def test_not_authorized_access(self, exercise: models.Exercise, student_user: models.User): |
| 79 | + client = conftest.get_logged_user(student_user.username) |
| 80 | + response = client.get(self._get_formatted_git_url(exercise, self.INFO_URL)) |
| 81 | + assert response.status_code == 401 |
| 82 | + |
| 83 | + def test_not_existing_user(self, exercise: models.Exercise): |
| 84 | + response = self._send_git_request( |
| 85 | + username='not-exists', |
| 86 | + method_name=self.GET_METHOD, |
| 87 | + url=self._get_formatted_git_url(exercise, self.INFO_URL), |
| 88 | + ) |
| 89 | + assert response.status_code == 401 |
| 90 | + |
| 91 | + def test_invalid_user_password(self, exercise: models.Exercise, student_user: models.User): |
| 92 | + response = self._send_git_request( |
| 93 | + username=student_user.username, |
| 94 | + method_name=self.GET_METHOD, |
| 95 | + url=self._get_formatted_git_url(exercise, self.INFO_URL), |
| 96 | + password='not real password' |
| 97 | + ) |
| 98 | + assert response.status_code == 401 |
| 99 | + |
| 100 | + def test_push_exercise(self, exercise: models.Exercise, student_user: models.User): |
| 101 | + git_receive_pack = 'git-receive-pack' |
| 102 | + response = self._send_git_request( |
| 103 | + username=student_user.username, |
| 104 | + method_name=self.GET_METHOD, |
| 105 | + url=self._get_formatted_git_url(exercise, self.INFO_URL), |
| 106 | + service=git_receive_pack, |
| 107 | + ) |
| 108 | + |
| 109 | + assert response.status_code == 200 |
| 110 | + assert response.data.startswith(b'001f#') |
| 111 | + |
| 112 | + response = self._send_git_request( |
| 113 | + username=student_user.username, |
| 114 | + method_name=self.POST_METHOD, |
| 115 | + url=self._get_formatted_git_url(exercise, git_receive_pack), |
| 116 | + data=POST_NEW_REPOSITORY_BUFFER, |
| 117 | + ) |
| 118 | + assert response.status_code == 200 |
| 119 | + assert response.data.startswith(b'0030\x01000eunpack ok\n0019ok refs/heads/master\n00000000') |
| 120 | + |
| 121 | + def test_get_exercise(self, exercise: models.Exercise, student_user: models.User): |
| 122 | + git_upload_pack = 'git-upload-pack' |
| 123 | + self.test_push_exercise(exercise, student_user) |
| 124 | + response = self._send_git_request( |
| 125 | + username=student_user.username, |
| 126 | + method_name=self.GET_METHOD, |
| 127 | + url=self._get_formatted_git_url(exercise, self.INFO_URL), |
| 128 | + service=git_upload_pack, |
| 129 | + ) |
| 130 | + assert response.status_code == 200 |
| 131 | + assert response.data.startswith(b'001e# service=git-upload-pack') |
| 132 | + |
| 133 | + response = self._send_git_request( |
| 134 | + username=student_user.username, |
| 135 | + method_name=self.POST_METHOD, |
| 136 | + url=self._get_formatted_git_url(exercise, git_upload_pack), |
| 137 | + data=POST_CLONE_REPOSITORY_BUFFER, |
| 138 | + ) |
| 139 | + assert response.status_code == 200 |
| 140 | + assert response.data.startswith(b'0008NAK\n0023\x02Enumerating objects: 3, done.') |
0 commit comments