Skip to content

Commit

Permalink
setup tests (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
Binlogo authored Jul 23, 2024
1 parent 58b641f commit 752544e
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 10 deletions.
90 changes: 82 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions packages/duckdb_protobuf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ crate-type = ["cdylib"]
[dependencies]
duckdb = { version = "1.0.0", features = ["vtab-loadable", "bundled"] }
duckdb-loadable-macros = "0.1.1"
prost-reflect = "0.13.1"
prost-reflect = "0.14.0"
protobuf = "3.5.0"
glob = "0.3.1"
byteorder = "1.5.0"
log = "0.4.21"
ouroboros = "0.18.4"
strum = { version = "0.26.3", features = ["derive"] }
strum = { version = "0.26.3", features = ["derive"] }

[dev-dependencies]
anyhow = "1.0"
prost = "0.13.1"
prost-build = "0.13.1"

1 change: 1 addition & 0 deletions packages/duckdb_protobuf/tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/generated
177 changes: 177 additions & 0 deletions packages/duckdb_protobuf/tests/it/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use anyhow::Result;
use duckdb::{Config, Connection};
use prost::Message;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use std::sync::Once;

static INIT: Once = Once::new();

fn setup() {
INIT.call_once(|| {
compile_protos().expect("Failed to compile protobufs");
generate_test_data().expect("Failed to generate test data");
compile_duckdb_extension().expect("Failed to compile DuckDB extension");
attach_metadata().expect("Failed to attach metadata");
});
}

fn compile_protos() -> Result<(), Box<dyn std::error::Error>> {
let proto_path = "tests/protos/user.proto";
let descriptor_dir = "tests/generated";
let out_dir = "tests/src";

std::fs::create_dir_all(descriptor_dir)?;
std::fs::create_dir_all(out_dir)?;

prost_build::Config::new()
.out_dir(out_dir)
.file_descriptor_set_path("tests/generated/descriptor.pb")
.compile_protos(&[proto_path], &[Path::new("tests/protos")])?;

Ok(())
}

fn generate_test_data() -> Result<(), Box<dyn std::error::Error>> {
// Include the generated Rust code for the protobuf messages
mod user {
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/src/user.rs"));
}

// Create some example User messages
let users = [
user::User {
name: "Alice".to_string(),
id: 1,
},
user::User {
name: "Bob".to_string(),
id: 2,
},
user::User {
name: "Charlie".to_string(),
id: 3,
},
];

let out_dir = "tests/generated/data";
std::fs::create_dir_all(out_dir)?;

// Serialize the messages to binary files
for (i, user) in users.iter().enumerate() {
let mut buf = Vec::new();
user.encode(&mut buf)?;

let mut file = File::create(format!("{out_dir}/user_{}.bin", i))?;
file.write_all(&buf)?;

println!("Generated test data for user {}: {:?}", i, user);
}

Ok(())
}

fn compile_duckdb_extension() -> Result<()> {
Command::new("cargo")
.args(["build", "--release"])
.status()?;

Ok(())
}

fn attach_metadata() -> Result<()> {
let target_dir = "../../target/release";
let library_output = if cfg!(target_os = "macos") {
"libduckdb_protobuf.dylib"
} else if cfg!(target_os = "linux") {
"libduckdb_protobuf.so"
} else {
unimplemented!("Unsupported platform");
};

Command::new("cargo")
.args([
"run",
"--package",
"duckdb_metadata_bin",
"--bin",
"duckdb_metadata",
"--",
"--input",
&format!("{}/{}", target_dir, library_output),
"--output",
&format!("{}/protobuf.duckdb_extension", target_dir),
"--extension-version",
"v0.0.1",
"--duckdb-version",
"v1.0.0",
"--platform",
if cfg!(target_os = "macos") {
"osx_arm64"
} else if cfg!(target_os = "linux") {
"linux_amd64"
} else {
unimplemented!("Unsupported platform")
},
])
.status()?;

println!("Metadata attached successfully.");

Ok(())
}

#[test]
fn test_setup_creates_files() {
setup();

for i in 0..3 {
let file_path = format!("tests/generated/data/user_{}.bin", i);
assert!(
Path::new(&file_path).exists(),
"File {} should exist",
file_path
);
}
}

#[test]
fn test_query_protobuf_data() -> Result<()> {
setup();

let config = Config::default().allow_unsigned_extensions()?;
let conn = Connection::open_in_memory_with_flags(config)?;

conn.execute("LOAD '../../target/release/protobuf.duckdb_extension'", [])?;
println!("DuckDB extension loaded successfully.");

let mut stmt = conn.prepare(
"
SELECT *
FROM protobuf(
descriptors = './tests/generated/descriptor.pb',
files = './tests/generated/data/**/*.bin',
message_type = 'user.User',
delimiter = 'SingleMessagePerFile'
)
LIMIT 10;
",
)?;

let mut rows = stmt.query([])?;

let mut results = Vec::new();
while let Some(row) = rows.next()? {
let name: String = row.get(0)?;
let id: i32 = row.get(1)?;
results.push((name, id));
}
println!("Query result: {results:?}");

assert_eq!(results.len(), 3, "Expected 3 rows");
assert_eq!(results[0].0, "Alice", "Expected first name to be 'Alice'");
assert_eq!(results[0].1, 1, "Expected first id to be 1");
Ok(())
}
10 changes: 10 additions & 0 deletions packages/duckdb_protobuf/tests/protos/user.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

syntax = "proto3";

package user;

message User {
string name = 1;
int32 id = 2;
}

9 changes: 9 additions & 0 deletions packages/duckdb_protobuf/tests/src/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This file is @generated by prost-build.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct User {
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
#[prost(int32, tag = "2")]
pub id: i32,
}

0 comments on commit 752544e

Please sign in to comment.