datafusion_ffi/tests/
utils.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::path::Path;
19
20use abi_stable::library::RootModule;
21use datafusion_common::{DataFusionError, Result};
22
23use crate::tests::ForeignLibraryModuleRef;
24
25/// Compute the path to the library. It would be preferable to simply use
26/// abi_stable::library::development_utils::compute_library_path however
27/// our current CI pipeline has a `ci` profile that we need to use to
28/// find the library.
29pub fn compute_library_path<M: RootModule>(
30    target_path: &Path,
31) -> std::io::Result<std::path::PathBuf> {
32    let debug_dir = target_path.join("debug");
33    let release_dir = target_path.join("release");
34    let ci_dir = target_path.join("ci");
35
36    let debug_path = M::get_library_path(&debug_dir.join("deps"));
37    let release_path = M::get_library_path(&release_dir.join("deps"));
38    let ci_path = M::get_library_path(&ci_dir.join("deps"));
39
40    let all_paths = vec![
41        (debug_dir.clone(), debug_path),
42        (release_dir, release_path),
43        (ci_dir, ci_path),
44    ];
45
46    let best_path = all_paths
47        .into_iter()
48        .filter(|(_, path)| path.exists())
49        .filter_map(|(dir, path)| path.metadata().map(|m| (dir, m)).ok())
50        .filter_map(|(dir, meta)| meta.modified().map(|m| (dir, m)).ok())
51        .max_by_key(|(_, date)| *date)
52        .map(|(dir, _)| dir)
53        .unwrap_or(debug_dir);
54
55    Ok(best_path)
56}
57
58pub fn get_module() -> Result<ForeignLibraryModuleRef> {
59    let expected_version = crate::version();
60
61    let crate_root = Path::new(env!("CARGO_MANIFEST_DIR"));
62    let target_dir = crate_root
63        .parent()
64        .expect("Failed to find crate parent")
65        .parent()
66        .expect("Failed to find workspace root")
67        .join("target");
68
69    // Find the location of the library. This is specific to the build environment,
70    // so you will need to change the approach here based on your use case.
71    // let target: &std::path::Path = "../../../../target/".as_ref();
72    let library_path =
73        compute_library_path::<ForeignLibraryModuleRef>(target_dir.as_path())
74            .map_err(|e| DataFusionError::External(Box::new(e)))?
75            .join("deps");
76
77    // Load the module
78    let module = ForeignLibraryModuleRef::load_from_directory(&library_path)
79        .map_err(|e| DataFusionError::External(Box::new(e)))?;
80
81    assert_eq!(
82        module
83            .version()
84            .expect("Unable to call version on FFI module")(),
85        expected_version
86    );
87
88    Ok(module)
89}