github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/net_test.go (about) 1 /* 2 * Copyright (c) 2016, Psiphon Inc. 3 * All rights reserved. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package common 21 22 import ( 23 "net" 24 "sync/atomic" 25 "testing" 26 "testing/iotest" 27 "time" 28 29 "github.com/miekg/dns" 30 ) 31 32 func TestLRUConns(t *testing.T) { 33 lruConns := NewLRUConns() 34 35 dummy1 := &dummyConn{} 36 entry1 := lruConns.Add(dummy1) 37 38 dummy2 := &dummyConn{} 39 entry2 := lruConns.Add(dummy2) 40 41 dummy3 := &dummyConn{} 42 entry3 := lruConns.Add(dummy3) 43 44 entry3.Touch() 45 entry2.Touch() 46 entry1.Touch() 47 48 if dummy1.IsClosed() || dummy2.IsClosed() || dummy3.IsClosed() { 49 t.Fatalf("unexpected IsClosed state") 50 } 51 52 lruConns.CloseOldest() 53 54 if dummy1.IsClosed() || dummy2.IsClosed() || !dummy3.IsClosed() { 55 t.Fatalf("unexpected IsClosed state") 56 } 57 58 lruConns.CloseOldest() 59 60 if dummy1.IsClosed() || !dummy2.IsClosed() || !dummy3.IsClosed() { 61 t.Fatalf("unexpected IsClosed state") 62 } 63 64 entry1.Remove() 65 66 lruConns.CloseOldest() 67 68 if dummy1.IsClosed() || !dummy2.IsClosed() || !dummy3.IsClosed() { 69 t.Fatalf("unexpected IsClosed state") 70 } 71 } 72 73 func TestIsBogon(t *testing.T) { 74 if IsBogon(net.ParseIP("8.8.8.8")) { 75 t.Errorf("unexpected bogon") 76 } 77 if !IsBogon(net.ParseIP("127.0.0.1")) { 78 t.Errorf("unexpected non-bogon") 79 } 80 if !IsBogon(net.ParseIP("192.168.0.1")) { 81 t.Errorf("unexpected non-bogon") 82 } 83 if !IsBogon(net.ParseIP("::1")) { 84 t.Errorf("unexpected non-bogon") 85 } 86 if !IsBogon(net.ParseIP("fc00::")) { 87 t.Errorf("unexpected non-bogon") 88 } 89 } 90 91 func BenchmarkIsBogon(b *testing.B) { 92 for i := 0; i < b.N; i++ { 93 IsBogon(net.ParseIP("8.8.8.8")) 94 } 95 } 96 97 func makeDNSQuery(domain string) ([]byte, error) { 98 query := new(dns.Msg) 99 query.SetQuestion(domain, dns.TypeA) 100 query.RecursionDesired = true 101 msg, err := query.Pack() 102 if err != nil { 103 return nil, err 104 } 105 return msg, nil 106 } 107 108 func TestParseDNSQuestion(t *testing.T) { 109 110 domain := dns.Fqdn("www.example.com") 111 msg, err := makeDNSQuery(domain) 112 if err != nil { 113 t.Fatalf("makeDNSQuery failed: %s", err) 114 } 115 116 checkDomain, err := ParseDNSQuestion(msg) 117 if err != nil { 118 t.Fatalf("ParseDNSQuestion failed: %s", err) 119 } 120 121 if checkDomain != domain { 122 t.Fatalf("unexpected domain") 123 } 124 } 125 126 func BenchmarkParseDNSQuestion(b *testing.B) { 127 128 domain := dns.Fqdn("www.example.com") 129 msg, err := makeDNSQuery(domain) 130 if err != nil { 131 b.Fatalf("makeDNSQuery failed: %s", err) 132 } 133 134 for i := 0; i < b.N; i++ { 135 ParseDNSQuestion(msg) 136 } 137 } 138 139 type dummyConn struct { 140 t *testing.T 141 timeout *time.Timer 142 readBytesPerSecond int64 143 writeBytesPerSecond int64 144 isClosed int32 145 } 146 147 func (c *dummyConn) Read(b []byte) (n int, err error) { 148 if c.readBytesPerSecond > 0 { 149 sleep := time.Duration(float64(int64(len(b))*int64(time.Second)) / float64(c.readBytesPerSecond)) 150 time.Sleep(sleep) 151 } 152 if c.timeout != nil { 153 select { 154 case <-c.timeout.C: 155 return 0, iotest.ErrTimeout 156 default: 157 } 158 } 159 return len(b), nil 160 } 161 162 func (c *dummyConn) Write(b []byte) (n int, err error) { 163 if c.writeBytesPerSecond > 0 { 164 sleep := time.Duration(float64(int64(len(b))*int64(time.Second)) / float64(c.writeBytesPerSecond)) 165 time.Sleep(sleep) 166 } 167 if c.timeout != nil { 168 select { 169 case <-c.timeout.C: 170 return 0, iotest.ErrTimeout 171 default: 172 } 173 } 174 return len(b), nil 175 } 176 177 func (c *dummyConn) Close() error { 178 atomic.StoreInt32(&c.isClosed, 1) 179 return nil 180 } 181 182 func (c *dummyConn) IsClosed() bool { 183 return atomic.LoadInt32(&c.isClosed) == 1 184 } 185 186 func (c *dummyConn) LocalAddr() net.Addr { 187 c.t.Fatal("LocalAddr not implemented") 188 return nil 189 } 190 191 func (c *dummyConn) RemoteAddr() net.Addr { 192 c.t.Fatal("RemoteAddr not implemented") 193 return nil 194 } 195 196 func (c *dummyConn) SetDeadline(t time.Time) error { 197 duration := time.Until(t) 198 if c.timeout == nil { 199 c.timeout = time.NewTimer(duration) 200 } else { 201 if !c.timeout.Stop() { 202 <-c.timeout.C 203 } 204 c.timeout.Reset(duration) 205 } 206 return nil 207 } 208 209 func (c *dummyConn) SetReadDeadline(t time.Time) error { 210 c.t.Fatal("SetReadDeadline not implemented") 211 return nil 212 } 213 214 func (c *dummyConn) SetWriteDeadline(t time.Time) error { 215 c.t.Fatal("SetWriteDeadline not implemented") 216 return nil 217 } 218 219 func (c *dummyConn) SetRateLimits(readBytesPerSecond, writeBytesPerSecond int64) { 220 c.readBytesPerSecond = readBytesPerSecond 221 c.writeBytesPerSecond = writeBytesPerSecond 222 }