func TestDNSLookupHost(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) ip, err := obj.LookupHost(context.Background(), "servfail.com") t.Logf("servfail.com - IP: %s, Err: %s", ip, err) test.AssertError(t, err, "Server failure") test.Assert(t, len(ip) == 0, "Should not have IPs") ip, err = obj.LookupHost(context.Background(), "nonexistent.letsencrypt.org") t.Logf("nonexistent.letsencrypt.org - IP: %s, Err: %s", ip, err) test.AssertNotError(t, err, "Not an error to not exist") test.Assert(t, len(ip) == 0, "Should not have IPs") // Single IPv4 address ip, err = obj.LookupHost(context.Background(), "cps.letsencrypt.org") t.Logf("cps.letsencrypt.org - IP: %s, Err: %s", ip, err) test.AssertNotError(t, err, "Not an error to exist") test.Assert(t, len(ip) == 1, "Should have IP") ip, err = obj.LookupHost(context.Background(), "cps.letsencrypt.org") t.Logf("cps.letsencrypt.org - IP: %s, Err: %s", ip, err) test.AssertNotError(t, err, "Not an error to exist") test.Assert(t, len(ip) == 1, "Should have IP") // No IPv6 ip, err = obj.LookupHost(context.Background(), "v6.letsencrypt.org") t.Logf("v6.letsencrypt.org - IP: %s, Err: %s", ip, err) test.AssertNotError(t, err, "Not an error to exist") test.Assert(t, len(ip) == 0, "Should not have IPs") }
func TestDNSServFail(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) bad := "servfail.com" _, _, err := obj.LookupTXT(context.Background(), bad) test.AssertError(t, err, "LookupTXT didn't return an error") _, err = obj.LookupHost(context.Background(), bad) test.AssertError(t, err, "LookupHost didn't return an error") // CAA lookup ignores validation failures from the resolver for now // and returns an empty list of CAA records. emptyCaa, err := obj.LookupCAA(context.Background(), bad) test.Assert(t, len(emptyCaa) == 0, "Query returned non-empty list of CAA records") test.AssertNotError(t, err, "LookupCAA returned an error") // When we turn on enforceCAASERVFAIL, such lookups should fail. obj.caaSERVFAILExceptions = map[string]bool{"servfailexception.example.com": true} emptyCaa, err = obj.LookupCAA(context.Background(), bad) test.Assert(t, len(emptyCaa) == 0, "Query returned non-empty list of CAA records") test.AssertError(t, err, "LookupCAA should have returned an error") // Unless they are on the exception list emptyCaa, err = obj.LookupCAA(context.Background(), "servfailexception.example.com") test.Assert(t, len(emptyCaa) == 0, "Query returned non-empty list of CAA records") test.AssertNotError(t, err, "LookupCAA for servfail exception returned an error") }
func TestAllowNilInIsSafeDomain(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl( &cmd.PortConfig{}, nil, nil, nil, nil, "user agent 1.0", "letsencrypt.org", stats, clock.NewFake(), blog.NewMock()) // Be cool with a nil SafeBrowsing. This will happen in prod when we have // flag mismatch between the VA and RA. domain := "example.com" resp, err := va.IsSafeDomain(ctx, &vaPB.IsSafeDomainRequest{Domain: &domain}) if err != nil { t.Errorf("nil SafeBrowsing, unexpected error: %s", err) } if !resp.GetIsSafe() { t.Errorf("nil Safebrowsing, should fail open but failed closed") } }
func TestDNSNoServers(t *testing.T) { obj := NewTestDNSResolverImpl(time.Hour, []string{}, testStats, clock.NewFake(), 1) _, err := obj.LookupHost(context.Background(), "letsencrypt.org") test.AssertError(t, err, "No servers") }
func TestOCSP(t *testing.T) { cases := []testCase{ {"OPTIONS", "/", http.StatusMethodNotAllowed}, {"GET", "/", http.StatusBadRequest}, // Bad URL encoding {"GET", "%ZZFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusBadRequest}, // Bad URL encoding {"GET", "%%FQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusBadRequest}, // Bad base64 encoding {"GET", "==MFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusBadRequest}, // Bad OCSP DER encoding {"GET", "AAAMFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusBadRequest}, // Good encoding all around, including a double slash {"GET", "MFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusOK}, } responder := Responder{ Source: testSource{}, clk: clock.NewFake(), } for _, tc := range cases { rw := httptest.NewRecorder() responder.ServeHTTP(rw, &http.Request{ Method: tc.method, URL: &url.URL{ Path: tc.path, }, }) if rw.Code != tc.expected { t.Errorf("Incorrect response code: got %d, wanted %d", rw.Code, tc.expected) } } }
func TestReconnect(t *testing.T) { ac, mockChannel, finish := setup(t) defer finish() // Override the clock so the sleep calls are instantaneous, regardless of what // the retry calls say. ac.clk = clock.NewFake() ac.retryTimeoutBase = time.Second ac.retryTimeoutMax = time.Second mockChannel.EXPECT().QueueDeclare( "fooqueue", AmqpDurable, AmqpDeleteUnused, AmqpExclusive, AmqpNoWait, nil).AnyTimes() mockChannel.EXPECT().QueueBind("fooqueue", "fooqueue", AmqpExchange, false, nil).Times(3).Return(errors.New("fail")) mockChannel.EXPECT().QueueBind("fooqueue", "fooqueue", AmqpExchange, false, nil).Return(nil) mockChannel.EXPECT().Consume("fooqueue", consumerName, AmqpAutoAck, AmqpExclusive, AmqpNoLocal, AmqpNoWait, nil).Return(make(<-chan amqp.Delivery), nil) mockChannel.EXPECT().NotifyClose(gomock.Any()).Return(make(chan *amqp.Error)) log = blog.UseMock() ac.reconnect(&cmd.AMQPConfig{}, log) if ac.channel != mockChannel { t.Errorf("ac.channel was not equal to mockChannel") } if ac.msgs == nil { t.Errorf("ac.msgs was not initialized") } if ac.closeChan == nil { t.Errorf("ac.closeChan was not initialized") } }
func TestParseLine(t *testing.T) { fc := clock.NewFake() fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC)) sa := &mockSA{} found, added := parseLogLine(sa, log, "") test.AssertEquals(t, found, false) test.AssertEquals(t, added, false) found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: b64der=[] err=[AMQP-RPC timeout], regID=[1337]") test.AssertEquals(t, found, true) test.AssertEquals(t, added, false) found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: b64der=[deadbeef] err=[AMQP-RPC timeout], regID=[]") test.AssertEquals(t, found, true) test.AssertEquals(t, added, false) log.Clear() found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: b64der=[MIIEWzCCA0OgAwIBAgITAP+gFgYw1hiy61wFEIJLFCdIVjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRoYXBweSBoYWNrZXIgZmFrZSBDQTAeFw0xNTEwMDMwNTIxMDBaFw0xNjAxMDEwNTIxMDBaMBgxFjAUBgNVBAMTDWV4YW1wbGUuY28uYm4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCeo/HSH63lWW42pqdwlalHWOS3JGa3REraT3xM9v3psdRwuTtlwf3YlpF/JIzK5JtXyA3CHGSwEGmUMhMNBZ0tg5I0booXnHyUeDVUnGSnpWgMUY+vCly+pI5oT8pjBHdcj6kjnDTx1cstBjsJi9HBcYPHUh78iEZBsvC0FAKsh8cHaEjUNHzvWd1anBdK0lRn25M8le9IxXi6di9SeyFmahmPteH+LYKZtNzrF5HpatB14+ywV8d212T62PCCnUPDLd+YWjo2+t5pZs7IlGhyGh7EerOOrI2kUUBg3tUdKDp4e3xplxvaAfSfdrqkGx+bQ0iqQnng+lVkXWYWRB8NAgMBAAGjggGVMIIBkTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDadDBAEUrnrP/566FLp6DmjrlrbMB8GA1UdIwQYMBaAFPt4TxL5YBWDLJ8XfzQZsy426kGJMGoGCCsGAQUFBwEBBF4wXDAmBggrBgEFBQcwAYYaaHR0cDovL2xvY2FsaG9zdDo0MDAyL29jc3AwMgYIKwYBBQUHMAKGJmh0dHA6Ly9sb2NhbGhvc3Q6NDAwMC9hY21lL2lzc3Vlci1jZXJ0MBgGA1UdEQQRMA+CDWV4YW1wbGUuY28uYm4wJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL2V4YW1wbGUuY29tL2NybDBjBgNVHSAEXDBaMAoGBmeBDAECATAAMEwGAyoDBDBFMCIGCCsGAQUFBwIBFhZodHRwOi8vZXhhbXBsZS5jb20vY3BzMB8GCCsGAQUFBwICMBMMEURvIFdoYXQgVGhvdSBXaWx0MA0GCSqGSIb3DQEBCwUAA4IBAQC7tLmUlxyvouVuIljbRtiL+zYdi/zXVSHAMXTkceqp8/8ucZBZu1fMBkB5SW2FUFd8EnuqhKGOeS3dNr9Pe4dLbUDR0UKIwV045Na+Jet4BbHDdWs3NXAutFhdGIa8ivLBQIbTzlBuVRhJE8g6qqjf5hYL0DXkLNptl2l+0+4xJMm/liCp/mYCGRwbdGUzwdSjACO76QLLSqZhkBF37ZJOuDbJTMBi3QzkOcTs6e4d/gSZpCy7yy6nJDxZ9N9P3XBYIpus+aZAYy29d2shYzE3st8cQfB2Wmb0SHd67sftTAzeudiiNW/4E4IKKH4R1S794apUO07y7pkqep1cz32k] err=[AMQP-RPC timeout], regID=[1001]") test.AssertEquals(t, found, true) test.AssertEquals(t, added, true) checkNoErrors(t) log.Clear() found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: b64der=[MIIEWzCCA0OgAwIBAgITAP+gFgYw1hiy61wFEIJLFCdIVjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRoYXBweSBoYWNrZXIgZmFrZSBDQTAeFw0xNTEwMDMwNTIxMDBaFw0xNjAxMDEwNTIxMDBaMBgxFjAUBgNVBAMTDWV4YW1wbGUuY28uYm4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCeo/HSH63lWW42pqdwlalHWOS3JGa3REraT3xM9v3psdRwuTtlwf3YlpF/JIzK5JtXyA3CHGSwEGmUMhMNBZ0tg5I0booXnHyUeDVUnGSnpWgMUY+vCly+pI5oT8pjBHdcj6kjnDTx1cstBjsJi9HBcYPHUh78iEZBsvC0FAKsh8cHaEjUNHzvWd1anBdK0lRn25M8le9IxXi6di9SeyFmahmPteH+LYKZtNzrF5HpatB14+ywV8d212T62PCCnUPDLd+YWjo2+t5pZs7IlGhyGh7EerOOrI2kUUBg3tUdKDp4e3xplxvaAfSfdrqkGx+bQ0iqQnng+lVkXWYWRB8NAgMBAAGjggGVMIIBkTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDadDBAEUrnrP/566FLp6DmjrlrbMB8GA1UdIwQYMBaAFPt4TxL5YBWDLJ8XfzQZsy426kGJMGoGCCsGAQUFBwEBBF4wXDAmBggrBgEFBQcwAYYaaHR0cDovL2xvY2FsaG9zdDo0MDAyL29jc3AwMgYIKwYBBQUHMAKGJmh0dHA6Ly9sb2NhbGhvc3Q6NDAwMC9hY21lL2lzc3Vlci1jZXJ0MBgGA1UdEQQRMA+CDWV4YW1wbGUuY28uYm4wJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL2V4YW1wbGUuY29tL2NybDBjBgNVHSAEXDBaMAoGBmeBDAECATAAMEwGAyoDBDBFMCIGCCsGAQUFBwIBFhZodHRwOi8vZXhhbXBsZS5jb20vY3BzMB8GCCsGAQUFBwICMBMMEURvIFdoYXQgVGhvdSBXaWx0MA0GCSqGSIb3DQEBCwUAA4IBAQC7tLmUlxyvouVuIljbRtiL+zYdi/zXVSHAMXTkceqp8/8ucZBZu1fMBkB5SW2FUFd8EnuqhKGOeS3dNr9Pe4dLbUDR0UKIwV045Na+Jet4BbHDdWs3NXAutFhdGIa8ivLBQIbTzlBuVRhJE8g6qqjf5hYL0DXkLNptl2l+0+4xJMm/liCp/mYCGRwbdGUzwdSjACO76QLLSqZhkBF37ZJOuDbJTMBi3QzkOcTs6e4d/gSZpCy7yy6nJDxZ9N9P3XBYIpus+aZAYy29d2shYzE3st8cQfB2Wmb0SHd67sftTAzeudiiNW/4E4IKKH4R1S794apUO07y7pkqep1cz32k] err=[AMQP-RPC timeout], regID=[1001]") test.AssertEquals(t, found, true) test.AssertEquals(t, added, false) checkNoErrors(t) }
func TestGenerateMessage(t *testing.T) { fc := clock.NewFake() stats := metrics.NewNoopScope() fromAddress, _ := mail.ParseAddress("happy sender <*****@*****.**>") log := blog.UseMock() m := New("", "", "", "", *fromAddress, log, stats, 0, 0) m.clk = fc m.csprgSource = fakeSource{} messageBytes, err := m.generateMessage([]string{"*****@*****.**"}, "test subject", "this is the body\n") test.AssertNotError(t, err, "Failed to generate email body") message := string(messageBytes) fields := strings.Split(message, "\r\n") test.AssertEquals(t, len(fields), 12) fmt.Println(message) test.AssertEquals(t, fields[0], "To: \"[email protected]\"") test.AssertEquals(t, fields[1], "From: \"happy sender\" <*****@*****.**>") test.AssertEquals(t, fields[2], "Subject: test subject") test.AssertEquals(t, fields[3], "Date: 01 Jan 70 00:00 UTC") test.AssertEquals(t, fields[4], "Message-Id: <*****@*****.**>") test.AssertEquals(t, fields[5], "MIME-Version: 1.0") test.AssertEquals(t, fields[6], "Content-Type: text/plain; charset=UTF-8") test.AssertEquals(t, fields[7], "Content-Transfer-Encoding: quoted-printable") test.AssertEquals(t, fields[8], "") test.AssertEquals(t, fields[9], "this is the body") }
func TestParseLine(t *testing.T) { fc := clock.NewFake() fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC)) sa := &mockSA{} found, added := parseLogLine(sa, log, "") test.AssertEquals(t, found, false) test.AssertEquals(t, added, false) found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[] err=[AMQP-RPC timeout], regID=[1337]") test.AssertEquals(t, found, true) test.AssertEquals(t, added, false) found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[deadbeef] err=[AMQP-RPC timeout], regID=[]") test.AssertEquals(t, found, true) test.AssertEquals(t, added, false) log.Clear() found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[3082045b30820343a003020102021300ffa0160630d618b2eb5c0510824b14274856300d06092a864886f70d01010b0500301f311d301b06035504030c146861707079206861636b65722066616b65204341301e170d3135313030333035323130305a170d3136303130313035323130305a3018311630140603550403130d6578616d706c652e636f2e626e30820122300d06092a864886f70d01010105000382010f003082010a02820101009ea3f1d21fade5596e36a6a77095a94758e4b72466b7444ada4f7c4cf6fde9b1d470b93b65c1fdd896917f248ccae49b57c80dc21c64b010699432130d059d2d8392346e8a179c7c947835549c64a7a5680c518faf0a5cbea48e684fca6304775c8fa9239c34f1d5cb2d063b098bd1c17183c7521efc884641b2f0b41402ac87c7076848d4347cef59dd5a9c174ad25467db933c95ef48c578ba762f527b21666a198fb5e1fe2d8299b4dceb1791e96ad075e3ecb057c776d764fad8f0829d43c32ddf985a3a36fade6966cec89468721a1ec47ab38eac8da4514060ded51d283a787b7c69971bda01f49f76baa41b1f9b4348aa4279e0fa55645d6616441f0d0203010001a382019530820191300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff04023000301d0603551d0e04160414369d0c100452b9eb3ffe7ae852e9e839a3ae5adb301f0603551d23041830168014fb784f12f96015832c9f177f3419b32e36ea4189306a06082b06010505070101045e305c302606082b06010505073001861a687474703a2f2f6c6f63616c686f73743a343030322f6f637370303206082b060105050730028626687474703a2f2f6c6f63616c686f73743a343030302f61636d652f6973737565722d6365727430180603551d110411300f820d6578616d706c652e636f2e626e30270603551d1f0420301e301ca01aa0188616687474703a2f2f6578616d706c652e636f6d2f63726c30630603551d20045c305a300a060667810c0102013000304c06032a03043045302206082b060105050702011616687474703a2f2f6578616d706c652e636f6d2f637073301f06082b0601050507020230130c11446f20576861742054686f752057696c74300d06092a864886f70d01010b05000382010100bbb4b994971cafa2e56e2258db46d88bfb361d8bfcd75521c03174e471eaa9f3ff2e719059bb57cc064079496d8550577c127baa84a18e792ddd36bf4f7b874b6d40d1d14288c15d38e4d6be25eb7805b1c3756b3735702eb4585d1886bc8af2c14086d3ce506e55184913c83aaaa8dfe6160bd035e42cda6d97697ed3ee3124c9bf9620a9fe6602191c1b746533c1d4a30023bbe902cb4aa661901177ed924eb836c94cc062dd0ce439c4ece9ee1dfe0499a42cbbcb2ea7243c59f4df4fdd7058229bacf9a640632dbd776b21633137b2df1c41f0765a66f448777aeec7ed4c0cdeb9d8a2356ff813820a287e11d52efde1aa543b4ef2ee992a7a9d5ccf7da4] err=[AMQP-RPC timeout], regID=[1001]") test.AssertEquals(t, found, true) test.AssertEquals(t, added, true) checkNoErrors(t) log.Clear() found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[3082045b30820343a003020102021300ffa0160630d618b2eb5c0510824b14274856300d06092a864886f70d01010b0500301f311d301b06035504030c146861707079206861636b65722066616b65204341301e170d3135313030333035323130305a170d3136303130313035323130305a3018311630140603550403130d6578616d706c652e636f2e626e30820122300d06092a864886f70d01010105000382010f003082010a02820101009ea3f1d21fade5596e36a6a77095a94758e4b72466b7444ada4f7c4cf6fde9b1d470b93b65c1fdd896917f248ccae49b57c80dc21c64b010699432130d059d2d8392346e8a179c7c947835549c64a7a5680c518faf0a5cbea48e684fca6304775c8fa9239c34f1d5cb2d063b098bd1c17183c7521efc884641b2f0b41402ac87c7076848d4347cef59dd5a9c174ad25467db933c95ef48c578ba762f527b21666a198fb5e1fe2d8299b4dceb1791e96ad075e3ecb057c776d764fad8f0829d43c32ddf985a3a36fade6966cec89468721a1ec47ab38eac8da4514060ded51d283a787b7c69971bda01f49f76baa41b1f9b4348aa4279e0fa55645d6616441f0d0203010001a382019530820191300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff04023000301d0603551d0e04160414369d0c100452b9eb3ffe7ae852e9e839a3ae5adb301f0603551d23041830168014fb784f12f96015832c9f177f3419b32e36ea4189306a06082b06010505070101045e305c302606082b06010505073001861a687474703a2f2f6c6f63616c686f73743a343030322f6f637370303206082b060105050730028626687474703a2f2f6c6f63616c686f73743a343030302f61636d652f6973737565722d6365727430180603551d110411300f820d6578616d706c652e636f2e626e30270603551d1f0420301e301ca01aa0188616687474703a2f2f6578616d706c652e636f6d2f63726c30630603551d20045c305a300a060667810c0102013000304c06032a03043045302206082b060105050702011616687474703a2f2f6578616d706c652e636f6d2f637073301f06082b0601050507020230130c11446f20576861742054686f752057696c74300d06092a864886f70d01010b05000382010100bbb4b994971cafa2e56e2258db46d88bfb361d8bfcd75521c03174e471eaa9f3ff2e719059bb57cc064079496d8550577c127baa84a18e792ddd36bf4f7b874b6d40d1d14288c15d38e4d6be25eb7805b1c3756b3735702eb4585d1886bc8af2c14086d3ce506e55184913c83aaaa8dfe6160bd035e42cda6d97697ed3ee3124c9bf9620a9fe6602191c1b746533c1d4a30023bbe902cb4aa661901177ed924eb836c94cc062dd0ce439c4ece9ee1dfe0499a42cbbcb2ea7243c59f4df4fdd7058229bacf9a640632dbd776b21633137b2df1c41f0765a66f448777aeec7ed4c0cdeb9d8a2356ff813820a287e11d52efde1aa543b4ef2ee992a7a9d5ccf7da4] err=[AMQP-RPC timeout], regID=[1001]") test.AssertEquals(t, found, true) test.AssertEquals(t, added, false) checkNoErrors(t) }
func TestDNSOneServer(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) _, err := obj.LookupHost(context.Background(), "letsencrypt.org") test.AssertNotError(t, err, "No message") }
func TestDNSTXTAuthorities(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) _, auths, err := obj.LookupTXT(context.Background(), "letsencrypt.org") test.AssertNotError(t, err, "TXT lookup failed") test.AssertEquals(t, len(auths), 1) test.AssertEquals(t, auths[0], "letsencrypt.org. 0 IN SOA ns.letsencrypt.org. master.letsencrypt.org. 1 1 1 1 1") }
func newFakeClock(t *testing.T) clock.FakeClock { const fakeTimeFormat = "2006-01-02T15:04:05.999999999Z" ft, err := time.Parse(fakeTimeFormat, fakeTimeFormat) if err != nil { t.Fatal(err) } fc := clock.NewFake() fc.Set(ft.UTC()) return fc }
func TestNotOrphan(t *testing.T) { fc := clock.NewFake() fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC)) sa := &mockSA{} log.Clear() found, added := parseLogLine(sa, log, "base64der=fakeout") test.AssertEquals(t, found, false) test.AssertEquals(t, added, false) checkNoErrors(t) }
// Clock functions similarly to clock.Default(), but the returned value can be // changed using the FAKECLOCK environment variable if the 'integration' build // flag is set. // // The FAKECLOCK env var is in the time.UnixDate format, returned by `date -d`. func Clock() clock.Clock { if tgt := os.Getenv("FAKECLOCK"); tgt != "" { targetTime, err := time.Parse(time.UnixDate, tgt) FailOnError(err, fmt.Sprintf("cmd.Clock: bad format for FAKECLOCK: %v\n", err)) cl := clock.NewFake() cl.Set(targetTime) blog.Get().Info(fmt.Sprintf("Time was set to %v via FAKECLOCK", targetTime)) return cl } return clock.Default() }
func TestDNSLookupTXT(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) a, _, err := obj.LookupTXT(context.Background(), "letsencrypt.org") t.Logf("A: %v", a) test.AssertNotError(t, err, "No message") a, _, err = obj.LookupTXT(context.Background(), "split-txt.letsencrypt.org") t.Logf("A: %v ", a) test.AssertNotError(t, err, "No message") test.AssertEquals(t, len(a), 1) test.AssertEquals(t, a[0], "abc") }
func TestAllowNilInIsSafeDomain(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&cmd.PortConfig{}, nil, nil, stats, clock.NewFake()) // Be cool with a nil SafeBrowsing. This will happen in prod when we have // flag mismatch between the VA and RA. resp, err := va.IsSafeDomain(ctx, &core.IsSafeDomainRequest{Domain: "example.com"}) if err != nil { t.Errorf("nil SafeBrowsing, unexpected error: %s", err) } else if !resp.IsSafe { t.Errorf("nil Safebrowsing, should fail open but failed closed") } }
func TestBase64Padding(t *testing.T) { fc := clock.NewFake() fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC)) sa := &mockSA{} log.Clear() found, added := parseLogLine(sa, log, ` "1459528419376","04/01/2016 16:33:39.376 +0000","2016-04-01T16:33:39.376647+00:00 staging dc 3 boulder-ca[11111]: [AUDIT] Failed RPC to store at SA, orphaning certificate: serial=[fa8b409b865dd77bd203b325624fabf19474] b64der=[MIIEaDCCA1CgAwIBAgITAPqLQJuGXdd70gOzJWJPq/GUdDANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdGYWtlIExFIEludGVybWVkaWF0ZSBYMTAeFw0xNjA0MDExNTM0MDBaFw0xNjA2MzAxNTM0MDBaMEsxGjAYBgNVBAMTEWRlZGloLmZpcnN0dm0ubmV0MS0wKwYDVQQFEyRmYThiNDA5Yjg2NWRkNzdiZDIwM2IzMjU2MjRmYWJmMTk0NzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASmfqA+3kb3yq2M+pOV+J3McEfieBEEoeUjKG6/emkCphZCeQQ4+/+6FIZEsVHvUeGB2lkadU5EYM41JN7yiwd80sN6SV36yrsRrhLGZ8ONpo/Q38c7YZsmIfv/g6SrvH+jggIaMIICFjAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCS41AfMhlnhMOh67w1jeTYBayMzMB8GA1UdIwQYMBaAFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHgGCCsGAQUFBwEBBGwwajAzBggrBgEFBQcwAYYnaHR0cDovL29jc3Auc3RnLWludC14MS5sZXRzZW5jcnlwdC5vcmcvMDMGCCsGAQUFBzAChidodHRwOi8vY2VydC5zdGctaW50LXgxLmxldHNlbmNyeXB0Lm9yZy8wHAYDVR0RBBUwE4IRZGVkaWguZmlyc3R2bS5uZXQwgf4GA1UdIASB9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAKmaeuOS5U6HPPddv8UCmzvOnoVsPq2c++bqmjLjKX8QZrzrVBUiTj5aPM1f4e55nOoGPz9RrXzwoce/MAX2X/YlvG1rxmCshi4/m90keA198kwmmGoPQKtR001D0kFJ2fC9P3omI4K3q24nG2j3SxFFBIcMG2LjEtVYqf2ftBxHBY1hp7DI32wt6Lrs7T/jbv69u2BlKCukmkAxWoig0n4LxaOxZa7KrwCdbLJwipy44WJUVQcJgdf1fTtmRitmIMkCjNo1g8czhYdX3sIo8glYtlBLC8JBokphK72DzSeLSPO2sFQ73URtBzzh60MYLq0GUVM8QfXMxbX+xdWNBgA==] err=[AMQP-RPC timeout], regID=[999999]" `) test.AssertEquals(t, found, true) test.AssertEquals(t, added, true) checkNoErrors(t) }
func setup(t *testing.T) (*amqpConnector, *MockamqpChannel, func()) { mockCtrl := gomock.NewController(t) mockChannel := NewMockamqpChannel(mockCtrl) ac := amqpConnector{ chMaker: mockChannelMaker{ channel: mockChannel, }, queueName: "fooqueue", retryTimeoutBase: time.Second, clk: clock.NewFake(), } return &ac, mockChannel, func() { mockCtrl.Finish() } }
func TestDNSLookupCAA(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) caas, err := obj.LookupCAA(context.Background(), "bracewel.net") test.AssertNotError(t, err, "CAA lookup failed") test.Assert(t, len(caas) > 0, "Should have CAA records") caas, err = obj.LookupCAA(context.Background(), "nonexistent.letsencrypt.org") test.AssertNotError(t, err, "CAA lookup failed") test.Assert(t, len(caas) == 0, "Shouldn't have CAA records") caas, err = obj.LookupCAA(context.Background(), "cname.example.com") test.AssertNotError(t, err, "CAA lookup failed") test.Assert(t, len(caas) > 0, "Should follow CNAME to find CAA") }
func ExampleLogger() { impl := setup(nil) bw, ok := impl.w.(*bothWriter) if !ok { fmt.Printf("Wrong type of impl's writer: %T\n", impl.w) return } bw.clk = clock.NewFake() impl.AuditErr(errors.New("Error Audit")) impl.Warning("Warning Audit") // Output: // [31m[1mE000000 log.test [AUDIT] Error Audit[0m // [33mW000000 log.test Warning Audit[0m }
func setup(t *testing.T) (*Impl, *x509.Certificate, *ecdsa.PrivateKey) { intermediatePEM, _ := pem.Decode([]byte(testIntermediate)) pub := New(nil, nil, 0, log) pub.issuerBundle = append(pub.issuerBundle, ct.ASN1Cert(intermediatePEM.Bytes)) pub.SA = mocks.NewStorageAuthority(clock.NewFake()) leafPEM, _ := pem.Decode([]byte(testLeaf)) leaf, err := x509.ParseCertificate(leafPEM.Bytes) test.AssertNotError(t, err, "Couldn't parse leafPEM.Bytes") k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) test.AssertNotError(t, err, "Couldn't generate test key") return pub, leaf, k }
func TestDNSNXDOMAIN(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) hostname := "nxdomain.letsencrypt.org" _, err := obj.LookupHost(context.Background(), hostname) expected := DNSError{dns.TypeA, hostname, nil, dns.RcodeNameError} if err, ok := err.(*DNSError); !ok || *err != expected { t.Errorf("Looking up %s, got %#v, expected %#v", hostname, err, expected) } _, _, err = obj.LookupTXT(context.Background(), hostname) expected.recordType = dns.TypeTXT if err, ok := err.(*DNSError); !ok || *err != expected { t.Errorf("Looking up %s, got %#v, expected %#v", hostname, err, expected) } }
func TestDNSServFail(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) bad := "servfail.com" _, _, err := obj.LookupTXT(context.Background(), bad) test.AssertError(t, err, "LookupTXT didn't return an error") _, err = obj.LookupHost(context.Background(), bad) test.AssertError(t, err, "LookupHost didn't return an error") // CAA lookup ignores validation failures from the resolver for now // and returns an empty list of CAA records. emptyCaa, err := obj.LookupCAA(context.Background(), bad) test.Assert(t, len(emptyCaa) == 0, "Query returned non-empty list of CAA records") test.AssertNotError(t, err, "LookupCAA returned an error") }
// initSA constructs a SQLStorageAuthority and a clean up function // that should be defer'ed to the end of the test. func initSA(t *testing.T) (*SQLStorageAuthority, clock.FakeClock, func()) { dbMap, err := NewDbMap(vars.DBConnSA, 0) if err != nil { t.Fatalf("Failed to create dbMap: %s", err) } fc := clock.NewFake() fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC)) sa, err := NewSQLStorageAuthority(dbMap, fc, log) if err != nil { t.Fatalf("Failed to create SA: %s", err) } cleanUp := test.ResetSATestDatabase(t) return sa, fc, cleanUp }
func TestCacheHeaders(t *testing.T) { source, err := NewSourceFromFile(responseFile) if err != nil { t.Fatalf("Error constructing source: %s", err) } fc := clock.NewFake() fc.Set(time.Date(2015, 11, 12, 0, 0, 0, 0, time.UTC)) responder := Responder{ Source: source, clk: fc, } rw := httptest.NewRecorder() responder.ServeHTTP(rw, &http.Request{ Method: "GET", URL: &url.URL{ Path: "MEMwQTA/MD0wOzAJBgUrDgMCGgUABBSwLsMRhyg1dJUwnXWk++D57lvgagQU6aQ/7p6l5vLV13lgPJOmLiSOl6oCAhJN", }, }) if rw.Code != http.StatusOK { t.Errorf("Unexpected HTTP status code %d", rw.Code) } testCases := []struct { header string value string }{ {"Last-Modified", "Wed, 21 Oct 2015 20:55:00 UTC"}, {"Expires", "Sun, 20 Oct 2030 00:00:00 UTC"}, {"Cache-Control", "max-age=471398400"}, } for _, tc := range testCases { headers, ok := rw.HeaderMap[tc.header] if !ok { t.Errorf("Header %s missing from HTTP response", tc.header) } if len(headers) != 1 { t.Errorf("Wrong number of headers in HTTP response. Wanted 1, got %d", len(headers)) } actual := headers[0] if actual != tc.value { t.Errorf("Got header %s: %s. Expected %s", tc.header, actual, tc.value) } } }
func TestGetAndProcessCerts(t *testing.T) { saDbMap, err := sa.NewDbMap(vars.DBConnSA, 0) test.AssertNotError(t, err, "Couldn't connect to database") fc := clock.NewFake() checker := newChecker(saDbMap, fc, pa, expectedValidityPeriod) sa, err := sa.NewSQLStorageAuthority(saDbMap, fc, blog.NewMock()) test.AssertNotError(t, err, "Couldn't create SA to insert certificates") saCleanUp := test.ResetSATestDatabase(t) defer func() { saCleanUp() }() testKey, _ := rsa.GenerateKey(rand.Reader, 1024) // Problems // Expiry period is too long rawCert := x509.Certificate{ Subject: pkix.Name{ CommonName: "not-blacklisted.com", }, BasicConstraintsValid: true, DNSNames: []string{"not-blacklisted.com"}, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, } reg := satest.CreateWorkingRegistration(t, sa) test.AssertNotError(t, err, "Couldn't create registration") for i := int64(0); i < 5; i++ { rawCert.SerialNumber = big.NewInt(mrand.Int63()) certDER, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey) test.AssertNotError(t, err, "Couldn't create certificate") _, err = sa.AddCertificate(context.Background(), certDER, reg.ID) test.AssertNotError(t, err, "Couldn't add certificate") } batchSize = 2 err = checker.getCerts(false) test.AssertNotError(t, err, "Failed to retrieve certificates") test.AssertEquals(t, len(checker.certs), 5) wg := new(sync.WaitGroup) wg.Add(1) checker.processCerts(wg, false) test.AssertEquals(t, checker.issuedReport.BadCerts, int64(5)) test.AssertEquals(t, len(checker.issuedReport.Entries), 5) }
func TestIsSafeDomain(t *testing.T) { // TODO(jmhodges): use more of the GSB lib by teaching it how to not make // http requests // This test is mocked out at the wrong level (SafeBrowsing) because the gsb lib // we rely on is a little funny and overcomplicated, but still hasn't // learned out how not make HTTP requests in tests. stats, _ := statsd.NewNoopClient() ctrl := gomock.NewController(t) defer ctrl.Finish() sbc := NewMockSafeBrowsing(ctrl) sbc.EXPECT().IsListed("good.com").Return("", nil) sbc.EXPECT().IsListed("bad.com").Return("bad", nil) sbc.EXPECT().IsListed("errorful.com").Return("", errors.New("welp")) sbc.EXPECT().IsListed("outofdate.com").Return("", safebrowsing.ErrOutOfDateHashes) va := NewValidationAuthorityImpl(&cmd.PortConfig{}, sbc, nil, stats, clock.NewFake()) resp, err := va.IsSafeDomain(ctx, &core.IsSafeDomainRequest{Domain: "good.com"}) if err != nil { t.Errorf("good.com: want no error, got '%s'", err) } if !resp.IsSafe { t.Errorf("good.com: want true, got %t", resp.IsSafe) } resp, err = va.IsSafeDomain(ctx, &core.IsSafeDomainRequest{Domain: "bad.com"}) if err != nil { t.Errorf("bad.com: want no error, got '%s'", err) } if resp.IsSafe { t.Errorf("bad.com: want false, got %t", resp.IsSafe) } _, err = va.IsSafeDomain(ctx, &core.IsSafeDomainRequest{Domain: "errorful.com"}) if err == nil { t.Errorf("errorful.com: want error, got none") } resp, err = va.IsSafeDomain(ctx, &core.IsSafeDomainRequest{Domain: "outofdate.com"}) if err != nil { t.Errorf("outofdate.com: want no error, got '%s'", err) } if !resp.IsSafe { t.Errorf("outofdate.com: IsSafeDomain should fail open on out of date hashes") } }
func TestPurgeAuthzs(t *testing.T) { dbMap, err := sa.NewDbMap(vars.DBConnSAFullPerms, 0) if err != nil { t.Fatalf("Couldn't connect the database: %s", err) } log := blog.UseMock() fc := clock.NewFake() fc.Add(time.Hour) ssa, err := sa.NewSQLStorageAuthority(dbMap, fc, log) if err != nil { t.Fatalf("unable to create SQLStorageAuthority: %s", err) } cleanUp := test.ResetSATestDatabase(t) defer cleanUp() stats := metrics.NewNoopScope() p := expiredAuthzPurger{stats, log, fc, dbMap, 1} rows, err := p.purgeAuthzs(time.Time{}, true) test.AssertNotError(t, err, "purgeAuthzs failed") test.AssertEquals(t, rows, int64(0)) old, new := fc.Now().Add(-time.Hour), fc.Now().Add(time.Hour) reg := satest.CreateWorkingRegistration(t, ssa) _, err = ssa.NewPendingAuthorization(context.Background(), core.Authorization{RegistrationID: reg.ID, Expires: &old}) test.AssertNotError(t, err, "NewPendingAuthorization failed") _, err = ssa.NewPendingAuthorization(context.Background(), core.Authorization{RegistrationID: reg.ID, Expires: &old}) test.AssertNotError(t, err, "NewPendingAuthorization failed") _, err = ssa.NewPendingAuthorization(context.Background(), core.Authorization{RegistrationID: reg.ID, Expires: &new}) test.AssertNotError(t, err, "NewPendingAuthorization failed") rows, err = p.purgeAuthzs(fc.Now(), true) test.AssertNotError(t, err, "purgeAuthzs failed") test.AssertEquals(t, rows, int64(2)) rows, err = p.purgeAuthzs(fc.Now().Add(time.Hour), true) test.AssertNotError(t, err, "purgeAuthzs failed") test.AssertEquals(t, rows, int64(1)) }
func TestConstructAuthHeader(t *testing.T) { stats, _ := statsd.NewNoopClient(nil) cpc, err := NewCachePurgeClient( "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net", "akab-client-token-xxx-xxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=", "akab-access-token-xxx-xxxxxxxxxxxxxxxx", 0, time.Second, nil, stats, ) test.AssertNotError(t, err, "Failed to create cache purge client") fc := clock.NewFake() cpc.clk = fc wantedTimestamp, err := time.Parse(timestampFormat, "20140321T19:34:21+0000") test.AssertNotError(t, err, "Failed to parse timestamp") fc.Add(wantedTimestamp.Sub(fc.Now())) req, err := http.NewRequest( "POST", fmt.Sprintf("%s%s", cpc.apiEndpoint, purgePath), bytes.NewBuffer([]byte{0}), ) test.AssertNotError(t, err, "Failed to create request") expectedHeader := "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=hXm4iCxtpN22m4cbZb4lVLW5rhX8Ca82vCFqXzSTPe4=" authHeader, err := cpc.constructAuthHeader( req, []byte("datadatadatadatadatadatadatadata"), "/testapi/v1/t3", "nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", ) test.AssertNotError(t, err, "Failed to create authorization header") test.AssertEquals(t, authHeader, expectedHeader) }
func TestRetry(t *testing.T) { isTempErr := &net.OpError{Op: "read", Err: tempError(true)} nonTempErr := &net.OpError{Op: "read", Err: tempError(false)} servFailError := errors.New("DNS problem: server failure at resolver looking up TXT for example.com") netError := errors.New("DNS problem: networking error looking up TXT for example.com") type testCase struct { maxTries int te *testExchanger expected error expectedCount int } tests := []*testCase{ // The success on first try case { maxTries: 3, te: &testExchanger{ errs: []error{nil}, }, expected: nil, expectedCount: 1, }, // Immediate non-OpError, error returns immediately { maxTries: 3, te: &testExchanger{ errs: []error{errors.New("nope")}, }, expected: servFailError, expectedCount: 1, }, // Temporary err, then non-OpError stops at two tries { maxTries: 3, te: &testExchanger{ errs: []error{isTempErr, errors.New("nope")}, }, expected: servFailError, expectedCount: 2, }, // Temporary error given always { maxTries: 3, te: &testExchanger{ errs: []error{ isTempErr, isTempErr, isTempErr, }, }, expected: netError, expectedCount: 3, }, // Even with maxTries at 0, we should still let a single request go // through { maxTries: 0, te: &testExchanger{ errs: []error{nil}, }, expected: nil, expectedCount: 1, }, // Temporary error given just once causes two tries { maxTries: 3, te: &testExchanger{ errs: []error{ isTempErr, nil, }, }, expected: nil, expectedCount: 2, }, // Temporary error given twice causes three tries { maxTries: 3, te: &testExchanger{ errs: []error{ isTempErr, isTempErr, nil, }, }, expected: nil, expectedCount: 3, }, // Temporary error given thrice causes three tries and fails { maxTries: 3, te: &testExchanger{ errs: []error{ isTempErr, isTempErr, isTempErr, }, }, expected: netError, expectedCount: 3, }, // temporary then non-Temporary error causes two retries { maxTries: 3, te: &testExchanger{ errs: []error{ isTempErr, nonTempErr, }, }, expected: netError, expectedCount: 2, }, } for i, tc := range tests { dr := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), tc.maxTries) dr.dnsClient = tc.te _, _, err := dr.LookupTXT(context.Background(), "example.com") if err == errTooManyRequests { t.Errorf("#%d, sent more requests than the test case handles", i) } expectedErr := tc.expected if (expectedErr == nil && err != nil) || (expectedErr != nil && err == nil) || (expectedErr != nil && expectedErr.Error() != err.Error()) { t.Errorf("#%d, error, expected %v, got %v", i, expectedErr, err) } if tc.expectedCount != tc.te.count { t.Errorf("#%d, error, expectedCount %v, got %v", i, tc.expectedCount, tc.te.count) } } dr := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 3) dr.dnsClient = &testExchanger{errs: []error{isTempErr, isTempErr, nil}} ctx, cancel := context.WithCancel(context.Background()) cancel() _, _, err := dr.LookupTXT(ctx, "example.com") if err == nil || err.Error() != "DNS problem: query timed out looking up TXT for example.com" { t.Errorf("expected %s, got %s", context.Canceled, err) } dr.dnsClient = &testExchanger{errs: []error{isTempErr, isTempErr, nil}} ctx, _ = context.WithTimeout(context.Background(), -10*time.Hour) _, _, err = dr.LookupTXT(ctx, "example.com") if err == nil || err.Error() != "DNS problem: query timed out looking up TXT for example.com" { t.Errorf("expected %s, got %s", context.DeadlineExceeded, err) } dr.dnsClient = &testExchanger{errs: []error{isTempErr, isTempErr, nil}} ctx, deadlineCancel := context.WithTimeout(context.Background(), -10*time.Hour) deadlineCancel() _, _, err = dr.LookupTXT(ctx, "example.com") if err == nil || err.Error() != "DNS problem: query timed out looking up TXT for example.com" { t.Errorf("expected %s, got %s", context.DeadlineExceeded, err) } }