Skip to content

Commit 72f03e0

Browse files
Start updating http testing (#297)
1 parent 41024ae commit 72f03e0

9 files changed

Lines changed: 212 additions & 69 deletions

File tree

.github/workflows/test.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,31 @@ jobs:
305305
test-http-server:
306306
name: Extension / HTTP Server
307307
runs-on: ubuntu-latest
308+
strategy:
309+
matrix:
310+
arch: [amd64]
311+
steps:
312+
- uses: actions/checkout@v2
313+
with:
314+
submodules: true
315+
- name: Cache Cargo
316+
uses: actions/cache@v4
317+
with:
318+
path: /home/runner/.cargo
319+
key: cargo-dft-cache-
320+
- name: Cache Rust dependencies
321+
uses: actions/cache@v4
322+
with:
323+
path: /home/runner/target
324+
key: target-dft-cache-
325+
- name: Setup Rust Toolchain
326+
uses: ./.github/actions/setup-rust
327+
- name: Run auth tests
328+
run: |
329+
cargo t --features=http server::http::router::test
330+
test-http-server-flightsql:
331+
name: Extension / HTTP Server (FlightSQL)
332+
runs-on: ubuntu-latest
308333
strategy:
309334
matrix:
310335
arch: [amd64]
@@ -326,7 +351,7 @@ jobs:
326351
uses: ./.github/actions/setup-rust
327352
- name: Start FlightSQL Server
328353
run: |
329-
cargo r --features=http -- serve-http &
354+
cargo r --features=flightsql -- serve-flight-sql &
330355
- name: Run auth tests
331356
run: |
332-
cargo t --features=http server::test
357+
cargo t --features=http server::http::router::flightsql_test

Cargo.lock

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ assert_cmd = "2.0.16"
6666
datafusion-udfs-wasm = { version = "0.1.0", path = "crates/datafusion-udfs-wasm", features = [
6767
"serde",
6868
] }
69+
http-body-util = "0.1.3"
6970
insta = { version = "1.40.0", features = ["yaml"] }
7071
predicates = "3.1.2"
7172
reqwest = { version = "0.12.14", features = ["json"] }
73+
serde_json = "1.0.140"
7274
tempfile = "3.2.0"
7375
url = "2.5.2"
7476

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use color_eyre::Result;
2020
#[cfg(any(feature = "flightsql", feature = "http"))]
2121
use datafusion_dft::{args::Command, server};
2222
use datafusion_dft::{args::DftArgs, cli, config::create_config, tui};
23+
#[cfg(feature = "http")]
2324
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
2425

2526
fn main() -> Result<()> {

src/server/http/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ use datafusion_app::{
3232
};
3333
use router::create_router;
3434
use tokio::{net::TcpListener, signal};
35-
use tracing::info;
35+
use tracing::{debug, info};
3636

3737
use super::try_start_metrics_server;
3838

39-
const DEFAULT_SERVER_ADDRESS: &str = "127.0.0.1:8080";
39+
const DEFAULT_SERVER_ADDRESS: &str = "localhost:8080";
4040

4141
/// From https://github.com/tokio-rs/axum/blob/main/examples/graceful-shutdown/src/main.rs
4242
async fn shutdown_signal() {
@@ -142,7 +142,7 @@ pub async fn try_run(cli: DftArgs, config: AppConfig) -> Result<()> {
142142
.await?;
143143
app_execution.with_flightsql_ctx(flightsql_context);
144144
}
145-
info!("Created AppExecution: {app_execution:?}");
145+
debug!("Created AppExecution: {app_execution:?}");
146146
let app = HttpApp::try_new(
147147
app_execution,
148148
config.clone(),

src/server/http/router.rs

Lines changed: 170 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ async fn get_catalog_handler(
100100
Query(query): Query<GetCatalogQueryParams>,
101101
) -> Response {
102102
let opts = ExecOptions::new(None, query.flightsql);
103+
if opts.flightsql && !cfg!(feature = "flightsql") {
104+
return (
105+
StatusCode::BAD_REQUEST,
106+
"FlightSQL is not enabled on this server",
107+
)
108+
.into_response();
109+
}
103110
let sql = "SHOW TABLES".to_string();
104111
execute_sql_with_opts(state, sql, opts).await
105112
}
@@ -150,7 +157,7 @@ async fn execute_sql_with_opts(
150157
)
151158
.into_response(),
152159

153-
Err(e) => (StatusCode::BAD_REQUEST, format!("Execution failed: {}", e)).into_response(),
160+
Err(e) => (StatusCode::BAD_REQUEST, format!("{}", e)).into_response(),
154161
}
155162
}
156163

@@ -169,6 +176,7 @@ async fn batch_stream_to_response(batch_stream: SendableRecordBatchStream) -> Re
169176
}
170177
Err(e) => {
171178
error!("Error executing query: {}", e);
179+
// TODO: Use more appropriate errors, like 404 for table that doesnt exist
172180
return (StatusCode::INTERNAL_SERVER_ERROR, "Query execution error")
173181
.into_response();
174182
}
@@ -190,3 +198,164 @@ async fn batch_stream_to_response(batch_stream: SendableRecordBatchStream) -> Re
190198
Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "UTF-8 conversion error").into_response(),
191199
}
192200
}
201+
202+
#[cfg(test)]
203+
mod test {
204+
use axum::body::Body;
205+
use datafusion_app::{
206+
config::ExecutionConfig, extensions::DftSessionStateBuilder, local::ExecutionContext,
207+
};
208+
use http::{Request, StatusCode};
209+
use http_body_util::BodyExt;
210+
211+
use crate::{
212+
config::HttpServerConfig, execution::AppExecution, server::http::router::create_router,
213+
};
214+
use tower::ServiceExt;
215+
216+
fn setup() -> (AppExecution, HttpServerConfig) {
217+
let config = ExecutionConfig::default();
218+
let state = DftSessionStateBuilder::try_new(None)
219+
.unwrap()
220+
.build()
221+
.unwrap();
222+
let local = ExecutionContext::try_new(&config, state).unwrap();
223+
let execution = AppExecution::new(local);
224+
225+
let http_config = HttpServerConfig::default();
226+
(execution, http_config)
227+
}
228+
229+
#[tokio::test]
230+
async fn test_get_catalog() {
231+
let (execution, http_config) = setup();
232+
let router = create_router(execution, http_config);
233+
234+
let req = Request::builder()
235+
.uri("/catalog")
236+
.body(Body::empty())
237+
.unwrap();
238+
let res = router.oneshot(req).await.unwrap();
239+
assert_eq!(res.status(), StatusCode::OK);
240+
}
241+
242+
#[tokio::test]
243+
async fn test_get_table() {
244+
let (execution, http_config) = setup();
245+
let router = create_router(execution, http_config);
246+
247+
let req = Request::builder()
248+
.uri("/table/datafusion/information_schema/df_settings")
249+
.body(Body::empty())
250+
.unwrap();
251+
let res = router.oneshot(req).await.unwrap();
252+
assert_eq!(res.status(), StatusCode::OK);
253+
}
254+
255+
#[tokio::test]
256+
async fn test_get_nonexistent_table() {
257+
let (execution, http_config) = setup();
258+
let router = create_router(execution, http_config);
259+
260+
let req = Request::builder()
261+
.uri("/table/datafusion/information_schema/df_setting")
262+
.body(Body::empty())
263+
.unwrap();
264+
let res = router.oneshot(req).await.unwrap();
265+
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
266+
}
267+
268+
#[tokio::test]
269+
async fn test_correct_when_flightsql_not_enabled() {
270+
let (execution, http_config) = setup();
271+
let router = create_router(execution, http_config);
272+
273+
let req = Request::builder()
274+
.uri("/catalog?flightsql=true")
275+
.body(Body::empty())
276+
.unwrap();
277+
let res = router.oneshot(req).await.unwrap();
278+
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
279+
let body = res.into_body().collect().await.unwrap().to_bytes();
280+
assert_eq!(body, "FlightSQL is not enabled on this server".as_bytes())
281+
}
282+
}
283+
284+
#[cfg(all(test, feature = "flightsql"))]
285+
mod flightsql_test {
286+
use axum::body::Body;
287+
use datafusion_app::{
288+
config::{ExecutionConfig, FlightSQLConfig},
289+
extensions::DftSessionStateBuilder,
290+
flightsql::FlightSQLContext,
291+
local::ExecutionContext,
292+
};
293+
use http::{Request, StatusCode};
294+
295+
use crate::{
296+
config::HttpServerConfig, execution::AppExecution, server::http::router::create_router,
297+
};
298+
use tower::ServiceExt;
299+
300+
async fn setup() -> (AppExecution, HttpServerConfig) {
301+
let config = ExecutionConfig::default();
302+
let state = DftSessionStateBuilder::try_new(None)
303+
.unwrap()
304+
.build()
305+
.unwrap();
306+
let local = ExecutionContext::try_new(&config, state).unwrap();
307+
let mut execution = AppExecution::new(local);
308+
let flightsql_cfg = FlightSQLConfig {
309+
connection_url: "localhost:50051".to_string(),
310+
..Default::default()
311+
};
312+
let flightsql_ctx = FlightSQLContext::new(flightsql_cfg);
313+
flightsql_ctx
314+
.create_client(Some("http://localhost:50051".to_string()))
315+
.await
316+
.unwrap();
317+
execution.with_flightsql_ctx(flightsql_ctx);
318+
319+
let http_config = HttpServerConfig::default();
320+
(execution, http_config)
321+
}
322+
323+
#[tokio::test]
324+
async fn test_get_catalog() {
325+
let (execution, http_config) = setup().await;
326+
let router = create_router(execution, http_config);
327+
328+
let req = Request::builder()
329+
.uri("/catalog?flightsql=true")
330+
.body(Body::empty())
331+
.unwrap();
332+
let res = router.oneshot(req).await.unwrap();
333+
assert_eq!(res.status(), StatusCode::OK);
334+
}
335+
336+
#[tokio::test]
337+
async fn test_get_table() {
338+
let (execution, http_config) = setup().await;
339+
let router = create_router(execution, http_config);
340+
341+
let req = Request::builder()
342+
.uri("/table/datafusion/information_schema/df_settings?flightsql=true")
343+
.body(Body::empty())
344+
.unwrap();
345+
let res = router.oneshot(req).await.unwrap();
346+
assert_eq!(res.status(), StatusCode::OK);
347+
}
348+
349+
#[tokio::test]
350+
async fn test_get_nonexistent_table() {
351+
let (execution, http_config) = setup().await;
352+
let router = create_router(execution, http_config);
353+
354+
let req = Request::builder()
355+
.uri("/table/datafusion/information_schema/df_setting?flightsql=true")
356+
.body(Body::empty())
357+
.unwrap();
358+
let res = router.oneshot(req).await.unwrap();
359+
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
360+
}
361+
}

tests/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ impl TestConfigBuilder {
198198
self
199199
}
200200

201+
// TODO: Update this to work with HTTP server
202+
#[allow(dead_code)]
201203
#[cfg(feature = "flightsql")]
202204
pub fn with_server_auth(
203205
&mut self,

tests/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,4 @@
1818
mod cli_cases;
1919
mod config;
2020
mod extension_cases;
21-
#[cfg(feature = "http")]
22-
mod server;
2321
mod tui_cases;

tests/server.rs

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)