Skip to content

Commit c02c4d9

Browse files
authored
feat: Add offline token creation test (#26771)
This commit adds an offline token creation test. We did not have this as part of the 3.4 test in the interest of time. This adds automated testing to make sure the flow we expect happens which includes: - Ability to create admin tokens via the CLI - Token creation on startup - Database creation on start With this we can be more confident that the feature works as expected and that other changes that might affect it have regression coverage.
1 parent a47967b commit c02c4d9

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

influxdb3/tests/cli/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod admin_token;
22
mod api;
33
mod db_retention;
4+
mod offline_tokens;
45

56
use crate::server::{ConfigProvider, TestServer};
67
use assert_cmd::Command as AssertCmd;
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use tempfile::TempDir;
2+
use test_helpers::assert_contains;
3+
4+
use crate::cli::api::run_cmd_with_result;
5+
use crate::server::{ConfigProvider, TestServer};
6+
use reqwest::StatusCode;
7+
use serde_json::Value;
8+
9+
#[test_log::test(tokio::test)]
10+
async fn test_offline_token_creation_flow() {
11+
// Create temporary directory for token files
12+
let temp_dir = TempDir::new().unwrap();
13+
let admin_token_file = temp_dir.path().join("admin_token.json");
14+
15+
// Step 1: Create offline admin token using CLI
16+
println!("Creating offline admin token...");
17+
let result = run_cmd_with_result(
18+
&[],
19+
None,
20+
vec![
21+
"create",
22+
"token",
23+
"--admin",
24+
"--offline",
25+
"--output-file",
26+
admin_token_file.to_str().unwrap(),
27+
],
28+
)
29+
.unwrap();
30+
println!("Admin token creation result: {}", result);
31+
assert_contains!(&result, "Token saved to:");
32+
33+
// Parse admin token from file
34+
let admin_token_content = std::fs::read_to_string(&admin_token_file).unwrap();
35+
let admin_token_json: Value = serde_json::from_str(&admin_token_content).unwrap();
36+
let admin_token = admin_token_json["token"].as_str().unwrap().to_string();
37+
38+
// Step 2: Start server with token files
39+
let mut server = TestServer::configure()
40+
.with_auth()
41+
.with_no_admin_token()
42+
.with_admin_token_file(admin_token_file.to_str().unwrap())
43+
.spawn()
44+
.await;
45+
46+
// Set the admin token for further operations
47+
server.set_token(Some(admin_token.clone()));
48+
49+
// Step 4: Verify tokens exist
50+
let result = server
51+
.run(
52+
vec!["show", "tokens"],
53+
&["--tls-ca", "../testing-certs/rootCA.pem"],
54+
)
55+
.unwrap();
56+
assert_contains!(&result, "_admin");
57+
58+
// Step 4: Verify database creation
59+
let result = server
60+
.run(
61+
vec!["show", "databases"],
62+
&["--tls-ca", "../testing-certs/rootCA.pem"],
63+
)
64+
.unwrap();
65+
assert_contains!(&result, "_internal");
66+
67+
// Step 5: Test admin token privileges
68+
let client = server.http_client();
69+
let base = server.client_addr();
70+
71+
// Admin can query _internal database
72+
let query_sql_url = format!("{base}/api/v3/query_sql");
73+
let response = client
74+
.get(&query_sql_url)
75+
.query(&[
76+
("db", "_internal"),
77+
("q", "SELECT * FROM system.tables LIMIT 1"),
78+
])
79+
.bearer_auth(&admin_token)
80+
.send()
81+
.await
82+
.unwrap();
83+
assert_eq!(response.status(), StatusCode::OK);
84+
85+
// Admin can create a new database
86+
let result = server
87+
.run(
88+
vec!["create", "database", "admin_test_db"],
89+
&["--tls-ca", "../testing-certs/rootCA.pem"],
90+
)
91+
.unwrap();
92+
assert_contains!(&result, "Database \"admin_test_db\" created successfully");
93+
}

influxdb3/tests/server/mod.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ pub struct TestConfig {
9797
gen1_duration: Option<String>,
9898
capture_logs: bool,
9999
enable_recovery_endpoint: bool,
100+
admin_token_file: Option<String>,
101+
permission_tokens_file: Option<String>,
100102
}
101103

102104
impl TestConfig {
@@ -184,6 +186,18 @@ impl TestConfig {
184186
self.capture_logs = true;
185187
self
186188
}
189+
190+
/// Set the admin token file path for this [`TestServer`]
191+
pub fn with_admin_token_file<S: Into<String>>(mut self, path: S) -> Self {
192+
self.admin_token_file = Some(path.into());
193+
self
194+
}
195+
196+
/// Set the permission tokens file path for this [`TestServer`]
197+
pub fn with_permission_tokens_file<S: Into<String>>(mut self, path: S) -> Self {
198+
self.permission_tokens_file = Some(path.into());
199+
self
200+
}
187201
}
188202

189203
impl ConfigProvider for TestConfig {
@@ -242,6 +256,20 @@ impl ConfigProvider for TestConfig {
242256
])
243257
}
244258

259+
if let Some(admin_token_file) = &self.admin_token_file {
260+
args.append(&mut vec![
261+
"--admin-token-file".to_string(),
262+
admin_token_file.to_owned(),
263+
])
264+
}
265+
266+
if let Some(permission_tokens_file) = &self.permission_tokens_file {
267+
args.append(&mut vec![
268+
"--permission-tokens-file".to_string(),
269+
permission_tokens_file.to_owned(),
270+
])
271+
}
272+
245273
args
246274
}
247275

0 commit comments

Comments
 (0)