package resolver import ( "syscall" "testing" "github.com/miekg/dns" "github.com/stretchr/testify/assert" ) // TestClassifyResponse sets a nameserver's status from the results of // its queries, built here. One that answered some record types, even // with no records, has not failed when its query for another type got // no usable reply, whatever the reason; one whose every query got none // has. func TestClassifyResponse(t *testing.T) { t.Parallel() tests := []struct { name string results queryState wantStatus string wantError string }{ { "some types answered with no records, another timed out", queryState{answered: true, gotTimeout: true}, StatusNoData, "", }, { "some types answered with no records, another got SERVFAIL", queryState{answered: true, errorReply: "SERVFAIL"}, StatusNoData, "", }, { "some types answered with no records, another was refused", queryState{answered: true, gotRefused: true}, StatusNoData, "", }, { "some types answered with no records, another got a network error", queryState{answered: true, netErr: syscall.ECONNREFUSED}, StatusNoData, "", }, { "some types answered with no records, another's reply was " + "truncated and its retry over TCP failed", queryState{answered: true, netErr: ErrTruncated}, StatusNoData, "", }, { "some types answered with no records, another got a referral", queryState{answered: true, gotReferral: true}, StatusNoData, "", }, { "every query timed out", queryState{gotTimeout: true}, StatusTimeout, "all queries timed out", }, { "every query got NOTIMP", queryState{errorReply: "NOTIMP"}, StatusError, "server returned NOTIMP", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() resp := &NameserverResponse{Status: StatusOK} classifyResponse(resp, tt.results) assert.Equal(t, tt.wantStatus, resp.Status) assert.Equal(t, tt.wantError, resp.Error) }) } } // TestReadReply checks which replies to a query about one record type, // built here, are an answer: one with the code NOERROR or NXDOMAIN. A // reply with any other code is not, and the type's query has failed. func TestReadReply(t *testing.T) { t.Parallel() tests := []struct { rcode int answered bool }{ {dns.RcodeSuccess, true}, {dns.RcodeNameError, true}, {dns.RcodeServerFailure, false}, {dns.RcodeNotImplemented, false}, {dns.RcodeFormatError, false}, } for _, tt := range tests { t.Run(dns.RcodeToString[tt.rcode], func(t *testing.T) { t.Parallel() msg := new(dns.Msg) msg.Authoritative = true msg.Rcode = tt.rcode resp := &NameserverResponse{Records: map[string][]string{}} err := readReply(msg, resp, &queryState{}) if tt.answered { assert.NoError(t, err) } else { assert.ErrorIs(t, err, ErrUnusableReply) } }) } }