mod common;
use glide::CustomCommand;
resp_test!(publish_no_subscribers_returns_zero, c, {
let chan = common::key("chan");
let received = c
.custom_command(&["PUBLISH", &chan, "hello"])
.await
.unwrap();
assert_eq!(glide::value::to_i64(received).unwrap(), 0);
});
mod glob_import_lock {
use glide::*;
pub async fn publish_via_glob(c: &GlideClient, chan: &str) -> RedisResult<i64> {
c.publish(chan, "nobody-listens").await
}
}
resp_test!(glob_import_publish_resolves_unambiguously, c, {
let n = glob_import_lock::publish_via_glob(&c, &common::key("glob_pub"))
.await
.unwrap();
assert_eq!(n, 0);
});
resp_test!(pubsub_channels_empty, c, {
let reply = c.custom_command(&["PUBSUB", "CHANNELS"]).await.unwrap();
match reply {
glide::Value::Array(items) => assert!(items.is_empty()),
glide::Value::Nil => {}
other => panic!("unexpected PUBSUB CHANNELS reply: {other:?}"),
}
});
resp_test!(pubsub_numpat_zero, c, {
let reply = c.custom_command(&["PUBSUB", "NUMPAT"]).await.unwrap();
assert_eq!(glide::value::to_i64(reply).unwrap(), 0);
});
resp_test!(spublish_no_subscribers, c, {
let chan = common::key("schan");
match c.custom_command(&["SPUBLISH", &chan, "msg"]).await {
Ok(v) => assert_eq!(glide::value::to_i64(v).unwrap(), 0),
Err(glide::GlideError::Request(_)) => {}
Err(other) => panic!("unexpected: {other:?}"),
}
});
timed_tokio_test!(
async fn runtime_subscribe_receives_then_unsubscribe() {
use glide::AsyncCommands;
use glide::commands::pubsub::PubSubCommands;
use glide::{GlideClient, GlideClientConfiguration};
use std::time::Duration;
let srv = match common::TestServer::start() {
Some(s) => s,
None => {
eprintln!("SKIP: no valkey-server binary available");
return;
}
};
let chan = common::key("rt-chan");
let subscriber = GlideClient::connect(
GlideClientConfiguration::with_address("127.0.0.1", srv.port).enable_pubsub(),
)
.await
.expect("connect subscriber");
let publisher = srv.client().await;
subscriber.subscribe(&[chan.as_str()]).await.unwrap();
assert!(
common::wait_for_numsub(&publisher, &chan, |n| n >= 1, Duration::from_secs(3)).await,
"subscription was not registered server-side in time"
);
let n: i64 = publisher.publish(&chan, "runtime-hello").await.unwrap();
assert!(n >= 1, "expected >=1 subscriber, got {n}");
let msg = tokio::time::timeout(Duration::from_secs(3), subscriber.get_pubsub_message())
.await
.expect("timed out waiting for runtime-subscribed message")
.expect("receive error");
assert_eq!(msg.channel.as_ref(), chan.as_bytes());
assert_eq!(msg.payload.as_ref(), b"runtime-hello");
subscriber.unsubscribe(&[chan.as_str()]).await.unwrap();
assert!(
common::wait_for_numsub(&publisher, &chan, |n| n == 0, Duration::from_secs(3)).await,
"unsubscribe did not take effect server-side in time"
);
let n2: i64 = publisher.publish(&chan, "after-unsub").await.unwrap();
assert_eq!(n2, 0, "no subscribers should remain after unsubscribe");
}
);
timed_tokio_test!(
async fn runtime_psubscribe_pattern_receive() {
use glide::AsyncCommands;
use glide::commands::pubsub::PubSubCommands;
use glide::{GlideClient, GlideClientConfiguration, PubSubMessageKind};
use std::time::Duration;
let srv = match common::TestServer::start() {
Some(s) => s,
None => {
eprintln!("SKIP: no valkey-server binary available");
return;
}
};
let subscriber = GlideClient::connect(
GlideClientConfiguration::with_address("127.0.0.1", srv.port).enable_pubsub(),
)
.await
.expect("connect subscriber");
let publisher = srv.client().await;
subscriber.psubscribe(&["news.*"]).await.unwrap();
assert!(
common::wait_for_numpat(&publisher, |n| n >= 1, Duration::from_secs(3)).await,
"pattern subscription was not registered server-side in time"
);
let _: i64 = publisher.publish("news.tech", "breaking").await.unwrap();
let msg = tokio::time::timeout(Duration::from_secs(3), subscriber.get_pubsub_message())
.await
.expect("timed out")
.expect("receive error");
assert_eq!(msg.kind, PubSubMessageKind::PMessage);
assert_eq!(msg.channel.as_ref(), b"news.tech");
assert_eq!(msg.pattern.as_deref(), Some(&b"news.*"[..]));
}
);
timed_tokio_test!(
async fn runtime_unsubscribe_all_stops_delivery() {
use glide::AsyncCommands;
use glide::commands::pubsub::PubSubCommands;
use glide::{GlideClient, GlideClientConfiguration};
use std::time::Duration;
let srv = match common::TestServer::start() {
Some(s) => s,
None => {
eprintln!("SKIP: no valkey-server binary available");
return;
}
};
let c1 = common::key("uc1");
let c2 = common::key("uc2");
let subscriber = GlideClient::connect(
GlideClientConfiguration::with_address("127.0.0.1", srv.port).enable_pubsub(),
)
.await
.expect("connect subscriber");
subscriber
.subscribe(&[c1.as_str(), c2.as_str()])
.await
.unwrap();
let publisher = srv.client().await;
assert!(
common::wait_for_numsub(&publisher, &c1, |n| n >= 1, Duration::from_secs(3)).await,
"subscription c1 not registered in time"
);
assert!(publisher.publish::<_, _, i64>(&c1, "x").await.unwrap() >= 1);
subscriber.unsubscribe(&[] as &[&str]).await.unwrap();
assert!(
common::wait_for_numsub(&publisher, &c1, |n| n == 0, Duration::from_secs(3)).await
&& common::wait_for_numsub(&publisher, &c2, |n| n == 0, Duration::from_secs(3))
.await,
"unsubscribe-all did not take effect server-side in time"
);
assert_eq!(publisher.publish::<_, _, i64>(&c1, "y").await.unwrap(), 0);
assert_eq!(publisher.publish::<_, _, i64>(&c2, "z").await.unwrap(), 0);
}
);