|
1 | 1 | pub mod auth; |
| 2 | +pub mod constants; |
2 | 3 | pub mod handler; |
3 | 4 |
|
4 | 5 | use api::VectorDb; |
@@ -68,176 +69,4 @@ pub async fn run_http_server( |
68 | 69 | } |
69 | 70 |
|
70 | 71 | #[cfg(test)] |
71 | | -mod tests { |
72 | | - use super::*; |
73 | | - use api::DbConfig; |
74 | | - use axum::http::StatusCode; |
75 | | - use axum_test::TestServer; |
76 | | - use defs::Similarity; |
77 | | - use index::{IndexType, hnsw::HnswConfig, kd_tree::KDTreeConfig}; |
78 | | - use serde_json::json; |
79 | | - use storage::StorageType; |
80 | | - |
81 | | - use defs::{ApiKeyEntry, ApiKeyRole, ApiKeyStore}; |
82 | | - |
83 | | - const API_KEY: &str = "full-access-key"; |
84 | | - const READONLY_API_KEY: &str = "read-only-key"; |
85 | | - |
86 | | - fn test_db() -> Arc<api::VectorDb> { |
87 | | - let temp_dir = tempfile::tempdir().unwrap(); |
88 | | - let db = api::init_api(DbConfig { |
89 | | - storage_type: StorageType::InMemory, |
90 | | - index_type: IndexType::Flat, |
91 | | - data_path: temp_dir.path().to_path_buf(), |
92 | | - dimension: 3, |
93 | | - similarity: Similarity::Cosine, |
94 | | - hnsw_config: HnswConfig::default(), |
95 | | - kd_tree_config: KDTreeConfig::default(), |
96 | | - }) |
97 | | - .unwrap(); |
98 | | - Arc::new(db) |
99 | | - } |
100 | | - |
101 | | - fn test_server() -> TestServer { |
102 | | - let keys = ApiKeyStore::new(vec![ |
103 | | - ApiKeyEntry { |
104 | | - name: "full".to_string(), |
105 | | - role: ApiKeyRole::ReadWrite, |
106 | | - key: API_KEY.to_string(), |
107 | | - }, |
108 | | - ApiKeyEntry { |
109 | | - name: "readonly".to_string(), |
110 | | - role: ApiKeyRole::ReadOnly, |
111 | | - key: READONLY_API_KEY.to_string(), |
112 | | - }, |
113 | | - ]); |
114 | | - let router = create_router(test_db(), Arc::new(keys)); |
115 | | - TestServer::new(router).unwrap() |
116 | | - } |
117 | | - |
118 | | - #[tokio::test] |
119 | | - async fn in_memory_storage_http_smoke_test() { |
120 | | - let server = test_server(); |
121 | | - |
122 | | - let insert_response = server |
123 | | - .post("/points") |
124 | | - .add_header("api-key", API_KEY) |
125 | | - .json(&json!({ |
126 | | - "vector": [1.0, 0.0, 0.0], |
127 | | - "payload": { |
128 | | - "content_type": "Text", |
129 | | - "content": "smoke-test" |
130 | | - } |
131 | | - })) |
132 | | - .await; |
133 | | - insert_response.assert_status(StatusCode::CREATED); |
134 | | - let insert_body: serde_json::Value = insert_response.json(); |
135 | | - let point_id = insert_body["point_id"].as_str().unwrap(); |
136 | | - |
137 | | - let get_response = server |
138 | | - .get(&format!("/points/{point_id}")) |
139 | | - .add_header("api-key", API_KEY) |
140 | | - .await; |
141 | | - get_response.assert_status_ok(); |
142 | | - let point_body: serde_json::Value = get_response.json(); |
143 | | - assert_eq!(point_body["payload"]["content"], "smoke-test"); |
144 | | - assert_eq!(point_body["vector"], json!([1.0, 0.0, 0.0])); |
145 | | - |
146 | | - let search_response = server |
147 | | - .post("/points/search") |
148 | | - .add_header("api-key", API_KEY) |
149 | | - .json(&json!({ |
150 | | - "vector": [1.0, 0.0, 0.0], |
151 | | - "similarity": "Cosine", |
152 | | - "limit": 1 |
153 | | - })) |
154 | | - .await; |
155 | | - search_response.assert_status_ok(); |
156 | | - let search_body: serde_json::Value = search_response.json(); |
157 | | - assert_eq!(search_body["results"], json!([point_id])); |
158 | | - |
159 | | - let delete_response = server |
160 | | - .delete(&format!("/points/{point_id}")) |
161 | | - .add_header("api-key", API_KEY) |
162 | | - .await; |
163 | | - delete_response.assert_status(StatusCode::NO_CONTENT); |
164 | | - |
165 | | - let missing_response = server |
166 | | - .get(&format!("/points/{point_id}")) |
167 | | - .add_header("api-key", API_KEY) |
168 | | - .await; |
169 | | - missing_response.assert_status(StatusCode::NOT_FOUND); |
170 | | - } |
171 | | - |
172 | | - #[tokio::test] |
173 | | - async fn public_routes_require_no_key() { |
174 | | - let server = test_server(); |
175 | | - server.get("/").await.assert_status_ok(); |
176 | | - server.get("/health").await.assert_status_ok(); |
177 | | - } |
178 | | - |
179 | | - #[tokio::test] |
180 | | - async fn protected_routes_reject_missing_key() { |
181 | | - let server = test_server(); |
182 | | - server |
183 | | - .get("/points/00000000-0000-0000-0000-000000000000") |
184 | | - .await |
185 | | - .assert_status(StatusCode::UNAUTHORIZED); |
186 | | - server |
187 | | - .post("/points") |
188 | | - .json(&json!({"vector": [1.0, 0.0, 0.0], "payload": {"content_type": "Text", "content": "x"}})) |
189 | | - .await |
190 | | - .assert_status(StatusCode::UNAUTHORIZED); |
191 | | - } |
192 | | - |
193 | | - #[tokio::test] |
194 | | - async fn protected_routes_reject_wrong_key() { |
195 | | - let server = test_server(); |
196 | | - server |
197 | | - .get("/points/00000000-0000-0000-0000-000000000000") |
198 | | - .add_header("api-key", "not-the-right-key") |
199 | | - .await |
200 | | - .assert_status(StatusCode::UNAUTHORIZED); |
201 | | - } |
202 | | - |
203 | | - #[tokio::test] |
204 | | - async fn readonly_key_can_read_but_not_write() { |
205 | | - let server = test_server(); |
206 | | - |
207 | | - let insert_response = server |
208 | | - .post("/points") |
209 | | - .add_header("api-key", API_KEY) |
210 | | - .json(&json!({"vector": [1.0, 0.0, 0.0], "payload": {"content_type": "Text", "content": "x"}})) |
211 | | - .await; |
212 | | - let point_id = insert_response.json::<serde_json::Value>()["point_id"] |
213 | | - .as_str() |
214 | | - .unwrap() |
215 | | - .to_string(); |
216 | | - |
217 | | - server |
218 | | - .get(&format!("/points/{point_id}")) |
219 | | - .add_header("api-key", READONLY_API_KEY) |
220 | | - .await |
221 | | - .assert_status_ok(); |
222 | | - |
223 | | - server |
224 | | - .post("/points/search") |
225 | | - .add_header("api-key", READONLY_API_KEY) |
226 | | - .json(&json!({"vector": [1.0, 0.0, 0.0], "similarity": "Cosine", "limit": 1})) |
227 | | - .await |
228 | | - .assert_status_ok(); |
229 | | - |
230 | | - server |
231 | | - .delete(&format!("/points/{point_id}")) |
232 | | - .add_header("api-key", READONLY_API_KEY) |
233 | | - .await |
234 | | - .assert_status(StatusCode::FORBIDDEN); |
235 | | - |
236 | | - server |
237 | | - .post("/points") |
238 | | - .add_header("api-key", READONLY_API_KEY) |
239 | | - .json(&json!({"vector": [1.0, 0.0, 0.0], "payload": {"content_type": "Text", "content": "y"}})) |
240 | | - .await |
241 | | - .assert_status(StatusCode::FORBIDDEN); |
242 | | - } |
243 | | -} |
| 72 | +mod tests; |
0 commit comments