require 'spec_helper'
require 'net/dns/resolver/timeouts'

describe Net::DNS::Resolver do
  it 'executes UDP query' do
    ipv4_sock = instance_double(UDPSocket, bind: 0, send: 0)
    ipv6_sock = instance_double(UDPSocket, bind: 0)

    google_com_a_record_response = [
      "A\x06\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06google\x03com\x00\x00\x01\x00\x01\xC0\f\x00\x01\x00\x01\x00\x00\x00I\x00\x04\x8E\xFA\xBA\xCE",
      ['AF_INET', 53, '8.8.8.8', '8.8.8.8']
    ]
    allow(ipv4_sock).to receive(:recvfrom).and_return(google_com_a_record_response)

    allow(UDPSocket).to receive(:new).and_return(ipv4_sock)
    allow(UDPSocket).to receive(:new).with(Socket::AF_INET6).and_return(ipv6_sock)

    resolver = Net::DNS::Resolver.new(nameservers: %w[8.8.8.8])
    response = resolver.query('google.com')

    expect(response.answer[0].address.to_s).to eq('142.250.186.206')
    expect(ipv4_sock).to have_received(:bind).with(instance_of(String), instance_of(Integer))
    expect(ipv4_sock).to have_received(:send).with(instance_of(String), 0, '8.8.8.8', 53)
    expect(ipv4_sock).to have_received(:recvfrom).with(instance_of(Integer))
  end

  it 'executes TCP query' do
    sock = instance_double(Socket, bind: 0, connect: 0, write: 0, close: nil)

    allow(sock).to receive(:recv).and_return("\x00,")
    google_com_a_record_response = "%\xF9\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06google\x03com\x00\x00\x01\x00\x01\xC0\f\x00\x01\x00\x01\x00\x00\x00\xB3\x00\x04\x8E\xFA\xBA\xCE"
    allow(sock).to receive(:recvfrom).and_return(google_com_a_record_response)

    allow(Socket).to receive(:new).and_return(sock)

    resolver = Net::DNS::Resolver.new(nameservers: %w[8.8.8.8], use_tcp: true)
    response = resolver.query('google.com')

    expect(response.answer[0].address.to_s).to eq('142.250.186.206')
    expect(sock).to have_received(:bind).with(instance_of(String))
    expect(sock).to have_received(:connect).with(Socket.pack_sockaddr_in(53, '8.8.8.8'))
    expect(sock).to have_received(:write).with(instance_of(String))
    expect(sock).to have_received(:recv)
    expect(sock).to have_received(:recvfrom).with(instance_of(Integer))
    expect(sock).to have_received(:close)
  end
end
