Skip to content

Commit 32d2352

Browse files
committed
add unit tests
1 parent 1553a3e commit 32d2352

File tree

1 file changed

+333
-0
lines changed

1 file changed

+333
-0
lines changed
Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
import json
2+
from hashlib import sha1
3+
4+
from dbt.contracts.project import GitPackage
5+
from dbt.task.deps import _create_sha1_hash
6+
from tests.unit.utils import ContractTestCase
7+
8+
9+
class TestGitPackageEnvVarExclusion(ContractTestCase):
10+
ContractType = GitPackage
11+
12+
def test_git_package_with_exclude_env_vars_from_hash_true(self):
13+
"""Test GitPackage with exclude-env-vars-from-hash set to True"""
14+
dct = {
15+
"git": "https://github.com/user/repo.git",
16+
"revision": "v1.0.0",
17+
"exclude-env-vars-from-hash": True,
18+
}
19+
package = self.ContractType(
20+
git="https://github.com/user/repo.git",
21+
revision="v1.0.0",
22+
exclude_env_vars_from_hash=True,
23+
)
24+
self.assert_from_dict(package, dct)
25+
26+
def test_git_package_with_exclude_env_vars_from_hash_false(self):
27+
"""Test GitPackage with exclude-env-vars-from-hash set to False"""
28+
dct = {
29+
"git": "https://github.com/user/repo.git",
30+
"revision": "v1.0.0",
31+
"exclude-env-vars-from-hash": False,
32+
}
33+
package = self.ContractType(
34+
git="https://github.com/user/repo.git",
35+
revision="v1.0.0",
36+
exclude_env_vars_from_hash=False,
37+
)
38+
self.assert_from_dict(package, dct)
39+
40+
def test_git_package_without_exclude_env_vars_from_hash(self):
41+
"""Test GitPackage without exclude-env-vars-from-hash (default behavior)"""
42+
dct = {
43+
"git": "https://github.com/user/repo.git",
44+
"revision": "v1.0.0",
45+
}
46+
package = self.ContractType(
47+
git="https://github.com/user/repo.git",
48+
revision="v1.0.0",
49+
)
50+
self.assert_from_dict(package, dct)
51+
52+
def test_to_dict_for_hash_excludes_env_vars_when_flag_is_true(self):
53+
"""Test that to_dict_for_hash excludes env vars when exclude_env_vars_from_hash is True"""
54+
# Create a package with unrendered git URL containing env vars
55+
package = GitPackage(
56+
git="https://github.com/${GITHUB_USER}/repo.git",
57+
revision="v1.0.0",
58+
exclude_env_vars_from_hash=True,
59+
unrendered={"git": "https://github.com/${GITHUB_USER}/repo.git"},
60+
)
61+
62+
# Get the dict for hash calculation
63+
hash_dict = package.to_dict_for_hash()
64+
65+
# Should use the unrendered git URL and exclude the flag itself
66+
self.assertEqual(hash_dict["git"], "https://github.com/${GITHUB_USER}/repo.git")
67+
self.assertEqual(hash_dict["revision"], "v1.0.0")
68+
self.assertNotIn("exclude-env-vars-from-hash", hash_dict)
69+
70+
def test_to_dict_for_hash_includes_env_vars_when_flag_is_false(self):
71+
"""Test that to_dict_for_hash includes env vars when exclude_env_vars_from_hash is False"""
72+
# Create a package with rendered git URL
73+
package = GitPackage(
74+
git="https://github.com/actualuser/repo.git",
75+
revision="v1.0.0",
76+
exclude_env_vars_from_hash=False,
77+
unrendered={"git": "https://github.com/${GITHUB_USER}/repo.git"},
78+
)
79+
80+
# Get the dict for hash calculation
81+
hash_dict = package.to_dict_for_hash()
82+
83+
# Should use the rendered git URL and include the flag
84+
self.assertEqual(hash_dict["git"], "https://github.com/actualuser/repo.git")
85+
self.assertEqual(hash_dict["revision"], "v1.0.0")
86+
self.assertEqual(hash_dict["exclude-env-vars-from-hash"], False)
87+
88+
def test_to_dict_for_hash_includes_env_vars_when_flag_is_none(self):
89+
"""Test that to_dict_for_hash includes env vars when exclude_env_vars_from_hash is None (default)"""
90+
# Create a package with rendered git URL
91+
package = GitPackage(
92+
git="https://github.com/actualuser/repo.git",
93+
revision="v1.0.0",
94+
unrendered={"git": "https://github.com/${GITHUB_USER}/repo.git"},
95+
)
96+
97+
# Get the dict for hash calculation (should use regular to_dict)
98+
hash_dict = package.to_dict_for_hash()
99+
100+
# Should use the rendered git URL since flag is None (falsy)
101+
self.assertEqual(hash_dict["git"], "https://github.com/actualuser/repo.git")
102+
self.assertEqual(hash_dict["revision"], "v1.0.0")
103+
self.assertIsNone(hash_dict.get("exclude-env-vars-from-hash"))
104+
105+
def test_hash_calculation_with_exclude_env_vars_true(self):
106+
"""Test that _create_sha1_hash uses to_dict_for_hash when available and excludes env vars"""
107+
# Create two packages: one with env vars resolved, one without
108+
package_with_env_vars = GitPackage(
109+
git="https://github.com/actualuser/repo.git",
110+
revision="v1.0.0",
111+
exclude_env_vars_from_hash=True,
112+
unrendered={"git": "https://github.com/${GITHUB_USER}/repo.git"},
113+
)
114+
115+
package_without_env_vars = GitPackage(
116+
git="https://github.com/differentuser/repo.git",
117+
revision="v1.0.0",
118+
exclude_env_vars_from_hash=True,
119+
unrendered={"git": "https://github.com/${GITHUB_USER}/repo.git"},
120+
)
121+
122+
# Both packages should produce the same hash since they use unrendered URLs
123+
hash1 = _create_sha1_hash([package_with_env_vars])
124+
hash2 = _create_sha1_hash([package_without_env_vars])
125+
126+
self.assertEqual(hash1, hash2, "Hashes should be identical when using unrendered URLs")
127+
128+
def test_hash_calculation_with_exclude_env_vars_false(self):
129+
"""Test that _create_sha1_hash includes env vars when exclude_env_vars_from_hash is False"""
130+
# Create two packages with different resolved git URLs
131+
package1 = GitPackage(
132+
git="https://github.com/user1/repo.git",
133+
revision="v1.0.0",
134+
exclude_env_vars_from_hash=False,
135+
unrendered={"git": "https://github.com/${GITHUB_USER}/repo.git"},
136+
)
137+
138+
package2 = GitPackage(
139+
git="https://github.com/user2/repo.git",
140+
revision="v1.0.0",
141+
exclude_env_vars_from_hash=False,
142+
unrendered={"git": "https://github.com/${GITHUB_USER}/repo.git"},
143+
)
144+
145+
# These packages should produce different hashes since they use rendered URLs
146+
hash1 = _create_sha1_hash([package1])
147+
hash2 = _create_sha1_hash([package2])
148+
149+
self.assertNotEqual(hash1, hash2, "Hashes should be different when using rendered URLs")
150+
151+
def test_hash_calculation_backwards_compatibility(self):
152+
"""Test that packages without to_dict_for_hash method still work (backwards compatibility)"""
153+
154+
# Create a simple mock package without to_dict_for_hash method
155+
class SimplePackage:
156+
def to_dict(self):
157+
return {"git": "https://github.com/user/repo.git", "revision": "v1.0.0"}
158+
159+
simple_package = SimplePackage()
160+
161+
# This should not raise an error and should use to_dict instead
162+
hash_result = _create_sha1_hash([simple_package])
163+
164+
# Verify the hash is calculated correctly
165+
expected_dict = {"git": "https://github.com/user/repo.git", "revision": "v1.0.0"}
166+
expected_str = json.dumps(expected_dict, sort_keys=True)
167+
expected_hash = sha1(expected_str.encode("utf-8")).hexdigest()
168+
169+
self.assertEqual(hash_result, expected_hash)
170+
171+
def test_package_with_subdirectory_and_exclude_env_vars(self):
172+
"""Test GitPackage with subdirectory and exclude-env-vars-from-hash"""
173+
package = GitPackage(
174+
git="https://github.com/actualuser/repo.git",
175+
revision="v1.0.0",
176+
subdirectory="subdir",
177+
exclude_env_vars_from_hash=True,
178+
unrendered={"git": "https://github.com/${GITHUB_USER}/repo.git"},
179+
)
180+
181+
hash_dict = package.to_dict_for_hash()
182+
183+
# Should include subdirectory and use unrendered git URL
184+
self.assertEqual(hash_dict["git"], "https://github.com/${GITHUB_USER}/repo.git")
185+
self.assertEqual(hash_dict["revision"], "v1.0.0")
186+
self.assertEqual(hash_dict["subdirectory"], "subdir")
187+
self.assertNotIn("exclude-env-vars-from-hash", hash_dict)
188+
189+
def test_package_without_unrendered_git_url(self):
190+
"""Test GitPackage with exclude_env_vars_from_hash=True but no unrendered git URL"""
191+
package = GitPackage(
192+
git="https://github.com/user/repo.git",
193+
revision="v1.0.0",
194+
exclude_env_vars_from_hash=True,
195+
# No unrendered dict or git key
196+
)
197+
198+
hash_dict = package.to_dict_for_hash()
199+
200+
# Should use the regular git URL since no unrendered version is available
201+
self.assertEqual(hash_dict["git"], "https://github.com/user/repo.git")
202+
self.assertEqual(hash_dict["revision"], "v1.0.0")
203+
self.assertNotIn("exclude-env-vars-from-hash", hash_dict)
204+
205+
def test_yaml_alias_support(self):
206+
"""Test that the YAML alias 'exclude-env-vars-from-hash' works correctly"""
207+
# Test creating from dict using the alias
208+
dct_with_alias = {
209+
"git": "https://github.com/user/repo.git",
210+
"revision": "v1.0.0",
211+
"exclude-env-vars-from-hash": True,
212+
}
213+
package = GitPackage.from_dict(dct_with_alias)
214+
215+
# The field should be accessible via the Python attribute name
216+
self.assertTrue(package.exclude_env_vars_from_hash)
217+
218+
# Converting back to dict should use the alias
219+
result_dict = package.to_dict()
220+
self.assertIn("exclude-env-vars-from-hash", result_dict)
221+
self.assertTrue(result_dict["exclude-env-vars-from-hash"])
222+
223+
def test_hash_consistency_across_environments(self):
224+
"""Test that packages with same unrendered URLs produce consistent hashes"""
225+
# Simulate packages from different environments with different resolved URLs
226+
package_env1 = GitPackage(
227+
git="https://github.com/user1/repo.git", # Different resolved URLs
228+
revision="v1.0.0",
229+
exclude_env_vars_from_hash=True,
230+
unrendered={
231+
"git": "https://github.com/${GITHUB_USER}/repo.git"
232+
}, # Same unrendered URL
233+
)
234+
235+
package_env2 = GitPackage(
236+
git="https://github.com/user2/repo.git", # Different resolved URLs
237+
revision="v1.0.0",
238+
exclude_env_vars_from_hash=True,
239+
unrendered={
240+
"git": "https://github.com/${GITHUB_USER}/repo.git"
241+
}, # Same unrendered URL
242+
)
243+
244+
# Both should produce the same hash
245+
hash1 = _create_sha1_hash([package_env1])
246+
hash2 = _create_sha1_hash([package_env2])
247+
248+
self.assertEqual(
249+
hash1, hash2, "Packages with same unrendered URLs should have consistent hashes"
250+
)
251+
252+
def test_mixed_package_types_in_hash(self):
253+
"""Test hash calculation with mixed package types (some with to_dict_for_hash, some without)"""
254+
# GitPackage with to_dict_for_hash method
255+
git_package = GitPackage(
256+
git="https://github.com/user/repo.git",
257+
revision="v1.0.0",
258+
exclude_env_vars_from_hash=True,
259+
unrendered={"git": "https://github.com/${USER}/repo.git"},
260+
)
261+
262+
# Mock package without to_dict_for_hash method
263+
class SimplePackage:
264+
def to_dict(self):
265+
return {"tarball": "https://example.com/package.tar.gz", "name": "simple_package"}
266+
267+
simple_package = SimplePackage()
268+
269+
# Should handle mixed package types without error
270+
hash_result = _create_sha1_hash([git_package, simple_package])
271+
272+
# Verify it's a valid SHA1 hash (40 hex characters)
273+
self.assertEqual(len(hash_result), 40)
274+
self.assertTrue(all(c in "0123456789abcdef" for c in hash_result))
275+
276+
def test_empty_unrendered_dict(self):
277+
"""Test GitPackage with exclude_env_vars_from_hash=True but empty unrendered dict"""
278+
package = GitPackage(
279+
git="https://github.com/user/repo.git",
280+
revision="v1.0.0",
281+
exclude_env_vars_from_hash=True,
282+
unrendered={}, # Empty dict, no git key
283+
)
284+
285+
hash_dict = package.to_dict_for_hash()
286+
287+
# Should use the regular git URL since unrendered["git"] doesn't exist
288+
self.assertEqual(hash_dict["git"], "https://github.com/user/repo.git")
289+
self.assertEqual(hash_dict["revision"], "v1.0.0")
290+
self.assertNotIn("exclude-env-vars-from-hash", hash_dict)
291+
292+
def test_real_world_scenario_different_machines(self):
293+
"""Test the real-world scenario where the same package spec results in different hashes on different machines"""
294+
# Simulate the scenario described in the issue:
295+
# Same packages.yml on different machines with different environment variables
296+
297+
# Machine 1: GITHUB_TOKEN=abc123
298+
machine1_package = GitPackage(
299+
git="https://[email protected]/myorg/private-repo.git", # Resolved with env var
300+
revision="v1.0.0",
301+
exclude_env_vars_from_hash=False, # Old behavior - includes env vars in hash
302+
unrendered={"git": "https://${GITHUB_TOKEN}@github.com/myorg/private-repo.git"},
303+
)
304+
305+
# Machine 2: GITHUB_TOKEN=xyz789
306+
machine2_package = GitPackage(
307+
git="https://[email protected]/myorg/private-repo.git", # Resolved with different env var
308+
revision="v1.0.0",
309+
exclude_env_vars_from_hash=False, # Old behavior - includes env vars in hash
310+
unrendered={"git": "https://${GITHUB_TOKEN}@github.com/myorg/private-repo.git"},
311+
)
312+
313+
# With old behavior (exclude_env_vars_from_hash=False), hashes are different
314+
hash1_old = _create_sha1_hash([machine1_package])
315+
hash2_old = _create_sha1_hash([machine2_package])
316+
self.assertNotEqual(
317+
hash1_old, hash2_old, "Old behavior: different env vars cause different hashes"
318+
)
319+
320+
# Now with new behavior (exclude_env_vars_from_hash=True)
321+
machine1_package.exclude_env_vars_from_hash = True
322+
machine2_package.exclude_env_vars_from_hash = True
323+
324+
hash1_new = _create_sha1_hash([machine1_package])
325+
hash2_new = _create_sha1_hash([machine2_package])
326+
self.assertEqual(
327+
hash1_new, hash2_new, "New behavior: same unrendered URLs produce same hashes"
328+
)
329+
330+
# And the new behavior produces different hashes than the old behavior
331+
# (since the flag itself is excluded from the hash)
332+
self.assertNotEqual(hash1_old, hash1_new)
333+
self.assertNotEqual(hash2_old, hash2_new)

0 commit comments

Comments
 (0)