-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathpip_test.rs
250 lines (226 loc) · 11.6 KB
/
pip_test.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
use crate::packaging_tool_versions::PackagingToolVersions;
use crate::tests::{builder, default_build_config, DEFAULT_PYTHON_VERSION};
use indoc::{formatdoc, indoc};
use libcnb_test::{assert_contains, assert_empty, BuildpackReference, PackResult, TestRunner};
#[test]
#[ignore = "integration test"]
fn pip_basic_install_and_cache_reuse() {
let PackagingToolVersions {
pip_version,
setuptools_version,
wheel_version,
} = PackagingToolVersions::default();
let config = default_build_config("tests/fixtures/pip_basic");
TestRunner::default().build(&config, |context| {
assert_empty!(context.pack_stderr);
assert_contains!(
context.pack_stdout,
&formatdoc! {"
[Determining Python version]
No Python version specified, using the current default of Python {DEFAULT_PYTHON_VERSION}.
To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes
[Installing Python and packaging tools]
Installing Python {DEFAULT_PYTHON_VERSION}
Installing pip {pip_version}, setuptools {setuptools_version} and wheel {wheel_version}
[Installing dependencies using Pip]
Running pip install
Collecting typing-extensions==4.7.1 (from -r requirements.txt (line 2))
Downloading typing_extensions-4.7.1-py3-none-any.whl.metadata (3.1 kB)
Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB)
Installing collected packages: typing-extensions
Successfully installed typing-extensions-4.7.1
"}
);
// Check that:
// - Pip is available at runtime too (and not just during the build).
// - The correct versions of pip/setuptools/wheel were installed.
// - Pip uses (via 'PYTHONUSERBASE') the user site-packages in the dependencies
// layer, and so can find the typing-extensions package installed there.
// - The "pip update available" warning is not shown (since it should be suppressed).
// - The system site-packages directory is protected against running 'pip install'
// without having passed '--user'.
let command_output =
context.run_shell_command("pip list && pip install --dry-run typing-extensions");
assert_empty!(command_output.stderr);
assert_contains!(
command_output.stdout,
&formatdoc! {"
Package Version
----------------- -------
pip {pip_version}
setuptools {setuptools_version}
typing_extensions 4.7.1
wheel {wheel_version}
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: typing-extensions in /layers/heroku_python/dependencies/lib/"
}
);
context.rebuild(&config, |rebuild_context| {
assert_empty!(rebuild_context.pack_stderr);
assert_contains!(
rebuild_context.pack_stdout,
&formatdoc! {"
[Determining Python version]
No Python version specified, using the current default of Python {DEFAULT_PYTHON_VERSION}.
To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes
[Installing Python and packaging tools]
Using cached Python {DEFAULT_PYTHON_VERSION}
Using cached pip {pip_version}, setuptools {setuptools_version} and wheel {wheel_version}
[Installing dependencies using Pip]
Using cached pip download/wheel cache
Running pip install
Collecting typing-extensions==4.7.1 (from -r requirements.txt (line 2))
Using cached typing_extensions-4.7.1-py3-none-any.whl.metadata (3.1 kB)
Using cached typing_extensions-4.7.1-py3-none-any.whl (33 kB)
Installing collected packages: typing-extensions
Successfully installed typing-extensions-4.7.1
"}
);
});
});
}
// This tests that:
// - The cached layers are correctly invalidated when Python/other versions change.
// - The layer metadata written by older versions of the buildpack are still compatible.
#[test]
#[ignore = "integration test"]
fn pip_cache_invalidation_with_compatible_metadata() {
let PackagingToolVersions {
pip_version,
setuptools_version,
wheel_version,
} = PackagingToolVersions::default();
let config = default_build_config("tests/fixtures/pip_basic");
TestRunner::default().build(
config.clone().buildpacks([BuildpackReference::Other(
"docker://docker.io/heroku/buildpack-python:0.10.0".to_string(),
)]),
|context| {
context.rebuild(config, |rebuild_context| {
assert_empty!(rebuild_context.pack_stderr);
assert_contains!(
rebuild_context.pack_stdout,
&formatdoc! {"
[Determining Python version]
No Python version specified, using the current default of Python {DEFAULT_PYTHON_VERSION}.
To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes
[Installing Python and packaging tools]
Discarding cache since:
- The Python version has changed from 3.12.3 to {DEFAULT_PYTHON_VERSION}
- The pip version has changed from 24.0 to {pip_version}
- The setuptools version has changed from 69.5.1 to {setuptools_version}
Installing Python {DEFAULT_PYTHON_VERSION}
Installing pip {pip_version}, setuptools {setuptools_version} and wheel {wheel_version}
[Installing dependencies using Pip]
Discarding cached pip download/wheel cache
Running pip install
Collecting typing-extensions==4.7.1 (from -r requirements.txt (line 2))
Downloading typing_extensions-4.7.1-py3-none-any.whl.metadata (3.1 kB)
Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB)
Installing collected packages: typing-extensions
Successfully installed typing-extensions-4.7.1
"}
);
});
},
);
}
// This tests that:
// - The cached layers are correctly invalidated when the layer metadata was incompatible.
// - That a suitable message was output explaining why.
#[test]
#[ignore = "integration test"]
fn pip_cache_invalidation_with_incompatible_metadata() {
// TODO: Enable this test on Heroku-24 the next time there is an incompatible metadata change,
// meaning we can bump the historic buildpack version to one that also supports Ubuntu 24.04.
if builder() == "heroku/builder:24" {
return;
}
let PackagingToolVersions {
pip_version,
setuptools_version,
wheel_version,
} = PackagingToolVersions::default();
let config = default_build_config("tests/fixtures/pip_basic");
TestRunner::default().build(
config.clone().buildpacks([BuildpackReference::Other(
"docker://docker.io/heroku/buildpack-python:0.8.4".to_string(),
)]),
|context| {
context.rebuild(config, |rebuild_context| {
assert_empty!(rebuild_context.pack_stderr);
assert_contains!(
rebuild_context.pack_stdout,
&formatdoc! {"
[Determining Python version]
No Python version specified, using the current default of Python {DEFAULT_PYTHON_VERSION}.
To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes
[Installing Python and packaging tools]
Discarding cache since the buildpack cache format has changed
Installing Python {DEFAULT_PYTHON_VERSION}
Installing pip {pip_version}, setuptools {setuptools_version} and wheel {wheel_version}
[Installing dependencies using Pip]
Discarding cached pip download/wheel cache
Running pip install
Collecting typing-extensions==4.7.1 (from -r requirements.txt (line 2))
Downloading typing_extensions-4.7.1-py3-none-any.whl.metadata (3.1 kB)
Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB)
Installing collected packages: typing-extensions
Successfully installed typing-extensions-4.7.1
"}
);
});
},
);
}
// This tests that:
// - Requirements file env var interpolation works (ie: user-provided env vars have been propagated to pip).
// - Git from the stack image can be found (ie: the system PATH has been correctly propagated to pip).
// - The editable mode repository clone is saved into the dependencies layer not the app dir.
// - Compiling a source distribution package (as opposed to a pre-built wheel) works.
// - The Python headers can be found in the `include/pythonX.Y/` directory of the Python layer.
#[test]
#[ignore = "integration test"]
fn pip_editable_git_compiled() {
TestRunner::default().build(
default_build_config( "tests/fixtures/pip_editable_git_compiled")
.env("WHEEL_PACKAGE_URL", "https://github.com/pypa/wheel"),
|context| {
assert_contains!(
context.pack_stdout,
"Cloning https://github.com/pypa/wheel (to revision 0.40.0) to /layers/heroku_python/dependencies/src/extension-dist"
);
},
);
}
#[test]
#[ignore = "integration test"]
fn pip_install_error() {
TestRunner::default().build(
default_build_config( "tests/fixtures/pip_invalid_requirement")
.expected_pack_result(PackResult::Failure),
|context| {
// Ideally we could test a combined stdout/stderr, however libcnb-test doesn't support this:
// https://github.com/heroku/libcnb.rs/issues/536
assert_contains!(
context.pack_stdout,
indoc! {"
[Installing dependencies using Pip]
Running pip install
"}
);
assert_contains!(
context.pack_stderr,
indoc! {"
ERROR: Invalid requirement: 'an-invalid-requirement!': Expected end or semicolon (after name and no valid version specifier)
an-invalid-requirement!
^ (from line 1 of requirements.txt)
[Error: Unable to install dependencies using pip]
The 'pip install' command to install the application's dependencies from
'requirements.txt' failed (exit status: 1).
See the log output above for more information.
"}
);
},
);
}