pact_plugin_driver/
core_capabilities.rs1use std::collections::HashMap;
15use std::sync::{Arc, Mutex};
16
17use async_trait::async_trait;
18use lazy_static::lazy_static;
19
20use crate::proto::{CompareContentsRequest, CompareContentsResponse, GenerateContentRequest, GenerateContentResponse};
21
22#[async_trait]
25pub trait CoreContentMatcher: Send + Sync {
26 async fn compare_contents(&self, request: CompareContentsRequest) -> anyhow::Result<CompareContentsResponse>;
28}
29
30#[async_trait]
33pub trait CoreContentGenerator: Send + Sync {
34 async fn generate_content(&self, request: GenerateContentRequest) -> anyhow::Result<GenerateContentResponse>;
36}
37
38lazy_static! {
39 static ref CORE_CONTENT_MATCHERS: Mutex<HashMap<String, Arc<dyn CoreContentMatcher>>> = Mutex::new(HashMap::new());
40 static ref CORE_CONTENT_GENERATORS: Mutex<HashMap<String, Arc<dyn CoreContentGenerator>>> = Mutex::new(HashMap::new());
41}
42
43pub fn register_core_content_matcher(key: &str, handler: Arc<dyn CoreContentMatcher>) {
47 CORE_CONTENT_MATCHERS.lock()
48 .expect("CORE_CONTENT_MATCHERS mutex poisoned")
49 .insert(key.to_string(), handler);
50}
51
52pub fn register_core_content_generator(key: &str, handler: Arc<dyn CoreContentGenerator>) {
56 CORE_CONTENT_GENERATORS.lock()
57 .expect("CORE_CONTENT_GENERATORS mutex poisoned")
58 .insert(key.to_string(), handler);
59}
60
61pub fn lookup_core_content_matcher(key: &str) -> Option<Arc<dyn CoreContentMatcher>> {
63 CORE_CONTENT_MATCHERS.lock()
64 .expect("CORE_CONTENT_MATCHERS mutex poisoned")
65 .get(key).cloned()
66}
67
68pub fn lookup_core_content_generator(key: &str) -> Option<Arc<dyn CoreContentGenerator>> {
70 CORE_CONTENT_GENERATORS.lock()
71 .expect("CORE_CONTENT_GENERATORS mutex poisoned")
72 .get(key).cloned()
73}
74
75pub fn deregister_core_content_matcher(key: &str) {
77 CORE_CONTENT_MATCHERS.lock()
78 .expect("CORE_CONTENT_MATCHERS mutex poisoned")
79 .remove(key);
80}
81
82pub fn deregister_core_content_generator(key: &str) {
84 CORE_CONTENT_GENERATORS.lock()
85 .expect("CORE_CONTENT_GENERATORS mutex poisoned")
86 .remove(key);
87}
88
89#[cfg(test)]
90mod tests {
91 use expectest::prelude::*;
92
93 use crate::proto::{CompareContentsRequest, CompareContentsResponse, GenerateContentRequest, GenerateContentResponse};
94
95 use super::*;
96
97 #[derive(Debug)]
98 struct TestMatcher;
99
100 #[async_trait]
101 impl CoreContentMatcher for TestMatcher {
102 async fn compare_contents(&self, _request: CompareContentsRequest) -> anyhow::Result<CompareContentsResponse> {
103 Ok(CompareContentsResponse::default())
104 }
105 }
106
107 #[derive(Debug)]
108 struct TestGenerator;
109
110 #[async_trait]
111 impl CoreContentGenerator for TestGenerator {
112 async fn generate_content(&self, _request: GenerateContentRequest) -> anyhow::Result<GenerateContentResponse> {
113 Ok(GenerateContentResponse::default())
114 }
115 }
116
117 #[test_log::test]
118 fn returns_none_for_an_unregistered_key() {
119 expect!(lookup_core_content_matcher("unregistered-matcher-key").is_none()).to(be_true());
120 expect!(lookup_core_content_generator("unregistered-generator-key").is_none()).to(be_true());
121 }
122
123 #[test_log::test(tokio::test)]
124 async fn registers_and_looks_up_a_content_matcher() {
125 register_core_content_matcher("test-matcher-key", Arc::new(TestMatcher));
126
127 let handler = lookup_core_content_matcher("test-matcher-key");
128 deregister_core_content_matcher("test-matcher-key");
129
130 expect!(handler.is_some()).to(be_true());
131 let response = handler.unwrap().compare_contents(CompareContentsRequest::default()).await;
132 expect!(response.is_ok()).to(be_true());
133 }
134
135 #[test_log::test(tokio::test)]
136 async fn registers_and_looks_up_a_content_generator() {
137 register_core_content_generator("test-generator-key", Arc::new(TestGenerator));
138
139 let handler = lookup_core_content_generator("test-generator-key");
140 deregister_core_content_generator("test-generator-key");
141
142 expect!(handler.is_some()).to(be_true());
143 let response = handler.unwrap().generate_content(GenerateContentRequest::default()).await;
144 expect!(response.is_ok()).to(be_true());
145 }
146
147 #[test_log::test]
148 fn deregister_is_a_no_op_for_an_unknown_key() {
149 deregister_core_content_matcher("never-registered");
150 deregister_core_content_generator("never-registered");
151 }
152}