package dnsresolver_test

import (
	"errors"

	fakesys "github.com/cloudfoundry/bosh-utils/system/fakes"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"

	. "github.com/cloudfoundry/bosh-agent/v2/platform/net/dnsresolver"
)

var _ = Describe("resolveConfResolver", func() {
	var (
		fs                  *fakesys.FakeFileSystem
		cmdRunner           *fakesys.FakeCmdRunner
		resolveConfResolver DNSResolver
	)

	BeforeEach(func() {
		fs = fakesys.NewFakeFileSystem()
		cmdRunner = fakesys.NewFakeCmdRunner()
		resolveConfResolver = NewResolveConfResolver(fs, cmdRunner)
	})

	Context("when /etc/resolv.conf contains at least one dns server", func() {
		BeforeEach(func() {
			err := fs.WriteFileString("/etc/resolv.conf", `
				nameserver 8.8.8.8
				nameserver 9.9.9.9`)
			Expect(err).NotTo(HaveOccurred())
		})

		It("returns nil", func() {
			err := resolveConfResolver.Validate([]string{"8.8.8.8", "10.10.10.10"})
			Expect(err).ToNot(HaveOccurred())
		})
	})

	Context("when reading /etc/resolv.conf failed", func() {
		It("returns error", func() {
			err := resolveConfResolver.Validate([]string{"8.8.8.8", "9.9.9.9"})
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("Reading /etc/resolv.conf"))
		})
	})

	Context("when /etc/resolv.conf does not contain any of the dns servers specified in the manifest", func() {
		BeforeEach(func() {
			err := fs.WriteFileString("/etc/resolv.conf", `nameserver 6.6.6.6`)
			Expect(err).NotTo(HaveOccurred())
		})

		It("returns error", func() {
			err := resolveConfResolver.Validate([]string{"8.8.8.8", "9.9.9.9"})
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("None of the DNS servers that were specified in the manifest were found in /etc/resolv.conf."))
		})
	})

	Context("when there are configured DNS servers", func() {
		It("writes DNS to /etc/resolvconf/resolv.conf.d/base", func() {
			err := resolveConfResolver.SetupDNS([]string{"8.8.8.8", "9.9.9.9"})
			Expect(err).ToNot(HaveOccurred())

			resolvConfBase := fs.GetFileTestStat("/etc/resolvconf/resolv.conf.d/base")
			Expect(resolvConfBase).ToNot(BeNil())

			expectedResolvConfBase := `# Generated by bosh-agent
nameserver 8.8.8.8
nameserver 9.9.9.9
`
			Expect(resolvConfBase.StringContents()).To(Equal(expectedResolvConfBase))
			Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"resolvconf", "-u"}))
		})

		Context("when writing to ../resolv.conf.d/base fails", func() {
			It("fails reporting the error", func() {
				fs.WriteFileError = errors.New("fake-write-file-error")

				err := resolveConfResolver.SetupDNS([]string{"8.8.8.8", "9.9.9.9"})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("Writing to /etc/resolvconf/resolv.conf.d/base"))
			})
		})
	})

	Context("when no DNS servers are configured", func() {

		Context("when could not read link /etc/resolv.conf", func() {
			It("fails reporting error", func() {
				fs.ReadAndFollowLinkError = errors.New("fake-read-link-error")

				err := resolveConfResolver.SetupDNS([]string{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("Reading /etc/resolv.conf symlink"))
			})
		})

		Context("when /etc/resolv.conf is no symlink", func() {
			BeforeEach(func() {
				err := fs.Symlink("/etc/resolv.conf", "/etc/resolv.conf")
				Expect(err).ToNot(HaveOccurred())

				err = fs.WriteFileString("/etc/resolv.conf", "fake-content")
				Expect(err).ToNot(HaveOccurred())
			})

			It("copies /etc/resolv.conf to .../resolv.conf.d/base", func() {
				err := resolveConfResolver.SetupDNS([]string{})
				Expect(err).ToNot(HaveOccurred())

				contents, err := fs.ReadFile("/etc/resolvconf/resolv.conf.d/base")
				Expect(err).ToNot(HaveOccurred())
				Expect(string(contents)).To(Equal("fake-content"))
			})

			Context("when copying fails", func() {
				It("fails reporting the error", func() {
					fs.CopyFileError = errors.New("fake-copy-error")

					err := resolveConfResolver.SetupDNS([]string{})
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("Copying /etc/resolv.conf for backwards compat"))
				})
			})
		})
	})

})
