Added files.
This commit is contained in:
277
imapclient/client_test.go
Normal file
277
imapclient/client_test.go
Normal file
@@ -0,0 +1,277 @@
|
||||
package imapclient_test
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/emersion/go-imap/v2"
|
||||
"github.com/emersion/go-imap/v2/imapclient"
|
||||
"github.com/emersion/go-imap/v2/imapserver"
|
||||
"github.com/emersion/go-imap/v2/imapserver/imapmemserver"
|
||||
)
|
||||
|
||||
const (
|
||||
testUsername = "test-user"
|
||||
testPassword = "test-password"
|
||||
)
|
||||
|
||||
const simpleRawMessage = `MIME-Version: 1.0
|
||||
Message-Id: <191101702316132@example.com>
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
This is my letter!`
|
||||
|
||||
var rsaCertPEM = `-----BEGIN CERTIFICATE-----
|
||||
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
|
||||
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
|
||||
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
|
||||
bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
|
||||
aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
|
||||
YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
|
||||
POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
|
||||
h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
|
||||
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
|
||||
bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
|
||||
5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
|
||||
cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
|
||||
+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
|
||||
grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
|
||||
5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
|
||||
WkBKOclmOV2xlTVuPw==
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
|
||||
var rsaKeyPEM = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
|
||||
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
|
||||
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
|
||||
URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX
|
||||
AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy
|
||||
VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK
|
||||
x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk
|
||||
lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL
|
||||
dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89
|
||||
EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq
|
||||
XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki
|
||||
6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O
|
||||
3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s
|
||||
uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ
|
||||
Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ
|
||||
w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo
|
||||
+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP
|
||||
OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA
|
||||
brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv
|
||||
m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y
|
||||
LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN
|
||||
/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN
|
||||
s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ
|
||||
Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0
|
||||
xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/
|
||||
ZboOWVe3icTy64BT3OQhmg==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
|
||||
func newMemClientServerPair(t *testing.T) (net.Conn, io.Closer) {
|
||||
memServer := imapmemserver.New()
|
||||
|
||||
user := imapmemserver.NewUser(testUsername, testPassword)
|
||||
user.Create("INBOX", nil)
|
||||
|
||||
memServer.AddUser(user)
|
||||
|
||||
cert, err := tls.X509KeyPair([]byte(rsaCertPEM), []byte(rsaKeyPEM))
|
||||
if err != nil {
|
||||
t.Fatalf("tls.X509KeyPair() = %v", err)
|
||||
}
|
||||
|
||||
server := imapserver.New(&imapserver.Options{
|
||||
NewSession: func(conn *imapserver.Conn) (imapserver.Session, *imapserver.GreetingData, error) {
|
||||
return memServer.NewSession(), nil, nil
|
||||
},
|
||||
TLSConfig: &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
},
|
||||
InsecureAuth: true,
|
||||
Caps: imap.CapSet{
|
||||
imap.CapIMAP4rev1: {},
|
||||
imap.CapIMAP4rev2: {},
|
||||
},
|
||||
})
|
||||
|
||||
ln, err := net.Listen("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatalf("net.Listen() = %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := server.Serve(ln); err != nil {
|
||||
t.Errorf("Serve() = %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
conn, err := net.Dial("tcp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatalf("net.Dial() = %v", err)
|
||||
}
|
||||
|
||||
return conn, server
|
||||
}
|
||||
|
||||
func newClientServerPair(t *testing.T, initialState imap.ConnState) (*imapclient.Client, io.Closer) {
|
||||
var useDovecot bool
|
||||
switch os.Getenv("GOIMAP_TEST_DOVECOT") {
|
||||
case "0", "":
|
||||
// ok
|
||||
case "1":
|
||||
useDovecot = true
|
||||
default:
|
||||
t.Fatalf("invalid GOIMAP_TEST_DOVECOT env var")
|
||||
}
|
||||
|
||||
var (
|
||||
conn net.Conn
|
||||
server io.Closer
|
||||
)
|
||||
if useDovecot {
|
||||
if initialState < imap.ConnStateAuthenticated {
|
||||
t.Skip("Dovecot connections are pre-authenticated")
|
||||
}
|
||||
conn, server = newDovecotClientServerPair(t)
|
||||
} else {
|
||||
conn, server = newMemClientServerPair(t)
|
||||
}
|
||||
|
||||
var debugWriter swapWriter
|
||||
debugWriter.Swap(io.Discard)
|
||||
|
||||
var options imapclient.Options
|
||||
if testing.Verbose() {
|
||||
options.DebugWriter = &debugWriter
|
||||
}
|
||||
client := imapclient.New(conn, &options)
|
||||
|
||||
if initialState >= imap.ConnStateAuthenticated {
|
||||
// Dovecot connections are pre-authenticated
|
||||
if !useDovecot {
|
||||
if err := client.Login(testUsername, testPassword).Wait(); err != nil {
|
||||
t.Fatalf("Login().Wait() = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
appendCmd := client.Append("INBOX", int64(len(simpleRawMessage)), nil)
|
||||
appendCmd.Write([]byte(simpleRawMessage))
|
||||
appendCmd.Close()
|
||||
if _, err := appendCmd.Wait(); err != nil {
|
||||
t.Fatalf("AppendCommand.Wait() = %v", err)
|
||||
}
|
||||
}
|
||||
if initialState >= imap.ConnStateSelected {
|
||||
if _, err := client.Select("INBOX", nil).Wait(); err != nil {
|
||||
t.Fatalf("Select().Wait() = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Turn on debug logs after we're done initializing the test
|
||||
debugWriter.Swap(os.Stderr)
|
||||
|
||||
return client, server
|
||||
}
|
||||
|
||||
// swapWriter is an io.Writer which can be swapped at runtime.
|
||||
type swapWriter struct {
|
||||
w io.Writer
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (sw *swapWriter) Write(b []byte) (int, error) {
|
||||
sw.mutex.Lock()
|
||||
w := sw.w
|
||||
sw.mutex.Unlock()
|
||||
|
||||
return w.Write(b)
|
||||
}
|
||||
|
||||
func (sw *swapWriter) Swap(w io.Writer) {
|
||||
sw.mutex.Lock()
|
||||
sw.w = w
|
||||
sw.mutex.Unlock()
|
||||
}
|
||||
|
||||
func TestLogin(t *testing.T) {
|
||||
client, server := newClientServerPair(t, imap.ConnStateNotAuthenticated)
|
||||
defer client.Close()
|
||||
defer server.Close()
|
||||
|
||||
if err := client.Login(testUsername, testPassword).Wait(); err != nil {
|
||||
t.Errorf("Login().Wait() = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogout(t *testing.T) {
|
||||
client, server := newClientServerPair(t, imap.ConnStateAuthenticated)
|
||||
defer server.Close()
|
||||
|
||||
if _, ok := server.(*dovecotServer); ok {
|
||||
t.Skip("Dovecot connections don't reply to LOGOUT")
|
||||
}
|
||||
|
||||
if err := client.Logout().Wait(); err != nil {
|
||||
t.Errorf("Logout().Wait() = %v", err)
|
||||
}
|
||||
if err := client.Close(); err != nil {
|
||||
t.Errorf("Close() = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/emersion/go-imap/issues/562
|
||||
func TestFetch_invalid(t *testing.T) {
|
||||
client, server := newClientServerPair(t, imap.ConnStateSelected)
|
||||
defer client.Close()
|
||||
defer server.Close()
|
||||
|
||||
_, err := client.Fetch(imap.UIDSet(nil), nil).Collect()
|
||||
if err == nil {
|
||||
t.Fatalf("UIDFetch().Collect() = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetch_closeUnreadBody(t *testing.T) {
|
||||
client, server := newClientServerPair(t, imap.ConnStateSelected)
|
||||
defer client.Close()
|
||||
defer server.Close()
|
||||
|
||||
fetchCmd := client.Fetch(imap.SeqSetNum(1), &imap.FetchOptions{
|
||||
BodySection: []*imap.FetchItemBodySection{
|
||||
{
|
||||
Specifier: imap.PartSpecifierNone,
|
||||
Peek: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err := fetchCmd.Close(); err != nil {
|
||||
t.Fatalf("UIDFetch().Close() = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitGreeting_eof(t *testing.T) {
|
||||
// bad server: connected but without greeting
|
||||
clientConn, serverConn := net.Pipe()
|
||||
|
||||
client := imapclient.New(clientConn, nil)
|
||||
defer client.Close()
|
||||
|
||||
if err := serverConn.Close(); err != nil {
|
||||
t.Fatalf("serverConn.Close() = %v", err)
|
||||
}
|
||||
|
||||
if err := client.WaitGreeting(); err == nil {
|
||||
t.Fatalf("WaitGreeting() should fail")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user