1package resolver
2
3import (
4	"context"
5	"io"
6	"net"
7	"time"
8
9	"github.com/ooni/probe-cli/v3/internal/engine/atomicx"
10)
11
12type FakeDialer struct {
13	Conn net.Conn
14	Err  error
15}
16
17func (d FakeDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
18	time.Sleep(10 * time.Microsecond)
19	return d.Conn, d.Err
20}
21
22type FakeConn struct {
23	ReadError             error
24	ReadData              []byte
25	SetDeadlineError      error
26	SetReadDeadlineError  error
27	SetWriteDeadlineError error
28	WriteError            error
29}
30
31func (c *FakeConn) Read(b []byte) (int, error) {
32	if len(c.ReadData) > 0 {
33		n := copy(b, c.ReadData)
34		c.ReadData = c.ReadData[n:]
35		return n, nil
36	}
37	if c.ReadError != nil {
38		return 0, c.ReadError
39	}
40	return 0, io.EOF
41}
42
43func (c *FakeConn) Write(b []byte) (n int, err error) {
44	if c.WriteError != nil {
45		return 0, c.WriteError
46	}
47	n = len(b)
48	return
49}
50
51func (*FakeConn) Close() (err error) {
52	return
53}
54
55func (*FakeConn) LocalAddr() net.Addr {
56	return &net.TCPAddr{}
57}
58
59func (*FakeConn) RemoteAddr() net.Addr {
60	return &net.TCPAddr{}
61}
62
63func (c *FakeConn) SetDeadline(t time.Time) (err error) {
64	return c.SetDeadlineError
65}
66
67func (c *FakeConn) SetReadDeadline(t time.Time) (err error) {
68	return c.SetReadDeadlineError
69}
70
71func (c *FakeConn) SetWriteDeadline(t time.Time) (err error) {
72	return c.SetWriteDeadlineError
73}
74
75type FakeTransport struct {
76	Data []byte
77	Err  error
78}
79
80func (ft FakeTransport) RoundTrip(ctx context.Context, query []byte) ([]byte, error) {
81	return ft.Data, ft.Err
82}
83
84func (ft FakeTransport) RequiresPadding() bool {
85	return false
86}
87
88func (ft FakeTransport) Address() string {
89	return ""
90}
91
92func (ft FakeTransport) Network() string {
93	return "fake"
94}
95
96type FakeEncoder struct {
97	Data []byte
98	Err  error
99}
100
101func (fe FakeEncoder) Encode(domain string, qtype uint16, padding bool) ([]byte, error) {
102	return fe.Data, fe.Err
103}
104
105type FakeResolver struct {
106	NumFailures *atomicx.Int64
107	Err         error
108	Result      []string
109}
110
111func NewFakeResolverThatFails() FakeResolver {
112	return FakeResolver{NumFailures: atomicx.NewInt64(), Err: errNotFound}
113}
114
115func NewFakeResolverWithResult(r []string) FakeResolver {
116	return FakeResolver{NumFailures: atomicx.NewInt64(), Result: r}
117}
118
119var errNotFound = &net.DNSError{
120	Err: "no such host",
121}
122
123func (c FakeResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) {
124	time.Sleep(10 * time.Microsecond)
125	if c.Err != nil {
126		if c.NumFailures != nil {
127			c.NumFailures.Add(1)
128		}
129		return nil, c.Err
130	}
131	return c.Result, nil
132}
133
134func (c FakeResolver) Network() string {
135	return "fake"
136}
137
138func (c FakeResolver) Address() string {
139	return ""
140}
141
142var _ Resolver = FakeResolver{}
143