Skip to content

Commit 56ee2b9

Browse files
authored
Add basic integration test for entity cache invalidation (#7150)
1 parent de9c3ca commit 56ee2b9

File tree

10 files changed

+314
-29
lines changed

10 files changed

+314
-29
lines changed

apollo-router/src/axum_factory/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! axum factory is useful to create an [`AxumHttpServerFactory`] which implements [`crate::http_server_factory::HttpServerFactory`]
2-
mod axum_http_server_factory;
2+
pub(crate) mod axum_http_server_factory;
33
pub(crate) mod compression;
44
pub(crate) mod connection_handle;
55
mod listeners;

apollo-router/src/axum_factory/tests.rs

-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ use tower::Service;
5555
use tower::ServiceExt;
5656
use tower::service_fn;
5757

58-
pub(crate) use super::axum_http_server_factory::make_axum_router;
5958
use super::*;
6059
use crate::ApolloRouterError;
6160
use crate::Configuration;

apollo-router/src/cache/redis.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -555,10 +555,14 @@ impl RedisCacheStorage {
555555
tracing::trace!("insert result {:?}", r);
556556
}
557557

558-
pub(crate) async fn delete<K: KeyType>(&self, keys: Vec<RedisKey<K>>) -> Option<u32> {
559-
let mut h: HashMap<u16, Vec<String>> = HashMap::new();
558+
/// Delete keys *without* adding the `namepsace` prefix because `keys` is from
559+
/// `scan_with_namespaced_results` and already includes it.
560+
pub(crate) async fn delete_from_scan_result(
561+
&self,
562+
keys: Vec<fred::types::RedisKey>,
563+
) -> Option<u32> {
564+
let mut h: HashMap<u16, Vec<fred::types::RedisKey>> = HashMap::new();
560565
for key in keys.into_iter() {
561-
let key = self.make_key(key);
562566
let hash = ClusterRouting::hash_key(key.as_bytes());
563567
let entry = h.entry(hash).or_default();
564568
entry.push(key);
@@ -581,11 +585,13 @@ impl RedisCacheStorage {
581585
Some(total)
582586
}
583587

584-
pub(crate) fn scan(
588+
/// The keys returned in `ScanResult` do include the prefix from `namespace` configuration.
589+
pub(crate) fn scan_with_namespaced_results(
585590
&self,
586591
pattern: String,
587592
count: Option<u32>,
588593
) -> Pin<Box<dyn Stream<Item = Result<ScanResult, RedisError>> + Send>> {
594+
let pattern = self.make_key(RedisKey(pattern));
589595
if self.is_cluster {
590596
Box::pin(self.inner.next().scan_cluster(pattern, count, None))
591597
} else {

apollo-router/src/plugins/cache/invalidation.rs

+8-10
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use tracing::Instrument;
1818

1919
use super::entity::Storage as EntityStorage;
2020
use crate::cache::redis::RedisCacheStorage;
21-
use crate::cache::redis::RedisKey;
2221
use crate::plugins::cache::entity::ENTITY_CACHE_VERSION;
2322
use crate::plugins::cache::entity::hash_entity_key;
2423

@@ -109,7 +108,8 @@ impl Invalidation {
109108
key_prefix
110109
);
111110

112-
let mut stream = redis_storage.scan(key_prefix.clone(), Some(self.scan_count));
111+
let mut stream =
112+
redis_storage.scan_with_namespaced_results(key_prefix.clone(), Some(self.scan_count));
113113
let mut count = 0u64;
114114
let mut error = None;
115115

@@ -124,15 +124,13 @@ impl Invalidation {
124124
error = Some(e);
125125
break;
126126
}
127-
Ok(scan_res) => {
128-
if let Some(keys) = scan_res.results() {
129-
let keys = keys
130-
.iter()
131-
.filter_map(|k| k.as_str())
132-
.map(|k| RedisKey(k.to_string()))
133-
.collect::<Vec<_>>();
127+
Ok(mut scan_res) => {
128+
if let Some(keys) = scan_res.take_results() {
134129
if !keys.is_empty() {
135-
let deleted = redis_storage.delete(keys).await.unwrap_or(0) as u64;
130+
let deleted = redis_storage
131+
.delete_from_scan_result(keys)
132+
.await
133+
.unwrap_or(0) as u64;
136134
count += deleted;
137135
}
138136
}

apollo-router/src/plugins/mock_subgraphs/mod.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,7 @@ fn resolve_normal_field<'a>(
253253
field_name: &'a str,
254254
arguments: &'a JsonMap,
255255
) -> Result<ResolvedValue<'a>, execution::resolver::ResolverError> {
256-
if !arguments.is_empty() {
257-
return Err("arguments not supported".into()); // TODO?
258-
}
256+
let _ignored = arguments; // TODO: find some way to vary response based on arguments?
259257
let mock = mocks
260258
.get(field_name)
261259
.ok_or("field not found in mocked data")?;

apollo-router/src/services/router/body.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ pub(crate) async fn into_bytes<B: HttpBody>(body: B) -> Result<Bytes, B::Error>
2020
// and convert types
2121

2222
/// Create an empty RouterBody
23-
pub(crate) fn empty() -> UnsyncBoxBody<Bytes, AxumError> {
23+
pub(crate) fn empty() -> RouterBody {
2424
Empty::<Bytes>::new()
2525
.map_err(|never| match never {})
2626
.boxed_unsync()
2727
}
2828

2929
/// Create a Full RouterBody using the supplied chunk
30-
pub(crate) fn from_bytes<T: Into<Bytes>>(chunk: T) -> UnsyncBoxBody<Bytes, AxumError> {
30+
pub fn from_bytes<T: Into<Bytes>>(chunk: T) -> RouterBody {
3131
Full::new(chunk.into())
3232
.map_err(|never| match never {})
3333
.boxed_unsync()

apollo-router/src/test_harness.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ use crate::services::router::service::RouterCreator;
3535
use crate::services::subgraph;
3636
use crate::services::supergraph;
3737
use crate::spec::Schema;
38-
#[cfg(test)]
3938
use crate::uplink::license_enforcement::LicenseState;
4039

4140
/// Mocks for services the Apollo Router must integrate with.
@@ -340,10 +339,10 @@ impl<'a> TestHarness<'a> {
340339
.boxed_clone())
341340
}
342341

343-
#[cfg(test)]
344-
pub(crate) async fn build_http_service(self) -> Result<HttpService, BoxError> {
342+
/// Build the HTTP service
343+
pub async fn build_http_service(self) -> Result<HttpService, BoxError> {
345344
use crate::axum_factory::ListenAddrAndRouter;
346-
use crate::axum_factory::tests::make_axum_router;
345+
use crate::axum_factory::axum_http_server_factory::make_axum_router;
347346
use crate::router_factory::RouterFactory;
348347

349348
let (config, supergraph_creator) = self.build_common().await?;
@@ -369,8 +368,7 @@ impl<'a> TestHarness<'a> {
369368
}
370369

371370
/// An HTTP-level service, as would be given to Hyper’s server
372-
#[cfg(test)]
373-
pub(crate) type HttpService = tower::util::BoxService<
371+
pub type HttpService = tower::util::BoxService<
374372
http::Request<crate::services::router::Body>,
375373
http::Response<axum::body::Body>,
376374
std::convert::Infallible,

0 commit comments

Comments
 (0)