Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

Commit 9b61d01

Browse files
authored
add tests (#705)
* test fork namespace * test destroy namespace * test create namespace load from url test load from dump * test load dump from file * reorganize test dir * fix sync_many_replicas test * load dump tests * test malformed dumps * add create dump test. * fix tests
1 parent 33bca7b commit 9b61d01

22 files changed

+1040
-511
lines changed

sqld/src/config.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@ use std::sync::Arc;
33

44
use anyhow::Context;
55
use hyper::client::HttpConnector;
6+
use hyper_rustls::HttpsConnector;
67
use sha256::try_digest;
78
use tokio::time::Duration;
89
use tonic::transport::Channel;
10+
use tower::ServiceExt;
911

1012
use crate::auth::{self, Auth};
1113
use crate::net::{AddrIncoming, Connector};
1214

1315
pub struct RpcClientConfig<C = HttpConnector> {
1416
pub remote_url: String,
15-
pub connector: C,
1617
pub tls_config: Option<TlsConfig>,
18+
pub connector: C,
1719
}
1820

1921
impl<C: Connector> RpcClientConfig<C> {
@@ -35,7 +37,7 @@ impl<C: Connector> RpcClientConfig<C> {
3537
builder = builder.tls_config(tls_config)?;
3638
}
3739

38-
let channel = builder.connect_with_connector_lazy(self.connector);
40+
let channel = builder.connect_with_connector_lazy(self.connector.map_err(Into::into));
3941

4042
Ok((channel, uri))
4143
}
@@ -104,8 +106,9 @@ impl<A> UserApiConfig<A> {
104106
}
105107
}
106108

107-
pub struct AdminApiConfig<A = AddrIncoming> {
109+
pub struct AdminApiConfig<A = AddrIncoming, C = HttpsConnector<HttpConnector>> {
108110
pub acceptor: A,
111+
pub connector: C,
109112
}
110113

111114
#[derive(Clone)]

sqld/src/error.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,32 @@ impl From<bincode::Error> for Error {
147147
}
148148
}
149149

150+
macro_rules! internal_from {
151+
($to:ty => { $($from:ty,)* }) => {
152+
$(
153+
impl From<$from> for $to {
154+
fn from(v: $from) -> Self {
155+
<$to>::Internal(v.to_string())
156+
}
157+
}
158+
)*
159+
160+
};
161+
}
162+
163+
internal_from! {
164+
LoadDumpError => {
165+
std::io::Error,
166+
rusqlite::Error,
167+
hyper::Error,
168+
tokio::task::JoinError,
169+
}
170+
}
171+
150172
#[derive(Debug, thiserror::Error)]
151173
pub enum LoadDumpError {
152-
#[error("IO error: {0}")]
153-
Io(#[from] std::io::Error),
174+
#[error("internal error: {0}")]
175+
Internal(String),
154176
#[error("Cannot load a dump on a replica")]
155177
ReplicaLoadDump,
156178
#[error("cannot load from a dump if a database already exists")]
@@ -161,10 +183,12 @@ pub enum LoadDumpError {
161183
DumpFileDoesntExist,
162184
#[error("invalid dump url")]
163185
InvalidDumpUrl,
164-
#[error("error fetching dump: {0}")]
165-
Fetch(#[from] hyper::Error),
166186
#[error("unsupported dump url scheme `{0}`, supported schemes are: `http`, `file`")]
167187
UnsupportedUrlScheme(String),
188+
#[error("a dump should execute within a transaction.")]
189+
NoTxn,
190+
#[error("the dump should commit the transaction.")]
191+
NoCommit,
168192
}
169193

170194
impl ResponseError for LoadDumpError {}
@@ -174,12 +198,14 @@ impl IntoResponse for LoadDumpError {
174198
use LoadDumpError::*;
175199

176200
match &self {
177-
Io(_) | Fetch(_) => self.format_err(StatusCode::INTERNAL_SERVER_ERROR),
201+
Internal(_) => self.format_err(StatusCode::INTERNAL_SERVER_ERROR),
178202
ReplicaLoadDump
179203
| LoadDumpExistingDb
180204
| InvalidDumpUrl
181205
| DumpFileDoesntExist
182206
| UnsupportedUrlScheme(_)
207+
| NoTxn
208+
| NoCommit
183209
| DumpFilePathNotAbsolute => self.format_err(StatusCode::BAD_REQUEST),
184210
}
185211
}

sqld/src/http/admin/mod.rs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use futures::TryStreamExt;
77
use hyper::Body;
88
use serde::{Deserialize, Serialize};
99
use std::io::ErrorKind;
10+
use std::path::PathBuf;
1011
use std::sync::Arc;
1112
use tokio_util::io::ReaderStream;
1213
use url::Url;
@@ -15,26 +16,30 @@ use crate::database::Database;
1516
use crate::error::LoadDumpError;
1617
use crate::hrana;
1718
use crate::namespace::{DumpStream, MakeNamespace, NamespaceName, NamespaceStore, RestoreOption};
19+
use crate::net::Connector;
1820
use crate::LIBSQL_PAGE_SIZE;
1921

2022
pub mod stats;
2123

2224
type UserHttpServer<M> =
2325
Arc<hrana::http::Server<<<M as MakeNamespace>::Database as Database>::Connection>>;
2426

25-
struct AppState<M: MakeNamespace> {
27+
struct AppState<M: MakeNamespace, C> {
2628
namespaces: NamespaceStore<M>,
2729
user_http_server: UserHttpServer<M>,
30+
connector: C,
2831
}
2932

30-
pub async fn run<M, A>(
33+
pub async fn run<M, A, C>(
3134
acceptor: A,
3235
user_http_server: UserHttpServer<M>,
3336
namespaces: NamespaceStore<M>,
37+
connector: C,
3438
) -> anyhow::Result<()>
3539
where
3640
A: crate::net::Accept,
3741
M: MakeNamespace,
42+
C: Connector,
3843
{
3944
use axum::routing::{get, post};
4045
let router = axum::Router::new()
@@ -56,6 +61,7 @@ where
5661
.route("/v1/diagnostics", get(handle_diagnostics))
5762
.with_state(Arc::new(AppState {
5863
namespaces,
64+
connector,
5965
user_http_server,
6066
}));
6167

@@ -70,8 +76,8 @@ async fn handle_get_index() -> &'static str {
7076
"Welcome to the sqld admin API"
7177
}
7278

73-
async fn handle_get_config<M: MakeNamespace>(
74-
State(app_state): State<Arc<AppState<M>>>,
79+
async fn handle_get_config<M: MakeNamespace, C: Connector>(
80+
State(app_state): State<Arc<AppState<M, C>>>,
7581
Path(namespace): Path<String>,
7682
) -> crate::Result<Json<HttpDatabaseConfig>> {
7783
let store = app_state
@@ -90,8 +96,8 @@ async fn handle_get_config<M: MakeNamespace>(
9096
Ok(Json(resp))
9197
}
9298

93-
async fn handle_diagnostics<M: MakeNamespace>(
94-
State(app_state): State<Arc<AppState<M>>>,
99+
async fn handle_diagnostics<M: MakeNamespace, C>(
100+
State(app_state): State<Arc<AppState<M, C>>>,
95101
) -> crate::Result<Json<Vec<String>>> {
96102
use crate::connection::Connection;
97103
use hrana::http::stream;
@@ -127,8 +133,8 @@ struct HttpDatabaseConfig {
127133
max_db_size: Option<bytesize::ByteSize>,
128134
}
129135

130-
async fn handle_post_config<M: MakeNamespace>(
131-
State(app_state): State<Arc<AppState<M>>>,
136+
async fn handle_post_config<M: MakeNamespace, C>(
137+
State(app_state): State<Arc<AppState<M, C>>>,
132138
Path(namespace): Path<String>,
133139
Json(req): Json<HttpDatabaseConfig>,
134140
) -> crate::Result<()> {
@@ -155,13 +161,15 @@ struct CreateNamespaceReq {
155161
max_db_size: Option<bytesize::ByteSize>,
156162
}
157163

158-
async fn handle_create_namespace<M: MakeNamespace>(
159-
State(app_state): State<Arc<AppState<M>>>,
164+
async fn handle_create_namespace<M: MakeNamespace, C: Connector>(
165+
State(app_state): State<Arc<AppState<M, C>>>,
160166
Path(namespace): Path<String>,
161167
Json(req): Json<CreateNamespaceReq>,
162168
) -> crate::Result<()> {
163169
let dump = match req.dump_url {
164-
Some(ref url) => RestoreOption::Dump(dump_stream_from_url(url).await?),
170+
Some(ref url) => {
171+
RestoreOption::Dump(dump_stream_from_url(url, app_state.connector.clone()).await?)
172+
}
165173
None => RestoreOption::Latest,
166174
};
167175

@@ -183,8 +191,8 @@ struct ForkNamespaceReq {
183191
timestamp: NaiveDateTime,
184192
}
185193

186-
async fn handle_fork_namespace<M: MakeNamespace>(
187-
State(app_state): State<Arc<AppState<M>>>,
194+
async fn handle_fork_namespace<M: MakeNamespace, C>(
195+
State(app_state): State<Arc<AppState<M, C>>>,
188196
Path((from, to)): Path<(String, String)>,
189197
req: Option<Json<ForkNamespaceReq>>,
190198
) -> crate::Result<()> {
@@ -195,14 +203,12 @@ async fn handle_fork_namespace<M: MakeNamespace>(
195203
Ok(())
196204
}
197205

198-
async fn dump_stream_from_url(url: &Url) -> Result<DumpStream, LoadDumpError> {
206+
async fn dump_stream_from_url<C>(url: &Url, connector: C) -> Result<DumpStream, LoadDumpError>
207+
where
208+
C: Connector,
209+
{
199210
match url.scheme() {
200211
"http" | "https" => {
201-
let connector = hyper_rustls::HttpsConnectorBuilder::new()
202-
.with_native_roots()
203-
.https_or_http()
204-
.enable_http1()
205-
.build();
206212
let client = hyper::client::Client::builder().build::<_, Body>(connector);
207213
let uri = url
208214
.as_str()
@@ -215,9 +221,7 @@ async fn dump_stream_from_url(url: &Url) -> Result<DumpStream, LoadDumpError> {
215221
Ok(Box::new(body))
216222
}
217223
"file" => {
218-
let path = url
219-
.to_file_path()
220-
.map_err(|_| LoadDumpError::InvalidDumpUrl)?;
224+
let path = PathBuf::from(url.path());
221225
if !path.is_absolute() {
222226
return Err(LoadDumpError::DumpFilePathNotAbsolute);
223227
}
@@ -234,8 +238,8 @@ async fn dump_stream_from_url(url: &Url) -> Result<DumpStream, LoadDumpError> {
234238
}
235239
}
236240

237-
async fn handle_delete_namespace<F: MakeNamespace>(
238-
State(app_state): State<Arc<AppState<F>>>,
241+
async fn handle_delete_namespace<F: MakeNamespace, C>(
242+
State(app_state): State<Arc<AppState<F, C>>>,
239243
Path(namespace): Path<String>,
240244
) -> crate::Result<()> {
241245
app_state

sqld/src/http/admin/stats.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ impl From<Stats> for StatsResponse {
3838
}
3939
}
4040

41-
pub(super) async fn handle_stats<M: MakeNamespace>(
42-
State(app_state): State<Arc<AppState<M>>>,
41+
pub(super) async fn handle_stats<M: MakeNamespace, C>(
42+
State(app_state): State<Arc<AppState<M, C>>>,
4343
Path(namespace): Path<String>,
4444
) -> crate::Result<Json<StatsResponse>> {
4545
let stats = app_state

sqld/src/lib.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::connection::{Connection, MakeConnection};
1010
use crate::error::Error;
1111
use crate::migration::maybe_migrate;
1212
use crate::net::Accept;
13-
use crate::net::AddrIncoming;
1413
use crate::rpc::proxy::rpc::proxy_server::Proxy;
1514
use crate::rpc::proxy::ProxyService;
1615
use crate::rpc::replica_proxy::ReplicaProxyService;
@@ -25,6 +24,7 @@ use config::{
2524
};
2625
use http::user::UserApi;
2726
use hyper::client::HttpConnector;
27+
use hyper_rustls::HttpsConnector;
2828
use namespace::{
2929
MakeNamespace, NamespaceName, NamespaceStore, PrimaryNamespaceConfig, PrimaryNamespaceMaker,
3030
ReplicaNamespaceConfig, ReplicaNamespaceMaker,
@@ -40,6 +40,8 @@ use tokio::time::Duration;
4040
use url::Url;
4141
use utils::services::idle_shutdown::IdleShutdownKicker;
4242

43+
use self::net::AddrIncoming;
44+
4345
pub mod config;
4446
pub mod connection;
4547
pub mod net;
@@ -80,11 +82,11 @@ pub(crate) static BLOCKING_RT: Lazy<Runtime> = Lazy::new(|| {
8082
type Result<T, E = Error> = std::result::Result<T, E>;
8183
type StatsSender = mpsc::Sender<(NamespaceName, Weak<Stats>)>;
8284

83-
pub struct Server<C = HttpConnector, A = AddrIncoming> {
85+
pub struct Server<C = HttpConnector, A = AddrIncoming, D = HttpsConnector<HttpConnector>> {
8486
pub path: Arc<Path>,
8587
pub db_config: DbConfig,
8688
pub user_api_config: UserApiConfig<A>,
87-
pub admin_api_config: Option<AdminApiConfig<A>>,
89+
pub admin_api_config: Option<AdminApiConfig<A, D>>,
8890
pub rpc_server_config: Option<RpcServerConfig<A>>,
8991
pub rpc_client_config: Option<RpcClientConfig<C>>,
9092
pub idle_shutdown_timeout: Option<Duration>,
@@ -95,7 +97,7 @@ pub struct Server<C = HttpConnector, A = AddrIncoming> {
9597
pub shutdown: Arc<Notify>,
9698
}
9799

98-
impl<C, A> Default for Server<C, A> {
100+
impl<C, A, D> Default for Server<C, A, D> {
99101
fn default() -> Self {
100102
Self {
101103
path: PathBuf::from("data.sqld").into(),
@@ -114,26 +116,27 @@ impl<C, A> Default for Server<C, A> {
114116
}
115117
}
116118

117-
struct Services<M: MakeNamespace, A, P, S> {
119+
struct Services<M: MakeNamespace, A, P, S, C> {
118120
namespaces: NamespaceStore<M>,
119121
idle_shutdown_kicker: Option<IdleShutdownKicker>,
120122
proxy_service: P,
121123
replication_service: S,
122124
user_api_config: UserApiConfig<A>,
123-
admin_api_config: Option<AdminApiConfig<A>>,
125+
admin_api_config: Option<AdminApiConfig<A, C>>,
124126
disable_namespaces: bool,
125127
disable_default_namespace: bool,
126128
db_config: DbConfig,
127129
auth: Arc<Auth>,
128130
path: Arc<Path>,
129131
}
130132

131-
impl<M, A, P, S> Services<M, A, P, S>
133+
impl<M, A, P, S, C> Services<M, A, P, S, C>
132134
where
133135
M: MakeNamespace,
134136
A: crate::net::Accept,
135137
P: Proxy,
136138
S: ReplicationLog,
139+
C: Connector,
137140
{
138141
fn configure(self, join_set: &mut JoinSet<anyhow::Result<()>>) {
139142
let user_http = UserApi {
@@ -154,11 +157,16 @@ where
154157

155158
let user_http_service = user_http.configure(join_set);
156159

157-
if let Some(AdminApiConfig { acceptor }) = self.admin_api_config {
160+
if let Some(AdminApiConfig {
161+
acceptor,
162+
connector,
163+
}) = self.admin_api_config
164+
{
158165
join_set.spawn(http::admin::run(
159166
acceptor,
160167
user_http_service,
161168
self.namespaces,
169+
connector,
162170
));
163171
}
164172
}
@@ -254,10 +262,11 @@ fn init_version_file(db_path: &Path) -> anyhow::Result<()> {
254262
Ok(())
255263
}
256264

257-
impl<C, A> Server<C, A>
265+
impl<C, A, D> Server<C, A, D>
258266
where
259267
C: Connector,
260268
A: Accept,
269+
D: Connector,
261270
{
262271
/// Setup sqlite global environment
263272
fn init_sqlite_globals(&self) {

0 commit comments

Comments
 (0)