Coverage for src/gitlabracadabra/tests/vcrfuncs.py: 97%

64 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-10 17:02 +0100

1# 

2# Copyright (C) 2019-2025 Mathieu Parent <math.parent@gmail.com> 

3# 

4# This program is free software: you can redistribute it and/or modify 

5# it under the terms of the GNU Lesser General Public License as published by 

6# the Free Software Foundation, either version 3 of the License, or 

7# (at your option) any later version. 

8# 

9# This program is distributed in the hope that it will be useful, 

10# but WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

12# GNU Lesser General Public License for more details. 

13# 

14# You should have received a copy of the GNU Lesser General Public License 

15# along with this program. If not, see <http://www.gnu.org/licenses/>. 

16 

17import inspect 

18import os 

19import re 

20from base64 import standard_b64decode, standard_b64encode 

21 

22from vcr import VCR 

23from vcr.matchers import body 

24 

25 

26def _gitlabracadabra_func_path_generator(function): 

27 func_file = inspect.getfile(function) 

28 method_name = function.__name__ # test_no_create 

29 instance_name = function.__self__.__class__.__name__ # TestUser 

30 fixture_name = re.sub(r"^Test", r"", instance_name) + "_" + re.sub(r"^test_", r"", method_name) + ".yaml" 

31 return os.path.join( 

32 os.path.dirname(func_file), 

33 "fixtures", 

34 fixture_name, 

35 ) 

36 

37 

38def _gitlabracadabra_uri_matcher(r1, r2): 

39 r1_uri = r1.uri 

40 r2_uri = r2.uri 

41 # Workaround 'all=True' in API calls 

42 # with python-gitlab < 1.8.0 

43 # See https://github.com/python-gitlab/python-gitlab/pull/701 

44 if r1_uri.endswith("all=True"): 44 ↛ 45line 44 didn't jump to line 45 because the condition on line 44 was never true

45 r1_uri = r1_uri[0:-9] 

46 # Ignore host and port 

47 r1_uri = re.sub(r"^https?://[^:/]+(:\d+)?/", "http://localhost/", r1_uri) 

48 r2_uri = re.sub(r"^https?://[^:/]+(:\d+)?/", "http://localhost/", r2_uri) 

49 return r1_uri == r2_uri 

50 

51 

52def _gitlabracadabra_body_matcher(r1, r2): 

53 if r1.method == "POST" and r1.method == r2.method and r1.url == r2.url: 

54 _, _, r1_boundary = r1.headers.get("Content-Type", "").partition("multipart/form-data; boundary=") 

55 _, _, r2_boundary = r2.headers.get("Content-Type", "").partition("multipart/form-data; boundary=") 

56 return ( 

57 r1_boundary and r2_boundary and r1.body.split(r1_boundary.encode()) == r2.body.split(r2_boundary.encode()) 

58 ) 

59 return body(r1, r2) 

60 

61 

62def _gitlabracadabra_headers(headers: dict[str, str]) -> dict[str, str]: 

63 new_headers: dict[str, str] = {} 

64 for header_name, header_value in headers.items(): 

65 if header_name == "Accept" and header_value != "*/*": 

66 header_value = "boilerplate" 

67 if header_name == "Accept-Encoding": 

68 if header_value == "*": 

69 header_value = "gzip, deflate" 

70 elif header_name == "Authorization": 

71 if header_value.startswith("Basic "): 

72 userpass = standard_b64decode(header_value.removeprefix("Basic ")).split(b":") 

73 userpass[1] = b"my-pass" 

74 basic_value = standard_b64encode(b":".join(userpass)).decode("ascii") 

75 header_value = f"Basic {basic_value}" 

76 elif header_value.startswith("Bearer "): 76 ↛ 87line 76 didn't jump to line 87 because the condition on line 76 was always true

77 header_value = "Bearer some-value" 

78 elif header_name == "Content-Length": 

79 header_value = "42" 

80 elif header_name == "Content-Type": 

81 if header_value.startswith("multipart/form-data; boundary="): 

82 header_value = "multipart/form-data; boundary=some-boundary" 

83 elif header_name == "PRIVATE-TOKEN": 

84 header_value = "MY-TOKEN" 

85 elif header_name in {"Content-type", "Cookie", "User-Agent"}: 

86 continue 

87 new_headers[header_name] = header_value 

88 return new_headers 

89 

90 

91def _gitlabracadabra_headers_matcher(r1, r2): 

92 r1_headers = _gitlabracadabra_headers(r1.headers) 

93 r2_headers = _gitlabracadabra_headers(r2.headers) 

94 if r1_headers != r2_headers: 

95 msg = f"{r1_headers} != {r2_headers}" 

96 raise AssertionError(msg) 

97 return r1_headers == r2_headers # compat 

98 

99 

100my_vcr = VCR( 

101 match_on=["method", "gitlabracadabra_uri", "body", "gitlabracadabra_headers"], 

102 func_path_generator=_gitlabracadabra_func_path_generator, 

103 record_mode="none", # change to 'once' or 'new_episodes' 

104 inject_cassette=True, 

105 decode_compressed_response=True, 

106) 

107my_vcr.register_matcher("gitlabracadabra_uri", _gitlabracadabra_uri_matcher) 

108my_vcr.register_matcher("gitlabracadabra_body", _gitlabracadabra_body_matcher) 

109my_vcr.register_matcher("gitlabracadabra_headers", _gitlabracadabra_headers_matcher)