Contentstack 2.0.1__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {contentstack-2.0.1 → contentstack-2.2.0}/Contentstack.egg-info/PKG-INFO +1 -1
- {contentstack-2.0.1 → contentstack-2.2.0}/Contentstack.egg-info/SOURCES.txt +5 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/PKG-INFO +1 -1
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/__init__.py +1 -1
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/contenttype.py +16 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/entry.py +17 -0
- contentstack-2.2.0/contentstack/globalfields.py +73 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/stack.py +10 -0
- contentstack-2.2.0/contentstack/variants.py +93 -0
- contentstack-2.2.0/tests/test_early_fetch.py +124 -0
- contentstack-2.2.0/tests/test_early_find.py +138 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/tests/test_entry.py +42 -40
- contentstack-2.2.0/tests/test_global_fields.py +98 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/tests/test_live_preview.py +3 -3
- {contentstack-2.0.1 → contentstack-2.2.0}/tests/test_stack.py +8 -5
- {contentstack-2.0.1 → contentstack-2.2.0}/Contentstack.egg-info/dependency_links.txt +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/Contentstack.egg-info/not-zip-safe +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/Contentstack.egg-info/requires.txt +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/Contentstack.egg-info/top_level.txt +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/LICENSE +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/README.md +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/asset.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/assetquery.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/basequery.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/controller.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/deep_merge_lp.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/entryqueryable.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/https_connection.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/image_transform.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/query.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/contentstack/utility.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/setup.cfg +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/setup.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/tests/test_assets.py +0 -0
- {contentstack-2.0.1 → contentstack-2.2.0}/tests/test_query.py +0 -0
|
@@ -16,13 +16,18 @@ contentstack/controller.py
|
|
|
16
16
|
contentstack/deep_merge_lp.py
|
|
17
17
|
contentstack/entry.py
|
|
18
18
|
contentstack/entryqueryable.py
|
|
19
|
+
contentstack/globalfields.py
|
|
19
20
|
contentstack/https_connection.py
|
|
20
21
|
contentstack/image_transform.py
|
|
21
22
|
contentstack/query.py
|
|
22
23
|
contentstack/stack.py
|
|
23
24
|
contentstack/utility.py
|
|
25
|
+
contentstack/variants.py
|
|
24
26
|
tests/test_assets.py
|
|
27
|
+
tests/test_early_fetch.py
|
|
28
|
+
tests/test_early_find.py
|
|
25
29
|
tests/test_entry.py
|
|
30
|
+
tests/test_global_fields.py
|
|
26
31
|
tests/test_live_preview.py
|
|
27
32
|
tests/test_query.py
|
|
28
33
|
tests/test_stack.py
|
|
@@ -22,7 +22,7 @@ __all__ = (
|
|
|
22
22
|
__title__ = 'contentstack-delivery-python'
|
|
23
23
|
__author__ = 'contentstack'
|
|
24
24
|
__status__ = 'debug'
|
|
25
|
-
__version__ = 'v2.0
|
|
25
|
+
__version__ = 'v2.2.0'
|
|
26
26
|
__endpoint__ = 'cdn.contentstack.io'
|
|
27
27
|
__email__ = 'support@contentstack.com'
|
|
28
28
|
__developer_email__ = 'mobile@contentstack.com'
|
|
@@ -13,6 +13,7 @@ from urllib import parse
|
|
|
13
13
|
|
|
14
14
|
from contentstack.entry import Entry
|
|
15
15
|
from contentstack.query import Query
|
|
16
|
+
from contentstack.variants import Variants
|
|
16
17
|
|
|
17
18
|
class ContentType:
|
|
18
19
|
"""
|
|
@@ -118,3 +119,18 @@ class ContentType:
|
|
|
118
119
|
url = f'{endpoint}/content_types?{encoded_params}'
|
|
119
120
|
result = self.http_instance.get(url)
|
|
120
121
|
return result
|
|
122
|
+
|
|
123
|
+
def variants(self, variant_uid: str | list[str], params: dict = None):
|
|
124
|
+
"""
|
|
125
|
+
Fetches the variants of the content type
|
|
126
|
+
:param variant_uid: {str} -- variant_uid
|
|
127
|
+
:return: Entry, so you can chain this call.
|
|
128
|
+
"""
|
|
129
|
+
return Variants(
|
|
130
|
+
http_instance=self.http_instance,
|
|
131
|
+
content_type_uid=self.__content_type_uid,
|
|
132
|
+
entry_uid=None,
|
|
133
|
+
variant_uid=variant_uid,
|
|
134
|
+
params=params,
|
|
135
|
+
logger=None
|
|
136
|
+
)
|
|
@@ -8,6 +8,7 @@ from urllib import parse
|
|
|
8
8
|
|
|
9
9
|
from contentstack.deep_merge_lp import DeepMergeMixin
|
|
10
10
|
from contentstack.entryqueryable import EntryQueryable
|
|
11
|
+
from contentstack.variants import Variants
|
|
11
12
|
|
|
12
13
|
class Entry(EntryQueryable):
|
|
13
14
|
"""
|
|
@@ -222,6 +223,22 @@ class Entry(EntryQueryable):
|
|
|
222
223
|
merged_response = DeepMergeMixin(entry_response, lp_entry).to_dict() # Convert to dictionary
|
|
223
224
|
return merged_response # Now correctly returns a dictionary
|
|
224
225
|
raise ValueError("Missing required keys in live_preview data")
|
|
226
|
+
|
|
227
|
+
def variants(self, variant_uid: str | list[str], params: dict = None):
|
|
228
|
+
"""
|
|
229
|
+
Fetches the variants of the entry
|
|
230
|
+
:param variant_uid: {str} -- variant_uid
|
|
231
|
+
:return: Entry, so you can chain this call.
|
|
232
|
+
"""
|
|
233
|
+
return Variants(
|
|
234
|
+
http_instance=self.http_instance,
|
|
235
|
+
content_type_uid=self.content_type_id,
|
|
236
|
+
entry_uid=self.entry_uid,
|
|
237
|
+
variant_uid=variant_uid,
|
|
238
|
+
params=params,
|
|
239
|
+
logger=self.logger
|
|
240
|
+
)
|
|
241
|
+
|
|
225
242
|
|
|
226
243
|
|
|
227
244
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Global field defines the structure or schema of a page or a section of your web
|
|
3
|
+
or mobile property. To create content for your application, you are required
|
|
4
|
+
to first create a Global field, and then create entries using the
|
|
5
|
+
Global field.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from urllib import parse
|
|
10
|
+
|
|
11
|
+
class GlobalField:
|
|
12
|
+
"""
|
|
13
|
+
Global field defines the structure or schema of a page or a
|
|
14
|
+
section of your web or mobile property. To create
|
|
15
|
+
content for your application, you are required to
|
|
16
|
+
first create a Global field, and then create entries using the
|
|
17
|
+
Global field.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, http_instance, global_field_uid, logger=None):
|
|
21
|
+
self.http_instance = http_instance
|
|
22
|
+
self.__global_field_uid = global_field_uid
|
|
23
|
+
self.local_param = {}
|
|
24
|
+
self.logger = logger or logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def fetch(self):
|
|
28
|
+
"""
|
|
29
|
+
This method is useful to fetch GlobalField of the of the stack.
|
|
30
|
+
:return:dict -- GlobalField response
|
|
31
|
+
------------------------------
|
|
32
|
+
Example:
|
|
33
|
+
|
|
34
|
+
>>> import contentstack
|
|
35
|
+
>>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
|
|
36
|
+
>>> global_field = stack.global_field('global_field_uid')
|
|
37
|
+
>>> some_dict = {'abc':'something'}
|
|
38
|
+
>>> response = global_field.fetch(some_dict)
|
|
39
|
+
------------------------------
|
|
40
|
+
"""
|
|
41
|
+
if self.__global_field_uid is None:
|
|
42
|
+
raise KeyError(
|
|
43
|
+
'global_field_uid can not be None to fetch GlobalField')
|
|
44
|
+
self.local_param['environment'] = self.http_instance.headers['environment']
|
|
45
|
+
uri = f'{self.http_instance.endpoint}/global_fields/{self.__global_field_uid}'
|
|
46
|
+
encoded_params = parse.urlencode(self.local_param)
|
|
47
|
+
url = f'{uri}?{encoded_params}'
|
|
48
|
+
result = self.http_instance.get(url)
|
|
49
|
+
return result
|
|
50
|
+
|
|
51
|
+
def find(self, params=None):
|
|
52
|
+
"""
|
|
53
|
+
This method is useful to fetch GlobalField of the of the stack.
|
|
54
|
+
:param params: dictionary of params
|
|
55
|
+
:return:dict -- GlobalField response
|
|
56
|
+
------------------------------
|
|
57
|
+
Example:
|
|
58
|
+
|
|
59
|
+
>>> import contentstack
|
|
60
|
+
>>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
|
|
61
|
+
>>> global_field = stack.global_field()
|
|
62
|
+
>>> some_dict = {'abc':'something'}
|
|
63
|
+
>>> response = global_field.find(param=some_dict)
|
|
64
|
+
------------------------------
|
|
65
|
+
"""
|
|
66
|
+
self.local_param['environment'] = self.http_instance.headers['environment']
|
|
67
|
+
if params is not None:
|
|
68
|
+
self.local_param.update(params)
|
|
69
|
+
encoded_params = parse.urlencode(self.local_param)
|
|
70
|
+
endpoint = self.http_instance.endpoint
|
|
71
|
+
url = f'{endpoint}/global_fields?{encoded_params}'
|
|
72
|
+
result = self.http_instance.get(url)
|
|
73
|
+
return result
|
|
@@ -6,6 +6,7 @@ from urllib3.util import Retry
|
|
|
6
6
|
from contentstack.asset import Asset
|
|
7
7
|
from contentstack.assetquery import AssetQuery
|
|
8
8
|
from contentstack.contenttype import ContentType
|
|
9
|
+
from contentstack.globalfields import GlobalField
|
|
9
10
|
from contentstack.https_connection import HTTPSConnection
|
|
10
11
|
from contentstack.image_transform import ImageTransform
|
|
11
12
|
|
|
@@ -202,6 +203,15 @@ class Stack:
|
|
|
202
203
|
:return: ContentType
|
|
203
204
|
"""
|
|
204
205
|
return ContentType(self.http_instance, content_type_uid)
|
|
206
|
+
|
|
207
|
+
def global_field(self, global_field_uid=None):
|
|
208
|
+
"""
|
|
209
|
+
Global field defines the structure or schema of a page or a section
|
|
210
|
+
of your web or mobile property.
|
|
211
|
+
param global_field_uid:
|
|
212
|
+
:return: GlobalField
|
|
213
|
+
"""
|
|
214
|
+
return GlobalField(self.http_instance, global_field_uid)
|
|
205
215
|
|
|
206
216
|
def asset(self, uid):
|
|
207
217
|
"""
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from urllib import parse
|
|
3
|
+
|
|
4
|
+
from contentstack.entryqueryable import EntryQueryable
|
|
5
|
+
|
|
6
|
+
class Variants(EntryQueryable):
|
|
7
|
+
"""
|
|
8
|
+
An entry is the actual piece of content that you want to publish.
|
|
9
|
+
Entries can be created for one of the available content types.
|
|
10
|
+
|
|
11
|
+
Entry works with
|
|
12
|
+
version={version_number}
|
|
13
|
+
environment={environment_name}
|
|
14
|
+
locale={locale_code}
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self,
|
|
18
|
+
http_instance=None,
|
|
19
|
+
content_type_uid=None,
|
|
20
|
+
entry_uid=None,
|
|
21
|
+
variant_uid=None,
|
|
22
|
+
params=None,
|
|
23
|
+
logger=None):
|
|
24
|
+
|
|
25
|
+
super().__init__()
|
|
26
|
+
EntryQueryable.__init__(self)
|
|
27
|
+
self.entry_param = {}
|
|
28
|
+
self.http_instance = http_instance
|
|
29
|
+
self.content_type_id = content_type_uid
|
|
30
|
+
self.entry_uid = entry_uid
|
|
31
|
+
self.variant_uid = variant_uid
|
|
32
|
+
self.logger = logger or logging.getLogger(__name__)
|
|
33
|
+
self.entry_param = params or {}
|
|
34
|
+
|
|
35
|
+
def find(self, params=None):
|
|
36
|
+
"""
|
|
37
|
+
find the variants of the entry of a particular content type
|
|
38
|
+
:param self.variant_uid: {str} -- self.variant_uid
|
|
39
|
+
:return: Entry, so you can chain this call.
|
|
40
|
+
"""
|
|
41
|
+
headers = self.http_instance.headers.copy() # Create a local copy of headers
|
|
42
|
+
if isinstance(self.variant_uid, str):
|
|
43
|
+
headers['x-cs-variant-uid'] = self.variant_uid
|
|
44
|
+
elif isinstance(self.variant_uid, list):
|
|
45
|
+
headers['x-cs-variant-uid'] = ','.join(self.variant_uid)
|
|
46
|
+
|
|
47
|
+
if params is not None:
|
|
48
|
+
self.entry_param.update(params)
|
|
49
|
+
encoded_params = parse.urlencode(self.entry_param)
|
|
50
|
+
endpoint = self.http_instance.endpoint
|
|
51
|
+
url = f'{endpoint}/content_types/{self.content_type_id}/entries?{encoded_params}'
|
|
52
|
+
self.http_instance.headers.update(headers)
|
|
53
|
+
result = self.http_instance.get(url)
|
|
54
|
+
self.http_instance.headers.pop('x-cs-variant-uid', None)
|
|
55
|
+
return result
|
|
56
|
+
|
|
57
|
+
def fetch(self, params=None):
|
|
58
|
+
"""
|
|
59
|
+
This method is useful to fetch variant entries of a particular content type and entries of the of the stack.
|
|
60
|
+
:return:dict -- contentType response
|
|
61
|
+
------------------------------
|
|
62
|
+
Example:
|
|
63
|
+
|
|
64
|
+
>>> import contentstack
|
|
65
|
+
>>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
|
|
66
|
+
>>> content_type = stack.content_type('content_type_uid')
|
|
67
|
+
>>> some_dict = {'abc':'something'}
|
|
68
|
+
>>> response = content_type.fetch(some_dict)
|
|
69
|
+
------------------------------
|
|
70
|
+
"""
|
|
71
|
+
"""
|
|
72
|
+
Fetches the variants of the entry
|
|
73
|
+
:param self.variant_uid: {str} -- self.variant_uid
|
|
74
|
+
:return: Entry, so you can chain this call.
|
|
75
|
+
"""
|
|
76
|
+
if self.entry_uid is None:
|
|
77
|
+
raise ValueError("entry_uid is required")
|
|
78
|
+
else:
|
|
79
|
+
headers = self.http_instance.headers.copy() # Create a local copy of headers
|
|
80
|
+
if isinstance(self.variant_uid, str):
|
|
81
|
+
headers['x-cs-variant-uid'] = self.variant_uid
|
|
82
|
+
elif isinstance(self.variant_uid, list):
|
|
83
|
+
headers['x-cs-variant-uid'] = ','.join(self.variant_uid)
|
|
84
|
+
|
|
85
|
+
if params is not None:
|
|
86
|
+
self.entry_param.update(params)
|
|
87
|
+
encoded_params = parse.urlencode(self.entry_param)
|
|
88
|
+
endpoint = self.http_instance.endpoint
|
|
89
|
+
url = f'{endpoint}/content_types/{self.content_type_id}/entries/{self.entry_uid}?{encoded_params}'
|
|
90
|
+
self.http_instance.headers.update(headers)
|
|
91
|
+
result = self.http_instance.get(url)
|
|
92
|
+
self.http_instance.headers.pop('x-cs-variant-uid', None)
|
|
93
|
+
return result
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for GlobalField.fetch method in contentstack.globalfields
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from unittest.mock import MagicMock
|
|
7
|
+
from contentstack.globalfields import GlobalField
|
|
8
|
+
from urllib.parse import urlencode
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def mock_http_instance():
|
|
13
|
+
"""
|
|
14
|
+
Fixture to provide a mock http_instance with required attributes.
|
|
15
|
+
"""
|
|
16
|
+
mock = MagicMock()
|
|
17
|
+
mock.endpoint = "https://api.contentstack.io/v3"
|
|
18
|
+
mock.headers = {"environment": "test_env"}
|
|
19
|
+
mock.get = MagicMock(return_value={"global_field": "data"})
|
|
20
|
+
return mock
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def global_field_uid():
|
|
25
|
+
"""
|
|
26
|
+
Fixture to provide a sample global_field_uid.
|
|
27
|
+
"""
|
|
28
|
+
return "sample_uid"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture
|
|
32
|
+
def global_field(mock_http_instance, global_field_uid):
|
|
33
|
+
"""
|
|
34
|
+
Fixture to provide a GlobalField instance with a mock http_instance and uid.
|
|
35
|
+
"""
|
|
36
|
+
return GlobalField(mock_http_instance, global_field_uid)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TestGlobalFieldFetch:
|
|
40
|
+
# ------------------- Happy Path Tests -------------------
|
|
41
|
+
|
|
42
|
+
def test_fetch_returns_expected_result(self, global_field):
|
|
43
|
+
"""
|
|
44
|
+
Test that fetch returns the result from http_instance.get with correct URL and params.
|
|
45
|
+
"""
|
|
46
|
+
result = global_field.fetch()
|
|
47
|
+
assert result == {"global_field": "data"}
|
|
48
|
+
assert global_field.local_param["environment"] == "test_env"
|
|
49
|
+
expected_params = urlencode({"environment": "test_env"})
|
|
50
|
+
expected_url = f"https://api.contentstack.io/v3/global_fields/sample_uid?{expected_params}"
|
|
51
|
+
global_field.http_instance.get.assert_called_once_with(expected_url)
|
|
52
|
+
|
|
53
|
+
def test_fetch_with_different_environment(self, mock_http_instance, global_field_uid):
|
|
54
|
+
"""
|
|
55
|
+
Test fetch with a different environment value in headers.
|
|
56
|
+
"""
|
|
57
|
+
mock_http_instance.headers["environment"] = "prod_env"
|
|
58
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
59
|
+
result = gf.fetch()
|
|
60
|
+
assert result == {"global_field": "data"}
|
|
61
|
+
expected_params = urlencode({"environment": "prod_env"})
|
|
62
|
+
expected_url = f"https://api.contentstack.io/v3/global_fields/sample_uid?{expected_params}"
|
|
63
|
+
mock_http_instance.get.assert_called_once_with(expected_url)
|
|
64
|
+
|
|
65
|
+
def test_fetch_preserves_existing_local_param(self, global_field):
|
|
66
|
+
"""
|
|
67
|
+
Test that fetch overwrites only the 'environment' key in local_param, preserving others.
|
|
68
|
+
"""
|
|
69
|
+
global_field.local_param = {"foo": "bar"}
|
|
70
|
+
result = global_field.fetch()
|
|
71
|
+
assert result == {"global_field": "data"}
|
|
72
|
+
assert global_field.local_param["foo"] == "bar"
|
|
73
|
+
assert global_field.local_param["environment"] == "test_env"
|
|
74
|
+
expected_params = urlencode({"foo": "bar", "environment": "test_env"})
|
|
75
|
+
expected_url = f"https://api.contentstack.io/v3/global_fields/sample_uid?{expected_params}"
|
|
76
|
+
global_field.http_instance.get.assert_called_once_with(expected_url)
|
|
77
|
+
|
|
78
|
+
# ------------------- Edge Case Tests -------------------
|
|
79
|
+
|
|
80
|
+
def test_fetch_raises_keyerror_when_uid_is_none(self, mock_http_instance):
|
|
81
|
+
"""
|
|
82
|
+
Test that fetch raises KeyError if global_field_uid is None.
|
|
83
|
+
"""
|
|
84
|
+
gf = GlobalField(mock_http_instance, None)
|
|
85
|
+
with pytest.raises(KeyError, match="global_field_uid can not be None"):
|
|
86
|
+
gf.fetch()
|
|
87
|
+
|
|
88
|
+
def test_fetch_raises_keyerror_when_uid_is_explicitly_set_to_none(self, mock_http_instance):
|
|
89
|
+
"""
|
|
90
|
+
Test that fetch raises KeyError if global_field_uid is explicitly set to None after init.
|
|
91
|
+
"""
|
|
92
|
+
gf = GlobalField(mock_http_instance, "not_none")
|
|
93
|
+
gf._GlobalField__global_field_uid = None # forcibly set to None
|
|
94
|
+
with pytest.raises(KeyError, match="global_field_uid can not be None"):
|
|
95
|
+
gf.fetch()
|
|
96
|
+
|
|
97
|
+
def test_fetch_handles_special_characters_in_params(self, global_field):
|
|
98
|
+
"""
|
|
99
|
+
Test that fetch correctly encodes special characters in local_param.
|
|
100
|
+
"""
|
|
101
|
+
global_field.local_param = {"foo": "bar baz", "qux": "a&b"}
|
|
102
|
+
result = global_field.fetch()
|
|
103
|
+
assert result == {"global_field": "data"}
|
|
104
|
+
expected_params = urlencode({"foo": "bar baz", "qux": "a&b", "environment": "test_env"})
|
|
105
|
+
expected_url = f"https://api.contentstack.io/v3/global_fields/sample_uid?{expected_params}"
|
|
106
|
+
global_field.http_instance.get.assert_called_once_with(expected_url)
|
|
107
|
+
|
|
108
|
+
def test_fetch_raises_keyerror_if_environment_header_missing(self, mock_http_instance, global_field_uid):
|
|
109
|
+
"""
|
|
110
|
+
Test that fetch raises KeyError if 'environment' is missing from http_instance.headers.
|
|
111
|
+
"""
|
|
112
|
+
del mock_http_instance.headers["environment"]
|
|
113
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
114
|
+
with pytest.raises(KeyError):
|
|
115
|
+
gf.fetch()
|
|
116
|
+
|
|
117
|
+
def test_fetch_propagates_http_instance_get_exception(self, global_field):
|
|
118
|
+
"""
|
|
119
|
+
Test that fetch propagates exceptions raised by http_instance.get.
|
|
120
|
+
"""
|
|
121
|
+
global_field.http_instance.get.side_effect = RuntimeError("Network error")
|
|
122
|
+
with pytest.raises(RuntimeError, match="Network error"):
|
|
123
|
+
global_field.fetch()
|
|
124
|
+
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# test_globalfields_find.py
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from unittest.mock import MagicMock, patch
|
|
5
|
+
from contentstack.globalfields import GlobalField
|
|
6
|
+
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def mock_http_instance():
|
|
9
|
+
"""
|
|
10
|
+
Fixture to provide a mock http_instance with headers and endpoint.
|
|
11
|
+
"""
|
|
12
|
+
mock = MagicMock()
|
|
13
|
+
mock.headers = {"environment": "test_env"}
|
|
14
|
+
mock.endpoint = "https://api.contentstack.io/v3"
|
|
15
|
+
mock.get = MagicMock(return_value={"global_fields": "data"})
|
|
16
|
+
return mock
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def global_field_uid():
|
|
20
|
+
"""
|
|
21
|
+
Fixture to provide a sample global_field_uid.
|
|
22
|
+
"""
|
|
23
|
+
return "sample_uid"
|
|
24
|
+
|
|
25
|
+
class TestGlobalFieldFind:
|
|
26
|
+
"""
|
|
27
|
+
Unit tests for GlobalField.find method, covering happy paths and edge cases.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# -------------------- Happy Path Tests --------------------
|
|
31
|
+
|
|
32
|
+
def test_find_with_no_params(self, mock_http_instance, global_field_uid):
|
|
33
|
+
"""
|
|
34
|
+
Test that find() with no params returns expected result and constructs correct URL.
|
|
35
|
+
"""
|
|
36
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
37
|
+
result = gf.find()
|
|
38
|
+
assert result == {"global_fields": "data"}
|
|
39
|
+
expected_url = (
|
|
40
|
+
"https://api.contentstack.io/v3/global_fields?environment=test_env"
|
|
41
|
+
)
|
|
42
|
+
mock_http_instance.get.assert_called_once_with(expected_url)
|
|
43
|
+
|
|
44
|
+
def test_find_with_params(self, mock_http_instance, global_field_uid):
|
|
45
|
+
"""
|
|
46
|
+
Test that find() with additional params merges them and encodes URL correctly.
|
|
47
|
+
"""
|
|
48
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
49
|
+
params = {"limit": 10, "skip": 5}
|
|
50
|
+
result = gf.find(params=params)
|
|
51
|
+
# The order of query params in the URL is not guaranteed, so check both possibilities
|
|
52
|
+
called_url = mock_http_instance.get.call_args[0][0]
|
|
53
|
+
assert result == {"global_fields": "data"}
|
|
54
|
+
assert called_url.startswith("https://api.contentstack.io/v3/global_fields?")
|
|
55
|
+
# All params must be present in the URL
|
|
56
|
+
for k, v in {"environment": "test_env", "limit": "10", "skip": "5"}.items():
|
|
57
|
+
assert f"{k}={v}" in called_url
|
|
58
|
+
|
|
59
|
+
def test_find_with_empty_params_dict(self, mock_http_instance, global_field_uid):
|
|
60
|
+
"""
|
|
61
|
+
Test that find() with an empty params dict behaves like no params.
|
|
62
|
+
"""
|
|
63
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
64
|
+
result = gf.find(params={})
|
|
65
|
+
assert result == {"global_fields": "data"}
|
|
66
|
+
expected_url = (
|
|
67
|
+
"https://api.contentstack.io/v3/global_fields?environment=test_env"
|
|
68
|
+
)
|
|
69
|
+
mock_http_instance.get.assert_called_once_with(expected_url)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_find_with_special_characters_in_params(self, mock_http_instance, global_field_uid):
|
|
74
|
+
"""
|
|
75
|
+
Test that find() correctly URL-encodes special characters in params.
|
|
76
|
+
"""
|
|
77
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
78
|
+
params = {"q": "name:foo/bar&baz", "limit": 1}
|
|
79
|
+
result = gf.find(params=params)
|
|
80
|
+
called_url = mock_http_instance.get.call_args[0][0]
|
|
81
|
+
# Check that special characters are URL-encoded
|
|
82
|
+
assert "q=name%3Afoo%2Fbar%26baz" in called_url
|
|
83
|
+
assert "limit=1" in called_url
|
|
84
|
+
assert result == {"global_fields": "data"}
|
|
85
|
+
|
|
86
|
+
def test_find_with_none_environment_in_headers(self, mock_http_instance, global_field_uid):
|
|
87
|
+
"""
|
|
88
|
+
Test that find() handles the case where 'environment' in headers is None.
|
|
89
|
+
"""
|
|
90
|
+
mock_http_instance.headers["environment"] = None
|
|
91
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
92
|
+
result = gf.find()
|
|
93
|
+
called_url = mock_http_instance.get.call_args[0][0]
|
|
94
|
+
# Should include 'environment=None' in the query string
|
|
95
|
+
assert "environment=None" in called_url
|
|
96
|
+
assert result == {"global_fields": "data"}
|
|
97
|
+
|
|
98
|
+
def test_find_with_non_string_param_values(self, mock_http_instance, global_field_uid):
|
|
99
|
+
"""
|
|
100
|
+
Test that find() handles non-string param values (e.g., int, bool, None).
|
|
101
|
+
"""
|
|
102
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
103
|
+
params = {"int_val": 42, "bool_val": True, "none_val": None}
|
|
104
|
+
result = gf.find(params=params)
|
|
105
|
+
called_url = mock_http_instance.get.call_args[0][0]
|
|
106
|
+
# int and bool should be stringified, None should be 'None'
|
|
107
|
+
assert "int_val=42" in called_url
|
|
108
|
+
assert "bool_val=True" in called_url
|
|
109
|
+
assert "none_val=None" in called_url
|
|
110
|
+
assert result == {"global_fields": "data"}
|
|
111
|
+
|
|
112
|
+
def test_find_with_empty_headers(self, global_field_uid):
|
|
113
|
+
"""
|
|
114
|
+
Test that find() raises KeyError if 'environment' is missing from headers.
|
|
115
|
+
"""
|
|
116
|
+
mock_http_instance = MagicMock()
|
|
117
|
+
mock_http_instance.headers = {}
|
|
118
|
+
mock_http_instance.endpoint = "https://api.contentstack.io/v3"
|
|
119
|
+
mock_http_instance.get = MagicMock(return_value={"global_fields": "data"})
|
|
120
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
121
|
+
with pytest.raises(KeyError):
|
|
122
|
+
gf.find()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_find_with_mutable_local_param(self, mock_http_instance, global_field_uid):
|
|
126
|
+
"""
|
|
127
|
+
Test that local_param is updated and persists between calls.
|
|
128
|
+
"""
|
|
129
|
+
gf = GlobalField(mock_http_instance, global_field_uid)
|
|
130
|
+
# First call with a param
|
|
131
|
+
gf.find(params={"foo": "bar"})
|
|
132
|
+
# Second call with a different param
|
|
133
|
+
gf.find(params={"baz": "qux"})
|
|
134
|
+
# local_param should have been updated with the last call's params
|
|
135
|
+
assert gf.local_param["baz"] == "qux"
|
|
136
|
+
assert gf.local_param["environment"] == "test_env"
|
|
137
|
+
# The previous param 'foo' should still be present (since update is cumulative)
|
|
138
|
+
assert gf.local_param["foo"] == "bar"
|
|
@@ -3,12 +3,12 @@ import unittest
|
|
|
3
3
|
import config
|
|
4
4
|
import contentstack
|
|
5
5
|
|
|
6
|
-
_UID = 'blt53ca1231625bdde4'
|
|
7
6
|
API_KEY = config.APIKEY
|
|
8
7
|
DELIVERY_TOKEN = config.DELIVERYTOKEN
|
|
9
8
|
ENVIRONMENT = config.ENVIRONMENT
|
|
10
9
|
HOST = config.HOST
|
|
11
|
-
|
|
10
|
+
FAQ_UID = config.FAQ_UID # Add this in your config.py
|
|
11
|
+
VARIANT_UID = config.VARIANT_UID
|
|
12
12
|
|
|
13
13
|
class TestEntry(unittest.TestCase):
|
|
14
14
|
|
|
@@ -19,69 +19,54 @@ class TestEntry(unittest.TestCase):
|
|
|
19
19
|
query = self.stack.content_type('faq').query()
|
|
20
20
|
result = query.find()
|
|
21
21
|
if result is not None:
|
|
22
|
-
self.
|
|
23
|
-
print(f'the uid is: {
|
|
22
|
+
self.faq_uid = result['entries'][0]['uid']
|
|
23
|
+
print(f'the uid is: {self.faq_uid}')
|
|
24
24
|
|
|
25
25
|
def test_entry_by_UID(self):
|
|
26
|
-
|
|
27
|
-
entry = self.stack.content_type('faq').entry(_UID)
|
|
26
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID)
|
|
28
27
|
result = entry.fetch()
|
|
29
28
|
if result is not None:
|
|
30
|
-
|
|
31
|
-
self.assertEqual(_UID, result['entry']['uid'])
|
|
29
|
+
self.assertEqual(FAQ_UID, result['entry']['uid'])
|
|
32
30
|
|
|
33
31
|
def test_03_entry_environment(self):
|
|
34
|
-
|
|
35
|
-
entry = self.stack.content_type('faq').entry(
|
|
36
|
-
_UID).environment('test')
|
|
32
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).environment('test')
|
|
37
33
|
self.assertEqual("test", entry.http_instance.headers['environment'])
|
|
38
34
|
|
|
39
35
|
def test_04_entry_locale(self):
|
|
40
|
-
|
|
41
|
-
entry = self.stack.content_type('faq').entry(_UID).locale('en-ei')
|
|
36
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).locale('en-ei')
|
|
42
37
|
entry.fetch()
|
|
43
38
|
self.assertEqual('en-ei', entry.entry_param['locale'])
|
|
44
39
|
|
|
45
40
|
def test_05_entry_version(self):
|
|
46
|
-
|
|
47
|
-
entry = self.stack.content_type('faq').entry(_UID).version(3)
|
|
41
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).version(3)
|
|
48
42
|
entry.fetch()
|
|
49
43
|
self.assertEqual(3, entry.entry_param['version'])
|
|
50
44
|
|
|
51
45
|
def test_06_entry_params(self):
|
|
52
|
-
|
|
53
|
-
entry = self.stack.content_type('faq').entry(
|
|
54
|
-
_UID).param('param_key', 'param_value')
|
|
46
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).param('param_key', 'param_value')
|
|
55
47
|
entry.fetch()
|
|
56
48
|
self.assertEqual('param_value', entry.entry_param['param_key'])
|
|
57
49
|
|
|
58
50
|
def test_07_entry_base_only(self):
|
|
59
|
-
|
|
60
|
-
entry = self.stack.content_type(
|
|
61
|
-
'faq').entry(_UID).only('field_UID')
|
|
51
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).only('field_UID')
|
|
62
52
|
entry.fetch()
|
|
63
53
|
self.assertEqual({'environment': 'development',
|
|
64
54
|
'only[BASE][]': 'field_UID'}, entry.entry_param)
|
|
65
55
|
|
|
66
56
|
def test_08_entry_base_excepts(self):
|
|
67
|
-
|
|
68
|
-
entry = self.stack.content_type('faq').entry(
|
|
69
|
-
_UID).excepts('field_UID')
|
|
57
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).excepts('field_UID')
|
|
70
58
|
entry.fetch()
|
|
71
59
|
self.assertEqual({'environment': 'development',
|
|
72
60
|
'except[BASE][]': 'field_UID'}, entry.entry_param)
|
|
73
61
|
|
|
74
62
|
def test_10_entry_base_include_reference_only(self):
|
|
75
|
-
|
|
76
|
-
entry = self.stack.content_type('faq').entry(_UID).only('field1')
|
|
63
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).only('field1')
|
|
77
64
|
entry.fetch()
|
|
78
65
|
self.assertEqual({'environment': 'development', 'only[BASE][]': 'field1'},
|
|
79
66
|
entry.entry_param)
|
|
80
67
|
|
|
81
68
|
def test_11_entry_base_include_reference_excepts(self):
|
|
82
|
-
|
|
83
|
-
entry = self.stack.content_type(
|
|
84
|
-
'faq').entry(_UID).excepts('field1')
|
|
69
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).excepts('field1')
|
|
85
70
|
entry.fetch()
|
|
86
71
|
self.assertEqual({'environment': 'development', 'except[BASE][]': 'field1'},
|
|
87
72
|
entry.entry_param)
|
|
@@ -95,15 +80,13 @@ class TestEntry(unittest.TestCase):
|
|
|
95
80
|
response = _entry.fetch()
|
|
96
81
|
|
|
97
82
|
def test_13_entry_support_include_fallback_unit_test(self):
|
|
98
|
-
|
|
99
|
-
entry = self.stack.content_type('faq').entry(
|
|
100
|
-
_UID).include_fallback()
|
|
83
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).include_fallback()
|
|
101
84
|
self.assertEqual(
|
|
102
85
|
True, entry.entry_param.__contains__('include_fallback'))
|
|
103
86
|
|
|
104
87
|
def test_14_entry_queryable_only(self):
|
|
105
88
|
try:
|
|
106
|
-
entry = self.stack.content_type('faq').entry(
|
|
89
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).only(4)
|
|
107
90
|
result = entry.fetch()
|
|
108
91
|
self.assertEqual(None, result['uid'])
|
|
109
92
|
except KeyError as e:
|
|
@@ -112,7 +95,7 @@ class TestEntry(unittest.TestCase):
|
|
|
112
95
|
|
|
113
96
|
def test_entry_queryable_excepts(self):
|
|
114
97
|
try:
|
|
115
|
-
entry = self.stack.content_type('faq').entry(
|
|
98
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).excepts(4)
|
|
116
99
|
result = entry.fetch()
|
|
117
100
|
self.assertEqual(None, result['uid'])
|
|
118
101
|
except KeyError as e:
|
|
@@ -120,20 +103,17 @@ class TestEntry(unittest.TestCase):
|
|
|
120
103
|
self.assertEqual("Invalid field_UID provided", e.args[0])
|
|
121
104
|
|
|
122
105
|
def test_16_entry_queryable_include_content_type(self):
|
|
123
|
-
entry = self.stack.content_type('faq').entry(
|
|
124
|
-
_UID).include_content_type()
|
|
106
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).include_content_type()
|
|
125
107
|
self.assertEqual({'include_content_type': 'true', 'include_global_field_schema': 'true'},
|
|
126
108
|
entry.entry_queryable_param)
|
|
127
109
|
|
|
128
110
|
def test_reference_content_type_uid(self):
|
|
129
|
-
entry = self.stack.content_type('faq').entry(
|
|
130
|
-
_UID).include_reference_content_type_uid()
|
|
111
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).include_reference_content_type_uid()
|
|
131
112
|
self.assertEqual({'include_reference_content_type_uid': 'true'},
|
|
132
113
|
entry.entry_queryable_param)
|
|
133
114
|
|
|
134
115
|
def test_19_entry_queryable_add_param(self):
|
|
135
|
-
entry = self.stack.content_type('faq').entry(
|
|
136
|
-
_UID).add_param('cms', 'contentstack')
|
|
116
|
+
entry = self.stack.content_type('faq').entry(FAQ_UID).add_param('cms', 'contentstack')
|
|
137
117
|
self.assertEqual({'cms': 'contentstack'}, entry.entry_queryable_param)
|
|
138
118
|
|
|
139
119
|
def test_20_entry_include_fallback(self):
|
|
@@ -154,6 +134,28 @@ class TestEntry(unittest.TestCase):
|
|
|
154
134
|
content_type = self.stack.content_type('faq')
|
|
155
135
|
entry = content_type.entry("878783238783").include_metadata()
|
|
156
136
|
self.assertEqual({'include_metadata': 'true'}, entry.entry_queryable_param)
|
|
137
|
+
|
|
138
|
+
def test_23_content_type_variants(self):
|
|
139
|
+
content_type = self.stack.content_type('faq')
|
|
140
|
+
entry = content_type.variants(VARIANT_UID).find()
|
|
141
|
+
self.assertIn('variants', entry['entries'][0]['publish_details'])
|
|
142
|
+
|
|
143
|
+
def test_24_entry_variants(self):
|
|
144
|
+
content_type = self.stack.content_type('faq')
|
|
145
|
+
entry = content_type.entry(FAQ_UID).variants(VARIANT_UID).fetch()
|
|
146
|
+
self.assertIn('variants', entry['entry']['publish_details'])
|
|
147
|
+
|
|
148
|
+
def test_25_content_type_variants_with_has_hash_variant(self):
|
|
149
|
+
content_type = self.stack.content_type('faq')
|
|
150
|
+
entry = content_type.variants([VARIANT_UID]).find()
|
|
151
|
+
self.assertIn('variants', entry['entries'][0]['publish_details'])
|
|
152
|
+
|
|
153
|
+
def test_25_content_type_entry_variants_with_has_hash_variant(self):
|
|
154
|
+
content_type = self.stack.content_type('faq').entry(FAQ_UID)
|
|
155
|
+
entry = content_type.variants([VARIANT_UID]).fetch()
|
|
156
|
+
self.assertIn('variants', entry['entry']['publish_details'])
|
|
157
|
+
|
|
158
|
+
|
|
157
159
|
|
|
158
160
|
|
|
159
161
|
if __name__ == '__main__':
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# test_globalfields_init.py
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
import logging
|
|
5
|
+
from contentstack.globalfields import GlobalField
|
|
6
|
+
|
|
7
|
+
class DummyHttpInstance:
|
|
8
|
+
"""A dummy HTTP instance for testing purposes."""
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def dummy_http():
|
|
13
|
+
"""Fixture to provide a dummy http_instance."""
|
|
14
|
+
return DummyHttpInstance()
|
|
15
|
+
|
|
16
|
+
@pytest.fixture
|
|
17
|
+
def dummy_logger():
|
|
18
|
+
"""Fixture to provide a dummy logger."""
|
|
19
|
+
return logging.getLogger("dummy_logger")
|
|
20
|
+
|
|
21
|
+
@pytest.mark.usefixtures("dummy_http")
|
|
22
|
+
class TestGlobalFieldInit:
|
|
23
|
+
"""
|
|
24
|
+
Unit tests for GlobalField.__init__ method.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# -------------------- Happy Path Tests --------------------
|
|
28
|
+
|
|
29
|
+
def test_init_with_all_arguments(self, dummy_http, dummy_logger):
|
|
30
|
+
"""
|
|
31
|
+
Test that __init__ correctly assigns all arguments when all are provided.
|
|
32
|
+
"""
|
|
33
|
+
uid = "global_field_123"
|
|
34
|
+
gf = GlobalField(dummy_http, uid, logger=dummy_logger)
|
|
35
|
+
assert gf.http_instance is dummy_http
|
|
36
|
+
# Accessing the private variable via name mangling
|
|
37
|
+
assert gf._GlobalField__global_field_uid == uid
|
|
38
|
+
assert gf.local_param == {}
|
|
39
|
+
assert gf.logger is dummy_logger
|
|
40
|
+
|
|
41
|
+
def test_init_without_logger_uses_default(self, dummy_http):
|
|
42
|
+
"""
|
|
43
|
+
Test that __init__ assigns a default logger if none is provided.
|
|
44
|
+
"""
|
|
45
|
+
uid = "gf_uid"
|
|
46
|
+
gf = GlobalField(dummy_http, uid)
|
|
47
|
+
assert gf.http_instance is dummy_http
|
|
48
|
+
assert gf._GlobalField__global_field_uid == uid
|
|
49
|
+
assert gf.local_param == {}
|
|
50
|
+
# Should be a logger instance, and not None
|
|
51
|
+
assert isinstance(gf.logger, logging.Logger)
|
|
52
|
+
# Should be the logger for the module
|
|
53
|
+
assert gf.logger.name == "contentstack.globalfields"
|
|
54
|
+
|
|
55
|
+
# -------------------- Edge Case Tests --------------------
|
|
56
|
+
|
|
57
|
+
def test_init_with_none_uid(self, dummy_http):
|
|
58
|
+
"""
|
|
59
|
+
Test that __init__ accepts None as global_field_uid.
|
|
60
|
+
"""
|
|
61
|
+
gf = GlobalField(dummy_http, None)
|
|
62
|
+
assert gf._GlobalField__global_field_uid is None
|
|
63
|
+
|
|
64
|
+
def test_init_with_empty_string_uid(self, dummy_http):
|
|
65
|
+
"""
|
|
66
|
+
Test that __init__ accepts empty string as global_field_uid.
|
|
67
|
+
"""
|
|
68
|
+
gf = GlobalField(dummy_http, "")
|
|
69
|
+
assert gf._GlobalField__global_field_uid == ""
|
|
70
|
+
|
|
71
|
+
def test_init_with_non_string_uid(self, dummy_http):
|
|
72
|
+
"""
|
|
73
|
+
Test that __init__ accepts non-string types for global_field_uid.
|
|
74
|
+
"""
|
|
75
|
+
for val in [123, 45.6, {"a": 1}, [1, 2, 3], (4, 5), True, object()]:
|
|
76
|
+
gf = GlobalField(dummy_http, val)
|
|
77
|
+
assert gf._GlobalField__global_field_uid == val
|
|
78
|
+
|
|
79
|
+
def test_init_with_none_http_instance(self):
|
|
80
|
+
"""
|
|
81
|
+
Test that __init__ accepts None as http_instance.
|
|
82
|
+
"""
|
|
83
|
+
uid = "gf_uid"
|
|
84
|
+
gf = GlobalField(None, uid)
|
|
85
|
+
assert gf.http_instance is None
|
|
86
|
+
assert gf._GlobalField__global_field_uid == uid
|
|
87
|
+
|
|
88
|
+
def test_init_with_custom_logger_object(self, dummy_http):
|
|
89
|
+
"""
|
|
90
|
+
Test that __init__ accepts any object as logger.
|
|
91
|
+
"""
|
|
92
|
+
class DummyLogger:
|
|
93
|
+
def info(self, msg): pass
|
|
94
|
+
dummy = DummyLogger()
|
|
95
|
+
gf = GlobalField(dummy_http, "uid", logger=dummy)
|
|
96
|
+
assert gf.logger is dummy
|
|
97
|
+
|
|
98
|
+
|
|
@@ -4,9 +4,9 @@ import config
|
|
|
4
4
|
import contentstack
|
|
5
5
|
from contentstack.deep_merge_lp import DeepMergeMixin
|
|
6
6
|
|
|
7
|
-
management_token =
|
|
8
|
-
entry_uid =
|
|
9
|
-
preview_token =
|
|
7
|
+
management_token = config.MANAGEMENT_TOKEN
|
|
8
|
+
entry_uid = config.LIVE_PREVIEW_ENTRY_UID
|
|
9
|
+
preview_token = config.PREVIEW_TOKEN
|
|
10
10
|
|
|
11
11
|
_lp_query = {
|
|
12
12
|
'live_preview': '#0#0#0#0#0#0#0#0#0#',
|
|
@@ -131,11 +131,14 @@ class TestStack(unittest.TestCase):
|
|
|
131
131
|
self.assertEqual(
|
|
132
132
|
'is not valid.', result['errors']['pagination_token'][0])
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
# Deprecated: This test was skipped due to deprecation of the sync_init feature or its API.
|
|
135
|
+
# If sync_init is permanently removed or unsupported, this test should remain commented or be deleted.
|
|
136
|
+
# If migration or replacement is planned, update this test accordingly.
|
|
137
|
+
# @unittest.skip('Work in progress')
|
|
138
|
+
# def test_16_initialise_sync(self):
|
|
139
|
+
# result = self.stack.sync_init()
|
|
140
|
+
# if result is not None:
|
|
141
|
+
# self.assertEqual(16, result['total_count'])
|
|
139
142
|
|
|
140
143
|
def test_17_entry_with_sync_token(self):
|
|
141
144
|
result = self.stack.sync_token('sync_token')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|