github.com/la5nta/wl2k-go@v0.11.8/fbb/wl2k_test.go (about) 1 // Copyright 2015 Martin Hebnes Pedersen (LA5NTA). All rights reserved. 2 // Use of this source code is governed by the MIT-license that can be 3 // found in the LICENSE file. 4 5 package fbb 6 7 import ( 8 "bufio" 9 "fmt" 10 "net" 11 "os" 12 "strings" 13 "testing" 14 ) 15 16 //[WL2K-2.8.4.8-B2FWIHJM$] 17 //Brentwood CMS > 18 // ;FW: LA5NTA 19 // [RMS Express-1.2.35.0-B2FHM$] 20 // ; WL2K DE LA5NTA (JO39EQ) 21 // FF 22 //FQ 23 24 func TestSessionP2P(t *testing.T) { 25 client, master := net.Pipe() 26 27 clientErr := make(chan error) 28 go func() { 29 s := NewSession("LA5NTA", "N0CALL", "JO39EQ", nil) 30 _, err := s.Exchange(client) 31 clientErr <- err 32 }() 33 34 masterErr := make(chan error) 35 go func() { 36 s := NewSession("N0CALL", "LA5NTA", "JO39EQ", nil) 37 s.IsMaster(true) 38 _, err := s.Exchange(master) 39 masterErr <- err 40 }() 41 42 if err := <-masterErr; err != nil { 43 t.Errorf("Master returned with error: %s", err) 44 } 45 if err := <-clientErr; err != nil { 46 t.Errorf("Client returned with error: %s", err) 47 } 48 } 49 50 func TestFWAuxOnlyExperiment(t *testing.T) { 51 os.Setenv("FW_AUX_ONLY_EXPERIMENT", "1") 52 defer os.Setenv("FW_AUX_ONLY_EXPERIMENT", "0") 53 54 client, master := net.Pipe() 55 56 clientErr := make(chan error) 57 go func() { 58 s := NewSession("LA5NTA", "N0CALL", "JO39EQ", nil) 59 s.AddAuxiliaryAddress(AddressFromString("EMCOMM-1@winlink.org")) 60 _, err := s.Exchange(client) 61 clientErr <- err 62 }() 63 64 masterErr := make(chan error) 65 go func() { 66 s := NewSession("N0CALL", "LA5NTA", "JO39EQ", nil) 67 s.IsMaster(true) 68 _, err := s.Exchange(master) 69 switch fw := s.RemoteForwarders(); { 70 case len(fw) != 1: 71 t.Errorf("unexpected FW count: %d", len(fw)) 72 case fw[0].String() != "EMCOMM-1": 73 t.Errorf("unexpected FW address: %q", fw[0]) 74 } 75 masterErr <- err 76 }() 77 78 if err := <-masterErr; err != nil { 79 t.Errorf("Master returned with error: %s", err) 80 } 81 if err := <-clientErr; err != nil { 82 t.Errorf("Client returned with error: %s", err) 83 } 84 } 85 86 func TestSessionCMS(t *testing.T) { 87 client, srv := net.Pipe() 88 89 cerrs := make(chan error) 90 go func() { 91 s := NewSession("LA5NTA", "LA1B-10", "JO39EQ", nil) 92 _, err := s.Exchange(client) 93 cerrs <- err 94 }() 95 96 fmt.Fprint(srv, "[WL2K-2.8.4.8-B2FWIHJM$]\r") 97 fmt.Fprint(srv, "Foobar should be ignored\r") 98 fmt.Fprint(srv, "Test CMS >\r") 99 100 expectLines := []string{ 101 ";FW: LA5NTA\r", 102 "[wl2kgo-0.1a-B2FHM$]\r", 103 "; LA1B-10 DE LA5NTA (JO39EQ)\r", 104 "FF\r", 105 } 106 107 // Read until FF 108 rd := bufio.NewReader(srv) 109 for i, expected := range expectLines { 110 line, _ := rd.ReadString('\r') 111 if line != expected { 112 line, expected = strings.TrimSpace(line), strings.TrimSpace(expected) 113 t.Fatalf("Unexpected line [%d]: Got '%s', expected '%s'.", i, line, expected) 114 } 115 } 116 117 fmt.Fprint(srv, "FQ\r") 118 srv.Close() 119 120 if err := <-cerrs; err != nil { 121 t.Errorf("Session exchange returned error: %s", err) 122 } 123 } 124 125 func TestSessionCMDWithMessage(t *testing.T) { 126 client, srv := net.Pipe() 127 128 cerrs := make(chan error) 129 go func() { 130 s := NewSession("LA5NTA", "LA1B-10", "JO39EQ", nil) 131 _, err := s.Exchange(client) 132 cerrs <- err 133 }() 134 135 fmt.Fprint(srv, "[WL2K-2.8.4.8-B2FWIHJM$]\r") 136 fmt.Fprint(srv, "Test CMS >\r") 137 138 expectLines := []string{ 139 ";FW: LA5NTA\r", 140 "[wl2kgo-0.1a-B2FHM$]\r", 141 "; LA1B-10 DE LA5NTA (JO39EQ)\r", 142 "FF\r", 143 } 144 145 // Read until FF 146 rd := bufio.NewReader(srv) 147 for i, expected := range expectLines { 148 line, _ := rd.ReadString('\r') 149 if line != expected { 150 line, expected = strings.TrimSpace(line), strings.TrimSpace(expected) 151 t.Fatalf("Unexpected line [%d]: Got '%s', expected '%s'.", i, line, expected) 152 } 153 } 154 155 // Send one proposal 156 fmt.Fprintf(srv, "FC EM TJKYEIMMHSRB 527 123 0\r") 157 fmt.Fprintf(srv, "F> 3b\r") // No more proposals + checksum 158 159 propAnswer, _ := rd.ReadString('\r') 160 if propAnswer != "FS =\r" { 161 t.Errorf("Expected 'FS =', got '%s'", propAnswer) 162 } 163 fmt.Fprintf(srv, "FF\r") // No more messages 164 165 if line, _ := rd.ReadString('\r'); line != "FQ\r" { 166 t.Errorf("Expected 'FQ', got '%s'", line) 167 } 168 169 if err := <-cerrs; err != nil { 170 t.Errorf("Session exchange returned error: %s", err) 171 } 172 } 173 174 func TestSessionCMSv4(t *testing.T) { 175 client, srv := net.Pipe() 176 177 cerrs := make(chan error) 178 go func() { 179 s := NewSession("LA5NTA", "LA1B-10", "JO39EQ", nil) 180 _, err := s.Exchange(client) 181 cerrs <- err 182 }() 183 184 fmt.Fprint(srv, "[WL2K-4.0-B2FWIHJM$]\r") 185 fmt.Fprint(srv, "Test CMS >\r") 186 187 expectLines := []string{ 188 ";FW: LA5NTA\r", 189 "[wl2kgo-0.1a-B2FHM$]\r", 190 "; LA1B-10 DE LA5NTA (JO39EQ)\r", 191 "FF\r", 192 } 193 194 // Read until FF 195 rd := bufio.NewReader(srv) 196 for i, expected := range expectLines { 197 line, _ := rd.ReadString('\r') 198 if line != expected { 199 line, expected = strings.TrimSpace(line), strings.TrimSpace(expected) 200 t.Fatalf("Unexpected line [%d]: Got '%s', expected '%s'.", i, line, expected) 201 } 202 } 203 204 // Send some CMS v4 ; lines 205 fmt.Fprintf(srv, ";PM: LA5NTA TJKYEIMMHSRB 123 martin.h.pedersen@gmail.com\r") 206 fmt.Fprintf(srv, ";WARNING: Foo bar baz\r") 207 208 // Send one proposal 209 fmt.Fprintf(srv, "FC EM TJKYEIMMHSRB 527 123 0\r") 210 fmt.Fprintf(srv, "F> 3b\r") // No more proposals + checksum 211 212 propAnswer, _ := rd.ReadString('\r') 213 if propAnswer != "FS =\r" { 214 t.Errorf("Expected 'FS =', got '%s'", propAnswer) 215 } 216 217 fmt.Fprintf(srv, ";WARNING: Foo bar baz\r") // One more CMS v4 ; line 218 fmt.Fprintf(srv, "FF\r") // No more messages 219 220 if line, _ := rd.ReadString('\r'); line != "FQ\r" { 221 t.Errorf("Expected 'FQ', got '%s'", line) 222 } 223 224 if err := <-cerrs; err != nil { 225 t.Errorf("Session exchange returned error: %s", err) 226 } 227 } 228 229 func TestSortProposals(t *testing.T) { 230 props := []*Proposal{ 231 mustProposalWithSubject("Just a test"), 232 mustProposalWithSubject("Re://WL2K O/Very important"), 233 mustProposalWithSubject("//WL2K R/Read this sometime, or don't"), 234 mustProposalWithSubject("//WL2K P/ Pretty important"), 235 mustProposalWithSubject("//WL2K Z/The world is on fire!"), 236 } 237 238 sortProposals(props) 239 240 // Flash 241 if props[0].Title() != "//WL2K Z/The world is on fire!" { 242 t.Error("Flash precedence was not in order") 243 } 244 // Immediate 245 if props[1].Title() != "Re://WL2K O/Very important" { 246 t.Error("Immediate precedence was not in order") 247 } 248 // Priority 249 if props[2].Title() != "//WL2K P/ Pretty important" { 250 t.Error("Priority precedence was not in order") 251 } 252 // Everything else is Routine, so goes by increasing size 253 if props[3].Title() != "Just a test" { 254 t.Error("Routine precedence was not in order") 255 } 256 if props[4].Title() != "//WL2K R/Read this sometime, or don't" { 257 t.Error("Routine precedence was not in order") 258 } 259 } 260 261 func mustProposalWithSubject(subject string) *Proposal { 262 p, err := proposalWithSubject(subject) 263 if err != nil { 264 panic(err) 265 } 266 return p 267 } 268 269 func proposalWithSubject(subject string) (*Proposal, error) { 270 msg := NewMessage(Private, "N0CALL") 271 msg.AddTo("N0CALL") 272 msg.SetSubject(subject) 273 _ = msg.SetBody("Satisfies validation") 274 return msg.Proposal(BasicProposal) 275 }