-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathinstall_command_docker_integration.rs
More file actions
260 lines (223 loc) · 7.95 KB
/
Copy pathinstall_command_docker_integration.rs
File metadata and controls
260 lines (223 loc) · 7.95 KB
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
251
252
253
254
255
256
257
258
259
260
//! Integration tests for the dependency-installer install command using Docker containers.
//!
//! These tests verify that the CLI binary can successfully install dependencies
//! in a clean Ubuntu 24.04 environment. They use testcontainers to spin up
//! isolated Docker containers.
use std::path::PathBuf;
mod containers;
use containers::ubuntu_container_builder::UbuntuContainerBuilder;
// ============================================================================
// NOTE: LXD Installer Test Not Included
// ============================================================================
//
// LXD installation via snap requires systemd to be running in the container,
// which is not available in standard Docker containers. To properly test LXD
// installation in a containerized environment, one would need:
//
// 1. A Docker image configured with systemd support
// 2. Running the container in privileged mode with systemd as init process
// 3. Additional container security capabilities
//
// This level of complexity goes beyond the scope of these integration tests.
// The LXD installer has been manually verified to work on real Ubuntu systems.
//
// For future maintainers: If you need to add LXD testing, consider:
// - Using a VM-based testing approach (e.g., with vagrant or multipass)
// - Creating a specialized Docker image with systemd support
// - Adding the test to a separate test suite that runs in VMs
/// Test that `cargo-machete` can be installed
#[tokio::test]
async fn it_should_install_cargo_machete_successfully() {
// Get the binary path (built by cargo before running tests)
let binary_path = get_binary_path();
// Start Ubuntu container with the binary
// Note: Container uses pre-built image with Rust nightly, sudo, and build tools
let container = UbuntuContainerBuilder::new(&binary_path).start().await;
// Install cargo-machete
let exit_code = container.exec_with_exit_code(&[
"dependency-installer",
"install",
"--dependency",
"cargo-machete",
"--log-level",
"off",
]);
// Verify installation succeeded via exit code
assert_eq!(
exit_code, 0,
"cargo-machete installation should succeed (exit code 0)"
);
// Verify the dependency is now installed
let exit_code = container.exec_with_exit_code(&[
"dependency-installer",
"check",
"--dependency",
"cargo-machete",
"--log-level",
"off",
]);
assert_eq!(
exit_code, 0,
"cargo-machete should be detected as installed after installation"
);
}
/// Test that installation is idempotent (can run multiple times)
#[tokio::test]
async fn it_should_handle_idempotent_installation_of_cargo_machete() {
let binary_path = get_binary_path();
let container = UbuntuContainerBuilder::new(&binary_path).start().await;
// Note: Container uses pre-built image with Rust nightly, sudo, and build tools
// Install cargo-machete first time
let exit_code1 = container.exec_with_exit_code(&[
"dependency-installer",
"install",
"--dependency",
"cargo-machete",
"--log-level",
"off",
]);
assert_eq!(
exit_code1, 0,
"First cargo-machete installation should succeed (exit code 0)"
);
// Install cargo-machete second time (should not fail - idempotent)
let exit_code2 = container.exec_with_exit_code(&[
"dependency-installer",
"install",
"--dependency",
"cargo-machete",
"--log-level",
"off",
]);
// Second installation should also succeed (idempotent behavior)
assert_eq!(
exit_code2, 0,
"Second cargo-machete installation should succeed (exit code 0) - idempotent behavior"
);
}
/// Test that `OpenTofu` can be installed
#[tokio::test]
async fn it_should_install_opentofu_successfully() {
let binary_path = get_binary_path();
let container = UbuntuContainerBuilder::new(&binary_path).start().await;
// Install OpenTofu
let exit_code = container.exec_with_exit_code(&[
"dependency-installer",
"install",
"--dependency",
"opentofu",
"--log-level",
"off",
]);
// Verify installation succeeded via exit code
assert_eq!(
exit_code, 0,
"OpenTofu installation should succeed (exit code 0)"
);
// Verify the dependency is now installed
let exit_code = container.exec_with_exit_code(&[
"dependency-installer",
"check",
"--dependency",
"opentofu",
"--log-level",
"off",
]);
assert_eq!(
exit_code, 0,
"OpenTofu should be detected as installed after installation"
);
}
/// Test that `Ansible` can be installed
#[tokio::test]
async fn it_should_install_ansible_successfully() {
let binary_path = get_binary_path();
let container = UbuntuContainerBuilder::new(&binary_path).start().await;
// Install Ansible
let exit_code = container.exec_with_exit_code(&[
"dependency-installer",
"install",
"--dependency",
"ansible",
"--log-level",
"off",
]);
// Verify installation succeeded via exit code
assert_eq!(
exit_code, 0,
"Ansible installation should succeed (exit code 0)"
);
// Verify the dependency is now installed
let exit_code = container.exec_with_exit_code(&[
"dependency-installer",
"check",
"--dependency",
"ansible",
"--log-level",
"off",
]);
assert_eq!(
exit_code, 0,
"Ansible should be detected as installed after installation"
);
}
/// Test that install command returns proper exit code on failure
///
/// Note: This test uses `exec_with_exit_code_silent` to suppress the expected
/// error output, keeping test output clean while still validating the exit code.
#[tokio::test]
async fn it_should_return_error_exit_code_when_installation_fails() {
let binary_path = get_binary_path();
let container = UbuntuContainerBuilder::new(&binary_path).start().await;
// Try to install an invalid/unknown dependency (should fail)
// Use silent execution to avoid error noise in test output
let exit_code = container.exec_with_exit_code_silent(&[
"dependency-installer",
"install",
"--dependency",
"invalid-dependency-name",
"--log-level",
"off",
]);
assert_ne!(
exit_code, 0,
"install command should exit with non-zero code when installation fails"
);
}
/// Get the path to the compiled binary
///
/// This function assumes the binary was built before running tests.
/// Run `cargo build --bin dependency-installer` before running these tests.
///
/// # Implementation Note
///
/// We use `CARGO_MANIFEST_DIR` and navigate up to the workspace root, then into
/// the target directory. This works because:
/// 1. `CARGO_MANIFEST_DIR` points to packages/dependency-installer
/// 2. The workspace root is two directories up
/// 3. The target directory is in the workspace root
///
/// Alternative approaches considered:
/// - `CARGO_TARGET_DIR`: Not always set
/// - `OUT_DIR`: Points to build script output, not target/debug
/// - Searching for target dir: Too expensive
fn get_binary_path() -> PathBuf {
// Get the package manifest directory (packages/dependency-installer)
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
// Navigate to workspace root (two levels up from packages/dependency-installer)
let workspace_root = manifest_dir
.parent() // packages/
.and_then(|p| p.parent()) // workspace root
.expect("Failed to find workspace root");
// Build path to the binary in target/debug
let path = workspace_root
.join("target")
.join("debug")
.join("dependency-installer");
assert!(
path.exists(),
"Binary not found at {}. Run 'cargo build --bin dependency-installer' first",
path.display()
);
path
}