-
-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
vec impl for DnsResolver #345
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty much spot on. Hope my comments serve as the missing guidelines you were needing. However, you do seem to have understood the intent of the issue as far as I can see. So great start!
Thanks @GlenDC , I make some change in recent commits. I would like to add some tests, can you give me some help? |
Sure. What tests would you like to add? I can chip in if they are useful and how you might go on doing so. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current version looks good except the minor comments I made.
With these changes applied I'm good with merging it, but curious to hear what kind of tests you want to still add.
Some demos for using DnsChainDomainResolve, just like in #332 mentioned |
Sure. For general advise you can check existing tests in rama. E.g. how to do multiple cases of same tests (test cases), or fact that you'll need to use Regarding these tests. Wouldn't overdo it. Again use your own judgement, but following cases come to my mind:
2-6 for both vec/array I guess. You can use the existing https://ramaproxy.org/docs/rama/dns/struct.DenyAllDns.html for your err case, and https://ramaproxy.org/docs/rama/dns/struct.InMemoryDns.html for the ok case. I wouldn't check on the actual inner errors, just the high level Ok vs Err is good enough :) And if ok of course do check if you get the expected IP. Make sure to test both IPv4 and IPv6. Feel free to cut on testing where you see fit, logic is simple enough that I don't think we really need that much testing here, but given you seem motivated to do so, do feel free to go for it :) |
Co-authored-by: Glen De Cauwsemaecker <[email protected]>
Hi @GlenDC ,I still have no idea for testing, could you give me some example code , thanks |
rama-dns/src/lib.rs
Outdated
} | ||
} | ||
|
||
impl<E: std::fmt::Debug + Send + std::error::Error> std::error::Error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you do E: std::error::Error + 'static
, can you not just do
self.errors.last()
on line 101? If not what error do you get?
rama-dns/src/lib.rs
Outdated
@@ -79,6 +79,89 @@ impl<R: DnsResolver<Error: Into<BoxError>>> DnsResolver for Option<R> { | |||
} | |||
} | |||
|
|||
#[derive(Debug)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be a good idea to move all your new code here to a new file: rama-dns/src/chain.rs
. Can be a private fail of which you pub use (re-export) types here.
rama-dns/src/lib.rs
Outdated
{ | ||
type Error = DnsChainDomainResolveErr<E>; | ||
|
||
async fn ipv4_lookup(&self, domain: Domain) -> Result<Vec<Ipv4Addr>, Self::Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can refactor these 2 definitions as:
macro_rules! dns_resolver_chain_impl {
() => {
async fn ipv4_lookup(&self, domain: Domain) -> Result<Vec<Ipv4Addr>, Self::Error> {
let mut errors = Vec::new();
for resolver in self {
match resolver.ipv4_lookup(domain.clone()).await {
Ok(ipv4s) => return Ok(ipv4s),
Err(err) => errors.push(err),
}
}
Err(DnsChainDomainResolveErr { errors })
}
async fn ipv6_lookup(&self, domain: Domain) -> Result<Vec<Ipv6Addr>, Self::Error> {
let mut errors = Vec::new();
for resolver in self {
match resolver.ipv6_lookup(domain.clone()).await {
Ok(ipv6s) => return Ok(ipv6s),
Err(err) => errors.push(err),
}
}
Err(DnsChainDomainResolveErr { errors })
}
}
}
so that you can do:
impl<R, E> DnsResolver for Vec<R>
where
R: DnsResolver<Error = E> + Send,
E: Send + 'static,
{
type Error = DnsChainDomainResolveErr<E>;
dns_resolver_chain_impl!()
}
impl<R, E, const N: usize> DnsResolver for [R; N]
where
R: DnsResolver<Error = E> + Send,
E: Send + 'static,
{
type Error = DnsChainDomainResolveErr<E>;
dns_resolver_chain_impl!()
}
Might give you an error around scoping or w/e, but nothing that can be resolved by in worst case
passing some stuff. With some cleverness you can probably even make it shorter, but this is already sufficient.
rama-dns/src/lib.rs
Outdated
Err(DnsChainDomainResolveErr { errors }) | ||
} | ||
} | ||
|
||
macro_rules! impl_dns_resolver_either_either { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while you're at it, feel free to move this macro def and its usage to a separate file called rama-dns/src/variant.rs
, keeps the lib.rs pretty clean
Sure, in So to pick up some of the given example cases, you can start with: #[cfg(test)]
mod tests {
use std::net::{Ipv4Addr, Ipv6Addr};
use rama_core::combinators::Either;
use super::*;
#[tokio::test]
async fn test_empty_chain_vec() {
let v = Vec::<DnsOverwrite>::new();
assert!(v
.ipv4_lookup(Domain::from_static("plabayo.tech"))
.await
.is_err());
assert!(v
.ipv6_lookup(Domain::from_static("plabayo.tech"))
.await
.is_err());
}
#[tokio::test]
async fn test_empty_chain_array() {
let a: [DnsOverwrite; 0] = [];
assert!(a
.ipv4_lookup(Domain::from_static("plabayo.tech"))
.await
.is_err());
assert!(a
.ipv6_lookup(Domain::from_static("plabayo.tech"))
.await
.is_err());
}
#[tokio::test]
async fn test_chain_ok_err_ipv4() {
let v = vec![
Either::A(serde_html_form::from_str("example.com=127.0.0.1").unwrap()),
Either::B(DenyAllDns::new()),
];
assert!(
v.ipv4_lookup(Domain::from_static("example.com"))
.await
.unwrap()
.into_iter()
.next()
.unwrap(),
Ipv4Addr::new(127, 0, 0, 1)
);
assert!(v
.ipv6_lookup(Domain::from_static("example.com"))
.await
.is_err());
}
#[tokio::test]
async fn test_chain_err_err_ok_ipv6() {
// ... TODO
}
// TODO ...
} Haven't tested the code or ran it so you might need to solve some issues in the code, but hopefully it gets the idea across. I certainly wouldn't test all possible combinations. Just try to combine a couple so that you more or less have tested some couple things. I'm not interested in full test coverage, so try to be minimal and smart about it, as this is also all code to maintain in the end. And thanks to how we write the code, e.g. using a macro for a single implementation, it is already more guaranteed that we have working code for both sequence implementations. |
Hi @GlenDC I have a try for #332 But I am not sure my implement is totally that issue asked. And also, thanks for your helping