mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-06 07:28:23 +00:00
remove stupid tests and methods
This commit is contained in:
+19
-22
@@ -70,10 +70,8 @@ impl SyncConnection {
|
||||
tracing::info!("Sync connection established to {}", url);
|
||||
|
||||
// Create subscription manager for this connection
|
||||
let subscription_manager = SubscriptionManager::new(
|
||||
filter_service.clone(),
|
||||
remote_domain.to_string(),
|
||||
);
|
||||
let subscription_manager =
|
||||
SubscriptionManager::new(filter_service.clone(), remote_domain.to_string());
|
||||
|
||||
Ok(Self {
|
||||
url: url.to_string(),
|
||||
@@ -208,10 +206,8 @@ impl SyncConnection {
|
||||
/// - kind 30617/30618: New announcement → add Layer 2 subscription
|
||||
/// - kind 1617/1618/1619/1621/1622: New PR/Issue → add Layer 3 subscription
|
||||
async fn handle_dynamic_subscription(&mut self, event: &Event) {
|
||||
let kind = event.kind.as_u16();
|
||||
|
||||
// Check if this is an announcement kind (triggers Layer 2 subscription)
|
||||
if SubscriptionManager::is_announcement_kind(kind) {
|
||||
if matches!(event.kind, Kind::GitRepoAnnouncement | Kind::RepoState) {
|
||||
if let Some(new_filters) = self.subscription_manager.add_announcement(event) {
|
||||
tracing::info!(
|
||||
"New announcement {} on {}, adding {} Layer 2 filter(s) (total filters: {})",
|
||||
@@ -224,8 +220,11 @@ impl SyncConnection {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this is a PR/Issue kind (triggers Layer 3 subscription)
|
||||
if SubscriptionManager::is_pr_issue_kind(kind) {
|
||||
// Check if this is a Patch/PR/Issue kind (triggers Layer 3 subscription)
|
||||
if matches!(
|
||||
event.kind,
|
||||
Kind::GitPatch | Kind::GitIssue | Kind::Custom(1618)
|
||||
) {
|
||||
if let Some(new_filters) = self.subscription_manager.add_event(event) {
|
||||
tracing::info!(
|
||||
"New PR/Issue {} on {}, adding {} Layer 3 filter(s) (total filters: {})",
|
||||
@@ -366,11 +365,13 @@ pub async fn connect_with_retry(
|
||||
);
|
||||
}
|
||||
|
||||
match SyncConnection::new(url, filter_service.clone(), &remote_domain, metrics.clone()).await {
|
||||
match SyncConnection::new(url, filter_service.clone(), &remote_domain, metrics.clone())
|
||||
.await
|
||||
{
|
||||
Ok(conn) => {
|
||||
// Record successful connection
|
||||
health_tracker.record_success(url);
|
||||
|
||||
|
||||
// Record metrics
|
||||
if let Some(ref m) = metrics {
|
||||
m.record_connection_attempt(url, true);
|
||||
@@ -379,7 +380,7 @@ pub async fn connect_with_retry(
|
||||
m.record_health_state(url, health_tracker.get_state(url));
|
||||
m.record_failure_count(url, 0);
|
||||
}
|
||||
|
||||
|
||||
tracing::info!("Sync connection established to {}", url);
|
||||
|
||||
// Run the connection (this blocks until disconnection)
|
||||
@@ -388,7 +389,7 @@ pub async fn connect_with_retry(
|
||||
// Connection ended - record as failure for reconnection backoff
|
||||
// (The connection ending is considered a failure even if it worked for a while)
|
||||
health_tracker.record_failure(url);
|
||||
|
||||
|
||||
// Update metrics for disconnection
|
||||
if let Some(ref m) = metrics {
|
||||
m.set_relay_connected(url, false);
|
||||
@@ -396,7 +397,7 @@ pub async fn connect_with_retry(
|
||||
m.record_health_state(url, health_tracker.get_state(url));
|
||||
m.record_failure_count(url, health_tracker.get_failure_count(url));
|
||||
}
|
||||
|
||||
|
||||
tracing::warn!("Sync connection to {} ended, will reconnect", url);
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -405,14 +406,14 @@ pub async fn connect_with_retry(
|
||||
|
||||
let failure_count = health_tracker.get_failure_count(url);
|
||||
let state = health_tracker.get_state(url);
|
||||
|
||||
|
||||
// Record metrics
|
||||
if let Some(ref m) = metrics {
|
||||
m.record_connection_attempt(url, false);
|
||||
m.set_relay_connected(url, false);
|
||||
m.record_health_state(url, state);
|
||||
m.record_failure_count(url, failure_count);
|
||||
|
||||
|
||||
// Track dead relays
|
||||
if state == super::health::HealthState::Dead {
|
||||
m.inc_dead_count();
|
||||
@@ -435,11 +436,7 @@ pub async fn connect_with_retry(
|
||||
.get_remaining_backoff(url)
|
||||
.unwrap_or(Duration::from_secs(5));
|
||||
|
||||
tracing::debug!(
|
||||
"Waiting {:?} before reconnecting to {}",
|
||||
wait_duration,
|
||||
url
|
||||
);
|
||||
tracing::debug!("Waiting {:?} before reconnecting to {}", wait_duration, url);
|
||||
tokio::time::sleep(wait_duration).await;
|
||||
}
|
||||
}
|
||||
@@ -473,4 +470,4 @@ mod tests {
|
||||
Some("relay.example.com".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-60
@@ -26,12 +26,6 @@ use super::filter::FilterService;
|
||||
/// Maximum number of filters before consolidation is triggered
|
||||
const CONSOLIDATION_THRESHOLD: usize = 150;
|
||||
|
||||
/// Kind 30617 - Repository Announcement (NIP-34)
|
||||
const KIND_REPOSITORY_ANNOUNCEMENT: u16 = 30617;
|
||||
|
||||
/// Kind 30618 - Maintainer List (NIP-34)
|
||||
const KIND_MAINTAINER_LIST: u16 = 30618;
|
||||
|
||||
/// Manages subscriptions for a single relay connection
|
||||
///
|
||||
/// Tracks which announcements and events have been subscribed to,
|
||||
@@ -113,10 +107,7 @@ impl SubscriptionManager {
|
||||
|
||||
// Build Layer 3 filter for this event
|
||||
// Layer 3 filters target events with 'e' tags pointing to this event
|
||||
let filter = Filter::new().custom_tag(
|
||||
SingleLetterTag::lowercase(Alphabet::E),
|
||||
event_id,
|
||||
);
|
||||
let filter = Filter::new().custom_tag(SingleLetterTag::lowercase(Alphabet::E), event_id);
|
||||
|
||||
Some(vec![filter])
|
||||
}
|
||||
@@ -212,67 +203,27 @@ impl SubscriptionManager {
|
||||
}
|
||||
};
|
||||
|
||||
// Determine the kind for the coordinate
|
||||
let kind = event.kind.as_u16();
|
||||
if kind != KIND_REPOSITORY_ANNOUNCEMENT && kind != KIND_MAINTAINER_LIST {
|
||||
// Verify this is an announcement kind
|
||||
if !matches!(event.kind, Kind::GitRepoAnnouncement | Kind::RepoState) {
|
||||
tracing::warn!(
|
||||
"Event {} is not an announcement (kind {}), cannot build Layer 2 filter",
|
||||
event.id.to_hex(),
|
||||
kind
|
||||
event.kind
|
||||
);
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// Build the addressable coordinate: kind:pubkey:identifier
|
||||
let coord = format!("{}:{}:{}", kind, event.pubkey.to_hex(), identifier);
|
||||
let coord = format!(
|
||||
"{}:{}:{}",
|
||||
event.kind.as_u16(),
|
||||
event.pubkey.to_hex(),
|
||||
identifier
|
||||
);
|
||||
|
||||
// Create filter with 'a' tag for this coordinate
|
||||
let filter = Filter::new().custom_tag(
|
||||
SingleLetterTag::lowercase(Alphabet::A),
|
||||
coord,
|
||||
);
|
||||
let filter = Filter::new().custom_tag(SingleLetterTag::lowercase(Alphabet::A), coord);
|
||||
|
||||
vec![filter]
|
||||
}
|
||||
|
||||
/// Check if an event kind is an announcement kind
|
||||
pub fn is_announcement_kind(kind: u16) -> bool {
|
||||
kind == KIND_REPOSITORY_ANNOUNCEMENT || kind == KIND_MAINTAINER_LIST
|
||||
}
|
||||
|
||||
/// Check if an event kind is a PR/Issue/Patch kind that should trigger Layer 3
|
||||
pub fn is_pr_issue_kind(kind: u16) -> bool {
|
||||
matches!(
|
||||
kind,
|
||||
1617 | // Patch proposal (NIP-34)
|
||||
1618 | // PR
|
||||
1619 | // PR Update
|
||||
1621 | // Issue
|
||||
1622 // Reply
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::SubscriptionManager;
|
||||
|
||||
#[test]
|
||||
fn test_is_announcement_kind() {
|
||||
assert!(SubscriptionManager::is_announcement_kind(30617));
|
||||
assert!(SubscriptionManager::is_announcement_kind(30618));
|
||||
assert!(!SubscriptionManager::is_announcement_kind(1));
|
||||
assert!(!SubscriptionManager::is_announcement_kind(1617));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_pr_issue_kind() {
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1617));
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1618));
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1619));
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1621));
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1622));
|
||||
assert!(!SubscriptionManager::is_pr_issue_kind(30617));
|
||||
assert!(!SubscriptionManager::is_pr_issue_kind(1));
|
||||
}
|
||||
}
|
||||
+43
-126
@@ -16,89 +16,6 @@
|
||||
|
||||
use ngit_grasp::sync::SubscriptionManager;
|
||||
|
||||
// ============================================================================
|
||||
// Configuration Constants Tests
|
||||
// ============================================================================
|
||||
|
||||
/// Test that default startup delay is 30 seconds
|
||||
#[test]
|
||||
fn test_default_startup_delay_is_30_seconds() {
|
||||
// The spec requires 30s warm-up before startup catchup
|
||||
const EXPECTED_STARTUP_DELAY: u64 = 30;
|
||||
|
||||
// This is defined in negentropy.rs as DEFAULT_STARTUP_DELAY_SECS
|
||||
// We verify the expected value matches the spec
|
||||
assert_eq!(EXPECTED_STARTUP_DELAY, 30);
|
||||
}
|
||||
|
||||
/// Test that default reconnect delay is 10 seconds
|
||||
#[test]
|
||||
fn test_default_reconnect_delay_is_10_seconds() {
|
||||
// The spec requires 10s delay after reconnection before catchup
|
||||
const EXPECTED_RECONNECT_DELAY: u64 = 10;
|
||||
assert_eq!(EXPECTED_RECONNECT_DELAY, 10);
|
||||
}
|
||||
|
||||
/// Test that reconnect lookback is 3 days
|
||||
#[test]
|
||||
fn test_reconnect_lookback_is_3_days() {
|
||||
// The spec requires 3 days lookback for reconnect catchup
|
||||
const EXPECTED_LOOKBACK_DAYS: u64 = 3;
|
||||
const EXPECTED_LOOKBACK_SECS: u64 = 3 * 24 * 60 * 60; // 259,200 seconds
|
||||
|
||||
assert_eq!(EXPECTED_LOOKBACK_DAYS, 3);
|
||||
assert_eq!(EXPECTED_LOOKBACK_SECS, 259200);
|
||||
}
|
||||
|
||||
/// Test daily catchup interval is 24 hours
|
||||
#[test]
|
||||
fn test_daily_catchup_interval_is_24_hours() {
|
||||
// The spec requires daily catchup once per 24 hours
|
||||
const EXPECTED_DAILY_INTERVAL_SECS: u64 = 86400; // 24 * 60 * 60
|
||||
assert_eq!(EXPECTED_DAILY_INTERVAL_SECS, 86400);
|
||||
}
|
||||
|
||||
/// Test relay stagger delay is 5 minutes
|
||||
#[test]
|
||||
fn test_relay_stagger_is_5_minutes() {
|
||||
// The spec requires 5-minute stagger between relays for catchup
|
||||
const EXPECTED_STAGGER_SECS: u64 = 300; // 5 * 60
|
||||
assert_eq!(EXPECTED_STAGGER_SECS, 300);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Filter Compatibility Tests
|
||||
// ============================================================================
|
||||
|
||||
/// Test that catchup uses announcement kinds (30617, 30618)
|
||||
#[test]
|
||||
fn test_catchup_uses_announcement_kinds() {
|
||||
// Layer 1 filters should include announcement kinds
|
||||
assert!(SubscriptionManager::is_announcement_kind(30617));
|
||||
assert!(SubscriptionManager::is_announcement_kind(30618));
|
||||
}
|
||||
|
||||
/// Test that catchup uses PR/Issue kinds for Layer 3
|
||||
#[test]
|
||||
fn test_catchup_uses_pr_issue_kinds() {
|
||||
// Layer 3 should track PR and Issue kinds
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1617)); // Patch proposal
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1618)); // PR
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1619)); // PR Update
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1621)); // Issue
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1622)); // Reply
|
||||
}
|
||||
|
||||
/// Test that non-sync kinds are not included in catchup
|
||||
#[test]
|
||||
fn test_catchup_excludes_non_sync_kinds() {
|
||||
// Regular text notes and other kinds should not be included
|
||||
assert!(!SubscriptionManager::is_announcement_kind(1)); // Text note
|
||||
assert!(!SubscriptionManager::is_announcement_kind(4)); // DM
|
||||
assert!(!SubscriptionManager::is_pr_issue_kind(1)); // Text note
|
||||
assert!(!SubscriptionManager::is_pr_issue_kind(30617)); // Announcement (wrong layer)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Catchup State Machine Tests
|
||||
// ============================================================================
|
||||
@@ -108,17 +25,17 @@ fn test_catchup_excludes_non_sync_kinds() {
|
||||
fn test_startup_catchup_runs_once() {
|
||||
// After startup catchup completes, should_run_startup_catchup should return false
|
||||
// This is handled by the startup_catchup_completed flag in NegentropyService
|
||||
|
||||
|
||||
// Simulating the state machine:
|
||||
let mut startup_completed = false;
|
||||
|
||||
|
||||
// Before running, should return true (if delay elapsed)
|
||||
let should_run_before = !startup_completed;
|
||||
assert!(should_run_before);
|
||||
|
||||
|
||||
// After running, mark as completed
|
||||
startup_completed = true;
|
||||
|
||||
|
||||
// Now should return false
|
||||
let should_run_after = !startup_completed;
|
||||
assert!(!should_run_after);
|
||||
@@ -128,12 +45,12 @@ fn test_startup_catchup_runs_once() {
|
||||
#[test]
|
||||
fn test_daily_catchup_interval_check() {
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
|
||||
const DAILY_INTERVAL_SECS: u64 = 86400;
|
||||
|
||||
|
||||
// Simulate last catchup time
|
||||
let last_catchup = Instant::now();
|
||||
|
||||
|
||||
// Immediately after, should not run
|
||||
let should_run_immediately = last_catchup.elapsed() >= Duration::from_secs(DAILY_INTERVAL_SECS);
|
||||
assert!(!should_run_immediately);
|
||||
@@ -144,10 +61,10 @@ fn test_daily_catchup_interval_check() {
|
||||
fn test_new_relay_should_run_daily_catchup() {
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
|
||||
|
||||
let last_daily_catchup: HashMap<String, Instant> = HashMap::new();
|
||||
let relay_url = "wss://test-relay.example.com";
|
||||
|
||||
|
||||
// No previous catchup recorded, should return true
|
||||
let should_run = !last_daily_catchup.contains_key(relay_url);
|
||||
assert!(should_run);
|
||||
@@ -159,14 +76,14 @@ fn test_reconnect_catchup_after_reconnection() {
|
||||
// Reconnect catchup should only trigger when:
|
||||
// 1. Connection was previously successful (had_previous_connection = true)
|
||||
// 2. Connection was lost and restored
|
||||
|
||||
|
||||
let mut had_previous_connection = false;
|
||||
|
||||
|
||||
// First connection - should NOT trigger reconnect catchup
|
||||
let is_reconnection_first = had_previous_connection;
|
||||
assert!(!is_reconnection_first);
|
||||
had_previous_connection = true;
|
||||
|
||||
|
||||
// Second connection (after disconnection) - SHOULD trigger
|
||||
let is_reconnection_second = had_previous_connection;
|
||||
assert!(is_reconnection_second);
|
||||
@@ -185,10 +102,10 @@ fn test_gap_events_validated_through_policy() {
|
||||
// 2. Check if event exists locally
|
||||
// 3. Validate through Nip34WritePolicy
|
||||
// 4. Store if accepted
|
||||
|
||||
|
||||
// This is verified by the implementation in negentropy.rs:run_catchup()
|
||||
// where PolicyResult::Accept leads to storage and PolicyResult::Reject is logged
|
||||
|
||||
|
||||
assert!(true); // Flow verification - actual validation tested in other tests
|
||||
}
|
||||
|
||||
@@ -197,14 +114,14 @@ fn test_gap_events_validated_through_policy() {
|
||||
fn test_gap_events_logged_at_warn_level() {
|
||||
// The spec requires gap events to be logged at WARN level
|
||||
// to distinguish them from live events (which are logged at INFO)
|
||||
|
||||
|
||||
// This is implemented in negentropy.rs with:
|
||||
// tracing::warn!("Gap event filled via {} catchup: {} (kind {})", ...)
|
||||
|
||||
|
||||
// We verify the logging pattern exists by testing the catchup types
|
||||
let catchup_types = ["startup", "reconnect", "daily"];
|
||||
assert_eq!(catchup_types.len(), 3);
|
||||
|
||||
|
||||
for catchup_type in catchup_types {
|
||||
assert!(!catchup_type.is_empty());
|
||||
}
|
||||
@@ -218,21 +135,21 @@ fn test_gap_events_logged_at_warn_level() {
|
||||
#[test]
|
||||
fn test_stagger_delay_for_multiple_relays() {
|
||||
const STAGGER_SECS: u64 = 300; // 5 minutes
|
||||
|
||||
|
||||
let _relay_urls = vec![
|
||||
"wss://relay1.example.com",
|
||||
"wss://relay2.example.com",
|
||||
"wss://relay2.example.com",
|
||||
"wss://relay3.example.com",
|
||||
];
|
||||
|
||||
|
||||
// First relay (index 0) should have no stagger
|
||||
let stagger_0 = 0 * STAGGER_SECS;
|
||||
assert_eq!(stagger_0, 0);
|
||||
|
||||
|
||||
// Second relay (index 1) should have 5 minute stagger
|
||||
let stagger_1 = 1 * STAGGER_SECS;
|
||||
assert_eq!(stagger_1, 300);
|
||||
|
||||
|
||||
// Third relay (index 2) should have 10 minute stagger
|
||||
let stagger_2 = 2 * STAGGER_SECS;
|
||||
assert_eq!(stagger_2, 600);
|
||||
@@ -242,15 +159,15 @@ fn test_stagger_delay_for_multiple_relays() {
|
||||
#[test]
|
||||
fn test_startup_catchup_waits_for_warmup() {
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
|
||||
const STARTUP_DELAY_SECS: u64 = 30;
|
||||
|
||||
|
||||
let startup_time = Instant::now();
|
||||
|
||||
|
||||
// Immediately after startup, should not run (delay not elapsed)
|
||||
let elapsed = startup_time.elapsed();
|
||||
let should_run = elapsed >= Duration::from_secs(STARTUP_DELAY_SECS);
|
||||
|
||||
|
||||
// This should be false since we just created startup_time
|
||||
assert!(!should_run);
|
||||
}
|
||||
@@ -265,7 +182,7 @@ fn test_reconnect_lookback_calculation() {
|
||||
// 3 days = 3 * 24 * 60 * 60 = 259,200 seconds
|
||||
let lookback_days: u64 = 3;
|
||||
let lookback_secs = lookback_days * 24 * 60 * 60;
|
||||
|
||||
|
||||
assert_eq!(lookback_secs, 259200);
|
||||
}
|
||||
|
||||
@@ -290,10 +207,10 @@ fn test_startup_catchup_scenario() {
|
||||
// 2. Run full reconciliation (no time limit)
|
||||
// 3. Mark as completed (runs only once)
|
||||
// 4. Stagger between relays (5 minutes)
|
||||
|
||||
|
||||
const STARTUP_DELAY: u64 = 30;
|
||||
const STAGGER: u64 = 300;
|
||||
|
||||
|
||||
assert_eq!(STARTUP_DELAY, 30);
|
||||
assert_eq!(STAGGER, 300);
|
||||
}
|
||||
@@ -306,10 +223,10 @@ fn test_reconnect_catchup_scenario() {
|
||||
// 2. Wait 10s reconnect delay
|
||||
// 3. Only fetch last 3 days of events
|
||||
// 4. Runs in background (doesn't block connection)
|
||||
|
||||
|
||||
const RECONNECT_DELAY: u64 = 10;
|
||||
const LOOKBACK_DAYS: u64 = 3;
|
||||
|
||||
|
||||
assert_eq!(RECONNECT_DELAY, 10);
|
||||
assert_eq!(LOOKBACK_DAYS, 3);
|
||||
}
|
||||
@@ -322,11 +239,11 @@ fn test_daily_catchup_scenario() {
|
||||
// 2. Run if 24h elapsed since last catchup for that relay
|
||||
// 3. Full reconciliation (no time limit)
|
||||
// 4. Stagger between relays (5 minutes)
|
||||
|
||||
|
||||
const CHECK_INTERVAL: u64 = 3600; // 1 hour
|
||||
const DAILY_INTERVAL: u64 = 86400; // 24 hours
|
||||
const STAGGER: u64 = 300; // 5 minutes
|
||||
|
||||
|
||||
assert_eq!(CHECK_INTERVAL, 3600);
|
||||
assert_eq!(DAILY_INTERVAL, 86400);
|
||||
assert_eq!(STAGGER, 300);
|
||||
@@ -343,10 +260,10 @@ fn test_existing_events_skipped() {
|
||||
// 1. Fetch events from relay
|
||||
// 2. For each event, check if it exists locally
|
||||
// 3. Skip if exists, validate and store if not
|
||||
|
||||
|
||||
// This is implemented in negentropy.rs:event_exists_locally()
|
||||
// which queries the database for the event by ID
|
||||
|
||||
|
||||
const SKIP_EXISTING: bool = true;
|
||||
assert!(SKIP_EXISTING);
|
||||
}
|
||||
@@ -355,15 +272,15 @@ fn test_existing_events_skipped() {
|
||||
#[test]
|
||||
fn test_duplicate_prevention() {
|
||||
use std::collections::HashSet;
|
||||
|
||||
|
||||
let mut processed_ids: HashSet<String> = HashSet::new();
|
||||
let event_id = "abc123def456".to_string();
|
||||
|
||||
|
||||
// First time seeing this event - should process
|
||||
let is_new = !processed_ids.contains(&event_id);
|
||||
assert!(is_new);
|
||||
processed_ids.insert(event_id.clone());
|
||||
|
||||
|
||||
// Second time - should skip
|
||||
let is_duplicate = processed_ids.contains(&event_id);
|
||||
assert!(is_duplicate);
|
||||
@@ -380,18 +297,18 @@ fn test_config_fields_for_catchup() {
|
||||
// - sync_startup_delay_secs (default: 30)
|
||||
// - sync_reconnect_delay_secs (default: 10)
|
||||
// - sync_reconnect_lookback_days (default: 3)
|
||||
|
||||
|
||||
// Environment variables:
|
||||
// - NGIT_SYNC_STARTUP_DELAY_SECS
|
||||
// - NGIT_SYNC_RECONNECT_DELAY_SECS
|
||||
// - NGIT_SYNC_RECONNECT_LOOKBACK_DAYS
|
||||
|
||||
|
||||
let expected_defaults = vec![
|
||||
("startup_delay_secs", 30u64),
|
||||
("reconnect_delay_secs", 10u64),
|
||||
("reconnect_lookback_days", 3u64),
|
||||
];
|
||||
|
||||
|
||||
assert_eq!(expected_defaults.len(), 3);
|
||||
assert_eq!(expected_defaults[0].1, 30);
|
||||
assert_eq!(expected_defaults[1].1, 10);
|
||||
@@ -405,9 +322,9 @@ fn test_catchup_respects_config() {
|
||||
let custom_startup_delay: u64 = 60;
|
||||
let custom_reconnect_delay: u64 = 20;
|
||||
let custom_lookback_days: u64 = 7;
|
||||
|
||||
|
||||
// All should be configurable to non-default values
|
||||
assert_ne!(custom_startup_delay, 30);
|
||||
assert_ne!(custom_reconnect_delay, 10);
|
||||
assert_ne!(custom_lookback_days, 3);
|
||||
}
|
||||
}
|
||||
|
||||
+100
-187
@@ -116,69 +116,6 @@ fn create_test_reply_event(keys: &Keys, event_id: &str) -> Event {
|
||||
.expect("Failed to sign event")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Kind Detection Tests
|
||||
// ============================================================================
|
||||
|
||||
/// Test that announcement kinds are correctly identified
|
||||
#[test]
|
||||
fn test_is_announcement_kind_30617() {
|
||||
assert!(SubscriptionManager::is_announcement_kind(30617));
|
||||
}
|
||||
|
||||
/// Test that maintainer list kind is correctly identified
|
||||
#[test]
|
||||
fn test_is_announcement_kind_30618() {
|
||||
assert!(SubscriptionManager::is_announcement_kind(30618));
|
||||
}
|
||||
|
||||
/// Test that non-announcement kinds are not identified as announcements
|
||||
#[test]
|
||||
fn test_is_announcement_kind_negative() {
|
||||
assert!(!SubscriptionManager::is_announcement_kind(1)); // Text note
|
||||
assert!(!SubscriptionManager::is_announcement_kind(1617)); // PR
|
||||
assert!(!SubscriptionManager::is_announcement_kind(1621)); // Issue
|
||||
assert!(!SubscriptionManager::is_announcement_kind(0)); // Unknown
|
||||
}
|
||||
|
||||
/// Test that PR/Issue kinds are correctly identified
|
||||
#[test]
|
||||
fn test_is_pr_issue_kind_1617() {
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1617)); // Patch proposal
|
||||
}
|
||||
|
||||
/// Test that PR kind 1618 is correctly identified
|
||||
#[test]
|
||||
fn test_is_pr_issue_kind_1618() {
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1618)); // PR
|
||||
}
|
||||
|
||||
/// Test that PR update kind is correctly identified
|
||||
#[test]
|
||||
fn test_is_pr_issue_kind_1619() {
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1619)); // PR Update
|
||||
}
|
||||
|
||||
/// Test that Issue kind is correctly identified
|
||||
#[test]
|
||||
fn test_is_pr_issue_kind_1621() {
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1621)); // Issue
|
||||
}
|
||||
|
||||
/// Test that Reply kind is correctly identified
|
||||
#[test]
|
||||
fn test_is_pr_issue_kind_1622() {
|
||||
assert!(SubscriptionManager::is_pr_issue_kind(1622)); // Reply
|
||||
}
|
||||
|
||||
/// Test that non-PR/Issue kinds are not identified
|
||||
#[test]
|
||||
fn test_is_pr_issue_kind_negative() {
|
||||
assert!(!SubscriptionManager::is_pr_issue_kind(30617)); // Announcement
|
||||
assert!(!SubscriptionManager::is_pr_issue_kind(1)); // Text note
|
||||
assert!(!SubscriptionManager::is_pr_issue_kind(0)); // Unknown
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Filter Count Tests
|
||||
// ============================================================================
|
||||
@@ -188,19 +125,19 @@ fn test_is_pr_issue_kind_negative() {
|
||||
fn test_initial_filter_count() {
|
||||
// Create a minimal SubscriptionManager-like state for testing
|
||||
// We test the logic without needing a full FilterService
|
||||
|
||||
|
||||
// Initial state: 0 announcements, 0 events, not consolidated
|
||||
// Filter count should be: 1 (Layer 1) + 0 + 0 = 1
|
||||
let announcement_count = 0;
|
||||
let event_count = 0;
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
let filter_count = if is_consolidated {
|
||||
1
|
||||
} else {
|
||||
1 + announcement_count + event_count
|
||||
};
|
||||
|
||||
|
||||
assert_eq!(filter_count, 1);
|
||||
}
|
||||
|
||||
@@ -210,13 +147,13 @@ fn test_filter_count_with_announcements() {
|
||||
let announcement_count = 5;
|
||||
let event_count = 0;
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
let filter_count = if is_consolidated {
|
||||
1
|
||||
} else {
|
||||
1 + announcement_count + event_count
|
||||
};
|
||||
|
||||
|
||||
// 1 (Layer 1) + 5 (announcements) = 6
|
||||
assert_eq!(filter_count, 6);
|
||||
}
|
||||
@@ -227,13 +164,13 @@ fn test_filter_count_with_events() {
|
||||
let announcement_count = 0;
|
||||
let event_count = 10;
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
let filter_count = if is_consolidated {
|
||||
1
|
||||
} else {
|
||||
1 + announcement_count + event_count
|
||||
};
|
||||
|
||||
|
||||
// 1 (Layer 1) + 10 (events) = 11
|
||||
assert_eq!(filter_count, 11);
|
||||
}
|
||||
@@ -244,13 +181,13 @@ fn test_filter_count_mixed() {
|
||||
let announcement_count = 50;
|
||||
let event_count = 30;
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
let filter_count = if is_consolidated {
|
||||
1
|
||||
} else {
|
||||
1 + announcement_count + event_count
|
||||
};
|
||||
|
||||
|
||||
// 1 + 50 + 30 = 81
|
||||
assert_eq!(filter_count, 81);
|
||||
}
|
||||
@@ -261,13 +198,13 @@ fn test_filter_count_consolidated() {
|
||||
let announcement_count = 100; // These would be cleared on consolidation
|
||||
let event_count = 100;
|
||||
let is_consolidated = true;
|
||||
|
||||
|
||||
let filter_count = if is_consolidated {
|
||||
1
|
||||
} else {
|
||||
1 + announcement_count + event_count
|
||||
};
|
||||
|
||||
|
||||
assert_eq!(filter_count, 1);
|
||||
}
|
||||
|
||||
@@ -280,9 +217,9 @@ fn test_filter_count_consolidated() {
|
||||
fn test_should_consolidate_below_threshold() {
|
||||
let filter_count = 100;
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
let should_consolidate = !is_consolidated && filter_count > CONSOLIDATION_THRESHOLD;
|
||||
|
||||
|
||||
assert!(!should_consolidate);
|
||||
}
|
||||
|
||||
@@ -291,9 +228,9 @@ fn test_should_consolidate_below_threshold() {
|
||||
fn test_should_consolidate_at_threshold() {
|
||||
let filter_count = 151; // > 150
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
let should_consolidate = !is_consolidated && filter_count > CONSOLIDATION_THRESHOLD;
|
||||
|
||||
|
||||
assert!(should_consolidate);
|
||||
}
|
||||
|
||||
@@ -302,9 +239,9 @@ fn test_should_consolidate_at_threshold() {
|
||||
fn test_should_consolidate_above_threshold() {
|
||||
let filter_count = 200;
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
let should_consolidate = !is_consolidated && filter_count > CONSOLIDATION_THRESHOLD;
|
||||
|
||||
|
||||
assert!(should_consolidate);
|
||||
}
|
||||
|
||||
@@ -313,9 +250,9 @@ fn test_should_consolidate_above_threshold() {
|
||||
fn test_should_consolidate_already_consolidated() {
|
||||
let filter_count = 200; // Would trigger, but already consolidated
|
||||
let is_consolidated = true;
|
||||
|
||||
|
||||
let should_consolidate = !is_consolidated && filter_count > CONSOLIDATION_THRESHOLD;
|
||||
|
||||
|
||||
assert!(!should_consolidate);
|
||||
}
|
||||
|
||||
@@ -323,11 +260,11 @@ fn test_should_consolidate_already_consolidated() {
|
||||
#[test]
|
||||
fn test_consolidation_threshold_boundary() {
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
// 150 should NOT trigger (> 150, not >= 150)
|
||||
let should_consolidate_at_150 = !is_consolidated && 150 > CONSOLIDATION_THRESHOLD;
|
||||
assert!(!should_consolidate_at_150);
|
||||
|
||||
|
||||
// 151 should trigger
|
||||
let should_consolidate_at_151 = !is_consolidated && 151 > CONSOLIDATION_THRESHOLD;
|
||||
assert!(should_consolidate_at_151);
|
||||
@@ -341,14 +278,14 @@ fn test_consolidation_threshold_boundary() {
|
||||
#[test]
|
||||
fn test_duplicate_announcement_prevention() {
|
||||
let mut subscribed_announcements: HashSet<String> = HashSet::new();
|
||||
|
||||
|
||||
let event_id = "abc123".to_string();
|
||||
|
||||
|
||||
// First add should succeed
|
||||
let is_new = !subscribed_announcements.contains(&event_id);
|
||||
assert!(is_new);
|
||||
subscribed_announcements.insert(event_id.clone());
|
||||
|
||||
|
||||
// Second add should fail (duplicate)
|
||||
let is_new_again = !subscribed_announcements.contains(&event_id);
|
||||
assert!(!is_new_again);
|
||||
@@ -358,14 +295,14 @@ fn test_duplicate_announcement_prevention() {
|
||||
#[test]
|
||||
fn test_duplicate_event_prevention() {
|
||||
let mut subscribed_events: HashSet<String> = HashSet::new();
|
||||
|
||||
|
||||
let event_id = "def456".to_string();
|
||||
|
||||
|
||||
// First add should succeed
|
||||
let is_new = !subscribed_events.contains(&event_id);
|
||||
assert!(is_new);
|
||||
subscribed_events.insert(event_id.clone());
|
||||
|
||||
|
||||
// Second add should fail (duplicate)
|
||||
let is_new_again = !subscribed_events.contains(&event_id);
|
||||
assert!(!is_new_again);
|
||||
@@ -375,14 +312,14 @@ fn test_duplicate_event_prevention() {
|
||||
#[test]
|
||||
fn test_multiple_unique_items_tracked() {
|
||||
let mut subscribed_announcements: HashSet<String> = HashSet::new();
|
||||
|
||||
|
||||
// Add multiple unique announcements
|
||||
for i in 0..10 {
|
||||
let id = format!("announcement_{}", i);
|
||||
assert!(!subscribed_announcements.contains(&id));
|
||||
subscribed_announcements.insert(id);
|
||||
}
|
||||
|
||||
|
||||
assert_eq!(subscribed_announcements.len(), 10);
|
||||
}
|
||||
|
||||
@@ -395,12 +332,12 @@ fn test_multiple_unique_items_tracked() {
|
||||
fn test_announcement_has_d_tag() {
|
||||
let keys = Keys::generate();
|
||||
let event = create_test_announcement(&keys, "my-repo");
|
||||
|
||||
|
||||
let has_d_tag = event.tags.iter().any(|tag| {
|
||||
let tag_vec = tag.clone().to_vec();
|
||||
tag_vec.len() >= 2 && tag_vec[0] == "d"
|
||||
});
|
||||
|
||||
|
||||
assert!(has_d_tag);
|
||||
}
|
||||
|
||||
@@ -409,7 +346,7 @@ fn test_announcement_has_d_tag() {
|
||||
fn test_announcement_correct_kind() {
|
||||
let keys = Keys::generate();
|
||||
let event = create_test_announcement(&keys, "my-repo");
|
||||
|
||||
|
||||
assert_eq!(event.kind.as_u16(), KIND_REPOSITORY_ANNOUNCEMENT);
|
||||
}
|
||||
|
||||
@@ -418,7 +355,7 @@ fn test_announcement_correct_kind() {
|
||||
fn test_maintainer_list_correct_kind() {
|
||||
let keys = Keys::generate();
|
||||
let event = create_test_maintainer_list(&keys, "maintainers");
|
||||
|
||||
|
||||
assert_eq!(event.kind.as_u16(), KIND_MAINTAINER_LIST);
|
||||
}
|
||||
|
||||
@@ -428,12 +365,12 @@ fn test_pr_event_has_a_tag() {
|
||||
let keys = Keys::generate();
|
||||
let coord = "30617:pubkey123:my-repo";
|
||||
let event = create_test_pr_event(&keys, coord);
|
||||
|
||||
|
||||
let has_a_tag = event.tags.iter().any(|tag| {
|
||||
let tag_vec = tag.clone().to_vec();
|
||||
tag_vec.len() >= 2 && tag_vec[0] == "a"
|
||||
});
|
||||
|
||||
|
||||
assert!(has_a_tag);
|
||||
}
|
||||
|
||||
@@ -443,12 +380,12 @@ fn test_issue_event_has_a_tag() {
|
||||
let keys = Keys::generate();
|
||||
let coord = "30617:pubkey123:my-repo";
|
||||
let event = create_test_issue_event(&keys, coord);
|
||||
|
||||
|
||||
let has_a_tag = event.tags.iter().any(|tag| {
|
||||
let tag_vec = tag.clone().to_vec();
|
||||
tag_vec.len() >= 2 && tag_vec[0] == "a"
|
||||
});
|
||||
|
||||
|
||||
assert!(has_a_tag);
|
||||
}
|
||||
|
||||
@@ -458,12 +395,12 @@ fn test_reply_event_has_e_tag() {
|
||||
let keys = Keys::generate();
|
||||
let event_id = "abc123def456";
|
||||
let event = create_test_reply_event(&keys, event_id);
|
||||
|
||||
|
||||
let has_e_tag = event.tags.iter().any(|tag| {
|
||||
let tag_vec = tag.clone().to_vec();
|
||||
tag_vec.len() >= 2 && tag_vec[0] == "e"
|
||||
});
|
||||
|
||||
|
||||
assert!(has_e_tag);
|
||||
}
|
||||
|
||||
@@ -477,50 +414,55 @@ fn test_subscription_lifecycle() {
|
||||
let mut subscribed_announcements: HashSet<String> = HashSet::new();
|
||||
let mut subscribed_events: HashSet<String> = HashSet::new();
|
||||
let mut is_consolidated = false;
|
||||
|
||||
|
||||
// Initial state
|
||||
let initial_count = 1 + subscribed_announcements.len() + subscribed_events.len();
|
||||
assert_eq!(initial_count, 1);
|
||||
|
||||
|
||||
// Add some announcements
|
||||
for i in 0..50 {
|
||||
subscribed_announcements.insert(format!("ann_{}", i));
|
||||
}
|
||||
|
||||
|
||||
let after_announcements = 1 + subscribed_announcements.len() + subscribed_events.len();
|
||||
assert_eq!(after_announcements, 51);
|
||||
|
||||
|
||||
// Add some events
|
||||
for i in 0..50 {
|
||||
subscribed_events.insert(format!("evt_{}", i));
|
||||
}
|
||||
|
||||
|
||||
let after_events = 1 + subscribed_announcements.len() + subscribed_events.len();
|
||||
assert_eq!(after_events, 101);
|
||||
|
||||
|
||||
// Add more to exceed threshold
|
||||
for i in 50..100 {
|
||||
subscribed_announcements.insert(format!("ann_{}", i));
|
||||
}
|
||||
|
||||
|
||||
let before_consolidation = 1 + subscribed_announcements.len() + subscribed_events.len();
|
||||
assert_eq!(before_consolidation, 151);
|
||||
|
||||
|
||||
// Should trigger consolidation
|
||||
let should_consolidate = !is_consolidated && before_consolidation > CONSOLIDATION_THRESHOLD;
|
||||
assert!(should_consolidate);
|
||||
|
||||
|
||||
// Consolidate
|
||||
subscribed_announcements.clear();
|
||||
subscribed_events.clear();
|
||||
is_consolidated = true;
|
||||
|
||||
|
||||
// After consolidation
|
||||
let after_consolidation = if is_consolidated { 1 } else { 1 + subscribed_announcements.len() + subscribed_events.len() };
|
||||
let after_consolidation = if is_consolidated {
|
||||
1
|
||||
} else {
|
||||
1 + subscribed_announcements.len() + subscribed_events.len()
|
||||
};
|
||||
assert_eq!(after_consolidation, 1);
|
||||
|
||||
|
||||
// Should not trigger consolidation again
|
||||
let should_consolidate_again = !is_consolidated && after_consolidation > CONSOLIDATION_THRESHOLD;
|
||||
let should_consolidate_again =
|
||||
!is_consolidated && after_consolidation > CONSOLIDATION_THRESHOLD;
|
||||
assert!(!should_consolidate_again);
|
||||
}
|
||||
|
||||
@@ -528,11 +470,11 @@ fn test_subscription_lifecycle() {
|
||||
#[test]
|
||||
fn test_consolidated_blocks_additions() {
|
||||
let is_consolidated = true;
|
||||
|
||||
|
||||
// When consolidated, add_announcement should return None (simulated)
|
||||
// The logic is: if is_consolidated, return None
|
||||
let should_add = !is_consolidated;
|
||||
|
||||
|
||||
assert!(!should_add);
|
||||
}
|
||||
|
||||
@@ -542,12 +484,12 @@ fn test_non_consolidated_allows_additions() {
|
||||
let is_consolidated = false;
|
||||
let mut subscribed_announcements: HashSet<String> = HashSet::new();
|
||||
let event_id = "new_announcement";
|
||||
|
||||
|
||||
// When not consolidated and event not in set, should add
|
||||
let should_add = !is_consolidated && !subscribed_announcements.contains(event_id);
|
||||
|
||||
|
||||
assert!(should_add);
|
||||
|
||||
|
||||
subscribed_announcements.insert(event_id.to_string());
|
||||
assert!(subscribed_announcements.contains(event_id));
|
||||
}
|
||||
@@ -562,7 +504,7 @@ fn test_announcement_coordinate_format() {
|
||||
let keys = Keys::generate();
|
||||
let identifier = "my-repo";
|
||||
let event = create_test_announcement(&keys, identifier);
|
||||
|
||||
|
||||
// Extract d tag
|
||||
let d_tag = event.tags.iter().find_map(|tag| {
|
||||
let tag_vec = tag.clone().to_vec();
|
||||
@@ -572,13 +514,18 @@ fn test_announcement_coordinate_format() {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assert!(d_tag.is_some());
|
||||
assert_eq!(d_tag.unwrap(), identifier);
|
||||
|
||||
|
||||
// Build coordinate: kind:pubkey:identifier
|
||||
let coord = format!("{}:{}:{}", KIND_REPOSITORY_ANNOUNCEMENT, event.pubkey.to_hex(), identifier);
|
||||
|
||||
let coord = format!(
|
||||
"{}:{}:{}",
|
||||
KIND_REPOSITORY_ANNOUNCEMENT,
|
||||
event.pubkey.to_hex(),
|
||||
identifier
|
||||
);
|
||||
|
||||
// Verify format
|
||||
let parts: Vec<&str> = coord.split(':').collect();
|
||||
assert_eq!(parts.len(), 3);
|
||||
@@ -590,16 +537,21 @@ fn test_announcement_coordinate_format() {
|
||||
#[test]
|
||||
fn test_multiple_announcement_coordinates_unique() {
|
||||
let keys = Keys::generate();
|
||||
|
||||
|
||||
let identifiers = vec!["repo1", "repo2", "repo3"];
|
||||
let mut coords: HashSet<String> = HashSet::new();
|
||||
|
||||
|
||||
for id in identifiers {
|
||||
let event = create_test_announcement(&keys, id);
|
||||
let coord = format!("{}:{}:{}", KIND_REPOSITORY_ANNOUNCEMENT, event.pubkey.to_hex(), id);
|
||||
let coord = format!(
|
||||
"{}:{}:{}",
|
||||
KIND_REPOSITORY_ANNOUNCEMENT,
|
||||
event.pubkey.to_hex(),
|
||||
id
|
||||
);
|
||||
coords.insert(coord);
|
||||
}
|
||||
|
||||
|
||||
assert_eq!(coords.len(), 3);
|
||||
}
|
||||
|
||||
@@ -614,30 +566,34 @@ fn test_workflow_announcement_then_pr() {
|
||||
let mut subscribed_announcements: HashSet<String> = HashSet::new();
|
||||
let mut subscribed_events: HashSet<String> = HashSet::new();
|
||||
let is_consolidated = false;
|
||||
|
||||
|
||||
// Step 1: Receive announcement
|
||||
let announcement = create_test_announcement(&keys, "my-repo");
|
||||
let ann_id = announcement.id.to_hex();
|
||||
|
||||
|
||||
// Should add to tracking (simulating add_announcement)
|
||||
let should_add_ann = !is_consolidated && !subscribed_announcements.contains(&ann_id);
|
||||
assert!(should_add_ann);
|
||||
subscribed_announcements.insert(ann_id.clone());
|
||||
|
||||
|
||||
// Filter count should increase
|
||||
let filter_count = 1 + subscribed_announcements.len() + subscribed_events.len();
|
||||
assert_eq!(filter_count, 2);
|
||||
|
||||
|
||||
// Step 2: Receive PR for that repo
|
||||
let coord = format!("{}:{}:my-repo", KIND_REPOSITORY_ANNOUNCEMENT, keys.public_key().to_hex());
|
||||
let coord = format!(
|
||||
"{}:{}:my-repo",
|
||||
KIND_REPOSITORY_ANNOUNCEMENT,
|
||||
keys.public_key().to_hex()
|
||||
);
|
||||
let pr = create_test_pr_event(&keys, &coord);
|
||||
let pr_id = pr.id.to_hex();
|
||||
|
||||
|
||||
// Should add to tracking (simulating add_event)
|
||||
let should_add_pr = !is_consolidated && !subscribed_events.contains(&pr_id);
|
||||
assert!(should_add_pr);
|
||||
subscribed_events.insert(pr_id.clone());
|
||||
|
||||
|
||||
// Filter count should increase again
|
||||
let filter_count = 1 + subscribed_announcements.len() + subscribed_events.len();
|
||||
assert_eq!(filter_count, 3);
|
||||
@@ -651,16 +607,16 @@ fn test_stress_many_items_triggers_consolidation() {
|
||||
let mut subscribed_events: HashSet<String> = HashSet::new();
|
||||
let mut is_consolidated = false;
|
||||
let mut consolidation_triggered = false;
|
||||
|
||||
|
||||
// Add 100 announcements
|
||||
for i in 0..100 {
|
||||
let event = create_test_announcement(&keys, &format!("repo-{}", i));
|
||||
let event_id = event.id.to_hex();
|
||||
|
||||
|
||||
if !is_consolidated && !subscribed_announcements.contains(&event_id) {
|
||||
subscribed_announcements.insert(event_id);
|
||||
}
|
||||
|
||||
|
||||
// Check consolidation after each add
|
||||
let filter_count = 1 + subscribed_announcements.len() + subscribed_events.len();
|
||||
if !is_consolidated && filter_count > CONSOLIDATION_THRESHOLD {
|
||||
@@ -671,18 +627,18 @@ fn test_stress_many_items_triggers_consolidation() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If we didn't consolidate yet, add events
|
||||
if !consolidation_triggered {
|
||||
for i in 0..100 {
|
||||
let coord = format!("30617:pubkey:repo-{}", i);
|
||||
let event = create_test_pr_event(&keys, &coord);
|
||||
let event_id = event.id.to_hex();
|
||||
|
||||
|
||||
if !is_consolidated && !subscribed_events.contains(&event_id) {
|
||||
subscribed_events.insert(event_id);
|
||||
}
|
||||
|
||||
|
||||
// Check consolidation after each add
|
||||
let filter_count = 1 + subscribed_announcements.len() + subscribed_events.len();
|
||||
if !is_consolidated && filter_count > CONSOLIDATION_THRESHOLD {
|
||||
@@ -694,55 +650,12 @@ fn test_stress_many_items_triggers_consolidation() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Consolidation should have been triggered
|
||||
assert!(consolidation_triggered);
|
||||
assert!(is_consolidated);
|
||||
|
||||
|
||||
// After consolidation, counts should be reset
|
||||
assert_eq!(subscribed_announcements.len(), 0);
|
||||
assert_eq!(subscribed_events.len(), 0);
|
||||
}
|
||||
|
||||
/// Test that all PR/Issue kinds are handled consistently
|
||||
#[test]
|
||||
fn test_all_pr_issue_kinds_handled() {
|
||||
let keys = Keys::generate();
|
||||
let coord = "30617:pubkey:repo";
|
||||
|
||||
// All these kinds should be identified as PR/Issue
|
||||
let pr_kinds = vec![1617, 1618, 1619, 1621, 1622];
|
||||
|
||||
for kind in pr_kinds {
|
||||
assert!(
|
||||
SubscriptionManager::is_pr_issue_kind(kind),
|
||||
"Kind {} should be identified as PR/Issue",
|
||||
kind
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Test that announcement and PR/Issue kinds are mutually exclusive
|
||||
#[test]
|
||||
fn test_kind_categories_mutually_exclusive() {
|
||||
let announcement_kinds = vec![30617, 30618];
|
||||
let pr_issue_kinds = vec![1617, 1618, 1619, 1621, 1622];
|
||||
|
||||
// No announcement kind should be a PR/Issue kind
|
||||
for kind in &announcement_kinds {
|
||||
assert!(
|
||||
!SubscriptionManager::is_pr_issue_kind(*kind),
|
||||
"Announcement kind {} should not be PR/Issue",
|
||||
kind
|
||||
);
|
||||
}
|
||||
|
||||
// No PR/Issue kind should be an announcement kind
|
||||
for kind in &pr_issue_kinds {
|
||||
assert!(
|
||||
!SubscriptionManager::is_announcement_kind(*kind),
|
||||
"PR/Issue kind {} should not be announcement",
|
||||
kind
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user