|
4 | 4 | RetailCRM API client v5 tests |
5 | 5 | """ |
6 | 6 |
|
7 | | -from urllib.parse import urlencode |
| 7 | +from urllib.parse import urlencode, parse_qs, urlsplit |
8 | 8 | import unittest |
| 9 | +import io |
9 | 10 | import os |
10 | 11 | import retailcrm |
11 | 12 | import pook |
@@ -5823,3 +5824,157 @@ def test_statistic_update(self): |
5823 | 5824 |
|
5824 | 5825 | self.assertTrue(response.is_successful(), True) |
5825 | 5826 | self.assertTrue(response.get_status_code() < 400, True) |
| 5827 | + |
| 5828 | + @pook.on |
| 5829 | + def test_knowledge_base_write_methods(self): |
| 5830 | + cases = [ |
| 5831 | + ('knowledge_base_section_create', ({'name': 'Shipping'},), |
| 5832 | + 'sections/create', 'section', {'name': 'Shipping'}, None), |
| 5833 | + ('knowledge_base_section_edit', (7, {'parentId': 0}), |
| 5834 | + 'sections/7/edit', 'section', {'parentId': 0}, None), |
| 5835 | + ('knowledge_base_section_delete', (7,), |
| 5836 | + 'sections/7/delete', None, None, None), |
| 5837 | + ('knowledge_base_document_create', ({'title': 'Shipping', 'externalId': 'doc-7'},), |
| 5838 | + 'documents/create', 'document', {'title': 'Shipping', 'externalId': 'doc-7'}, None), |
| 5839 | + ('knowledge_base_document_edit', (7, {'content': '', 'availableForCopilot': False, 'sectionId': None}, 'id'), |
| 5840 | + 'documents/7/edit', 'document', {'content': '', 'availableForCopilot': False, 'sectionId': None}, 'id'), |
| 5841 | + ('knowledge_base_document_edit', ('doc-7', {'externalId': None}), |
| 5842 | + 'documents/doc-7/edit', 'document', {'externalId': None}, None), |
| 5843 | + ('knowledge_base_document_delete', (7, 'id'), |
| 5844 | + 'documents/7/delete', None, None, 'id'), |
| 5845 | + ('knowledge_base_document_delete', ('doc-7',), |
| 5846 | + 'documents/doc-7/delete', None, None, None), |
| 5847 | + ] |
| 5848 | + for method, args, path, field, payload, by in cases: |
| 5849 | + with self.subTest(method=method, args=args): |
| 5850 | + parameters = {} |
| 5851 | + if field: |
| 5852 | + parameters[field] = json.dumps(payload) |
| 5853 | + if by: |
| 5854 | + parameters['by'] = by |
| 5855 | + request = (pook.post(os.getenv('RETAILCRM_URL') + '/api/v5/knowledge-base/' + path) |
| 5856 | + .headers({'X-API-KEY': os.getenv('RETAILCRM_KEY')})) |
| 5857 | + if parameters: |
| 5858 | + request.body(urlencode(parameters)) |
| 5859 | + else: |
| 5860 | + request.filter(lambda req, _: not req.body) |
| 5861 | + mock = request.reply(200).headers(self.__header).json({'success': True, 'id': 7}) |
| 5862 | + result = getattr(self.client, method)(*args) |
| 5863 | + self.assertTrue(mock.mock.done) |
| 5864 | + self.assertTrue(result.is_successful()) |
| 5865 | + self.assertEqual(7, result.get_response()['id']) |
| 5866 | + self.assertEqual({}, self.client.parameters) |
| 5867 | + |
| 5868 | + @pook.on |
| 5869 | + def test_knowledge_base_read_methods(self): |
| 5870 | + cases = [ |
| 5871 | + ('knowledge_base_sections', (), 'sections', {}, {'sections': [{'id': 1, 'parentId': None}]}), |
| 5872 | + ('knowledge_base_document', ('doc-7',), 'documents/doc-7', {}, |
| 5873 | + {'document': {'id': 7, 'content': None, 'file': None}}), |
| 5874 | + ('knowledge_base_document', (7, 'id'), 'documents/7', {'by': ['id']}, |
| 5875 | + {'document': {'id': 7, 'file': {'id': 9, 'url': 'https://example.com/file'}}}), |
| 5876 | + ('knowledge_base_documents', ({'ids': [7, 8], 'externalIds': ['doc-7'], 'hasFile': False, |
| 5877 | + 'directOnly': True, 'availableForCopilot': False, |
| 5878 | + 'search': 'Shipping'}, 20, 'opaque+/='), |
| 5879 | + 'documents', {'filter[ids][]': ['7', '8'], |
| 5880 | + 'filter[externalIds][]': ['doc-7'], 'filter[hasFile]': ['0'], |
| 5881 | + 'filter[directOnly]': ['1'], 'filter[availableForCopilot]': ['0'], |
| 5882 | + 'filter[search]': ['Shipping'], 'limit': ['20'], 'cursor': ['opaque+/=']}, |
| 5883 | + {'documents': [{'id': 7, 'content': '# Shipping', 'availableForCopilot': False}]}), |
| 5884 | + ('knowledge_base_documents_history', ({'sinceId': 12, 'documentId': 7, |
| 5885 | + 'startDate': '2026-10-26 10:00:00', |
| 5886 | + 'endDate': '2026-10-26 11:00:00'},), |
| 5887 | + 'documents/history', {'filter[sinceId]': ['12'], 'filter[documentId]': ['7'], |
| 5888 | + 'filter[startDate]': ['2026-10-26 10:00:00'], |
| 5889 | + 'filter[endDate]': ['2026-10-26 11:00:00'], 'limit': ['20'], 'page': ['1']}, |
| 5890 | + {'history': [{'id': 13, 'field': 'section', 'oldValue': None, 'newValue': {'id': 2}}]}), |
| 5891 | + ] |
| 5892 | + for method, args, path, query, body in cases: |
| 5893 | + with self.subTest(method=method, args=args): |
| 5894 | + body = dict(body, success=True) |
| 5895 | + url = os.getenv('RETAILCRM_URL') + '/api/v5/knowledge-base/' + path |
| 5896 | + mock = (pook.get(url).headers({'X-API-KEY': os.getenv('RETAILCRM_KEY')}) |
| 5897 | + .filter(lambda req, _, expected=query: parse_qs(urlsplit(req.rawurl).query) == expected) |
| 5898 | + .reply(200).headers(self.__header).json(body)) |
| 5899 | + result = getattr(self.client, method)(*args) |
| 5900 | + self.assertTrue(mock.mock.done) |
| 5901 | + self.assertEqual(body, result.get_response()) |
| 5902 | + self.assertEqual({}, self.client.parameters) |
| 5903 | + |
| 5904 | + @pook.on |
| 5905 | + def test_knowledge_base_documents_cursor_pagination(self): |
| 5906 | + responses = [ |
| 5907 | + {'success': True, 'documents': [{'id': 7}], 'pagination': {'nextCursor': 'next+/='}}, |
| 5908 | + {'success': True, 'documents': [{'id': 8}], 'pagination': {'nextCursor': ''}}, |
| 5909 | + ] |
| 5910 | + ids, cursor = [], None |
| 5911 | + for body in responses: |
| 5912 | + query = {'limit': 20} |
| 5913 | + if cursor: |
| 5914 | + query['cursor'] = cursor |
| 5915 | + url = os.getenv('RETAILCRM_URL') + '/api/v5/knowledge-base/documents?' + urlencode(query) |
| 5916 | + mock = (pook.get(url).headers({'X-API-KEY': os.getenv('RETAILCRM_KEY')}) |
| 5917 | + .reply(200).headers(self.__header).json(body)) |
| 5918 | + result = self.client.knowledge_base_documents(limit=20, cursor=cursor) |
| 5919 | + self.assertTrue(mock.mock.done) |
| 5920 | + payload = result.get_response() |
| 5921 | + ids.extend(doc['id'] for doc in payload['documents']) |
| 5922 | + cursor = payload['pagination']['nextCursor'] |
| 5923 | + self.assertEqual([7, 8], ids) |
| 5924 | + self.assertEqual('', cursor) |
| 5925 | + |
| 5926 | + @pook.on |
| 5927 | + def test_knowledge_base_file_attachment(self): |
| 5928 | + file = {'id': 9, 'filename': 'manual.pdf', 'attachment': [{'knowledgeBaseDocument': {'id': 7}}]} |
| 5929 | + mock = (pook.post(os.getenv('RETAILCRM_URL') + '/api/v5/files/9/edit') |
| 5930 | + .headers({'X-API-KEY': os.getenv('RETAILCRM_KEY')}) |
| 5931 | + .body(self.dictionaryEncode('file', file)) |
| 5932 | + .reply(200).headers(self.__header).json({'success': True, 'file': file})) |
| 5933 | + result = self.client.files_edit(file) |
| 5934 | + self.assertTrue(mock.mock.done) |
| 5935 | + self.assertEqual(file, result.get_response()['file']) |
| 5936 | + |
| 5937 | + @pook.on |
| 5938 | + def test_knowledge_base_api_errors(self): |
| 5939 | + for status in (400, 403, 404, 500): |
| 5940 | + with self.subTest(status=status): |
| 5941 | + mock = (pook.get(os.getenv('RETAILCRM_URL') + '/api/v5/knowledge-base/documents/missing') |
| 5942 | + .headers({'X-API-KEY': os.getenv('RETAILCRM_KEY')}) |
| 5943 | + .reply(status).headers(self.__header).json({'success': False, 'errorMsg': 'Failure'})) |
| 5944 | + result = self.client.knowledge_base_document('missing') |
| 5945 | + self.assertTrue(mock.mock.done) |
| 5946 | + self.assertFalse(result.is_successful()) |
| 5947 | + self.assertEqual(status, result.get_status_code()) |
| 5948 | + self.assertEqual('Failure', result.get_error_msg()) |
| 5949 | + |
| 5950 | + @pook.on |
| 5951 | + def test_knowledge_base_default_pagination(self): |
| 5952 | + for method in ('knowledge_base_documents', 'knowledge_base_documents_history'): |
| 5953 | + with self.subTest(method=method): |
| 5954 | + path, query = 'documents', {'limit': 20} |
| 5955 | + if method == 'knowledge_base_documents_history': |
| 5956 | + path += '/history' |
| 5957 | + query['page'] = 1 |
| 5958 | + url = os.getenv('RETAILCRM_URL') + '/api/v5/knowledge-base/' + path + '?' + urlencode(query) |
| 5959 | + mock = (pook.get(url).headers({'X-API-KEY': os.getenv('RETAILCRM_KEY')}) |
| 5960 | + .reply(200).headers(self.__header).json({'success': True})) |
| 5961 | + result = getattr(self.client, method)() |
| 5962 | + self.assertTrue(mock.mock.done) |
| 5963 | + self.assertTrue(result.is_successful()) |
| 5964 | + self.assertEqual({}, self.client.parameters) |
| 5965 | + |
| 5966 | + @pook.on |
| 5967 | + def test_files_upload_original_file(self): |
| 5968 | + for content in (b'original bytes', io.BytesIO(b'original bytes')): |
| 5969 | + with self.subTest(content=type(content).__name__): |
| 5970 | + mock = (pook.post(os.getenv('RETAILCRM_URL') + '/api/v5/files/upload') |
| 5971 | + .headers({'X-API-KEY': os.getenv('RETAILCRM_KEY'), |
| 5972 | + 'Content-Type': 'application/octet-stream'}) |
| 5973 | + .filter(lambda req, _: (req.body.getvalue().decode() |
| 5974 | + if hasattr(req.body, 'getvalue') else req.body) == 'original bytes') |
| 5975 | + .reply(201).headers(self.__header).json({'success': True, 'file': {'id': 9}})) |
| 5976 | + result = self.client.files_upload(content) |
| 5977 | + self.assertTrue(mock.mock.done) |
| 5978 | + self.assertTrue(result.is_successful()) |
| 5979 | + self.assertEqual(9, result.get_response()['file']['id']) |
| 5980 | + self.assertEqual({}, self.client.parameters) |
0 commit comments