const R = require("ramda"); const { getDomainService, diffRecords } = require("../utils/domain-service"); const { DOMAIN_DOMAIN } = require("../utils/constants"); const getCpanel = ({ zone, addZone, removeZone, redir, addRedir, removeRedir, addEmail, removeEmail, } = {}) => ({ zone: { fetch: (_) => zone(), add: (rec) => addZone(rec), remove: (rec) => removeZone(rec), }, redirection: { fetch: (_) => redir(), add: (rec) => addRedir(rec), remove: (rec) => removeRedir(rec), }, email: { add: (rec) => addEmail(rec), remove: (rec) => removeEmail(rec), }, }); describe("diffRecords", () => { it("should show added record", () => { const oldRecords = [ { name: "xx", type: "CNAME", address: "fck.com." }, { name: "xa", type: "A", address: "111.1.1212.1" }, ]; const newRecords = [ { name: "xx", type: "CNAME", address: "fck.com." }, { name: "xa", type: "A", address: "111.1.1212.1" }, { name: "boo", type: "CNAME", address: "x.com" }, ]; const result = diffRecords(oldRecords, newRecords); expect(result).toEqual({ remove: [], add: [{ name: "boo", type: "CNAME", address: "x.com" }], }); }); it("should show edited records", () => { const oldRecords = [ { name: "xx", type: "CNAME", address: "fck.com." }, { name: "xa", type: "A", address: "111.1.1212.1" }, ]; const newRecords = [ { name: "xx", type: "CNAME", address: "fck.com." }, { name: "xa", type: "A", address: "69.69.69.69" }, ]; const result = diffRecords(oldRecords, newRecords); expect(result).toEqual({ remove: [{ name: "xa", type: "A", address: "111.1.1212.1" }], add: [{ name: "xa", type: "A", address: "69.69.69.69" }], }); }); it("should show added records with the same name and record type", () => { const oldRecords = [ { name: "xx", type: "CNAME", address: "fck.com." }, { name: "xa", type: "A", address: "69.69.69.69" }, ]; const newRecords = [ { name: "xx", type: "CNAME", address: "fck.com." }, { name: "xa", type: "A", address: "69.69.69.69" }, { name: "xa", type: "A", address: "69.69.4.20" }, ]; const result = diffRecords(oldRecords, newRecords); expect(result).toEqual({ remove: [], add: [{ name: "xa", type: "A", address: "69.69.4.20" }], }); }); it("should diff complex changes", () => { const oldRecords = [ { name: "a", type: "CNAME", address: "fck.com." }, { name: "b", type: "A", address: "69.69.69.69" }, { name: "111", type: "CNAME", address: "x" }, { name: "d", type: "A", address: "69.69.4.20" }, ]; const newRecords = [ { name: "111", type: "CNAME", address: "x" }, { name: "d", type: "CNAME", address: "duck.com" }, { name: "a", type: "CNAME", address: "og.com" }, { name: "b", type: "A", address: "69.69.69.69" }, { name: "b", type: "A", address: "69.69.4.20" }, { name: "c", type: "CNAME", address: "ccc.cc" }, ]; const result = diffRecords(oldRecords, newRecords); expect(result).toEqual({ remove: [ { name: "a", type: "CNAME", address: "fck.com." }, { name: "d", type: "A", address: "69.69.4.20" }, ], add: [ { name: "d", type: "CNAME", address: "duck.com" }, { name: "a", type: "CNAME", address: "og.com" }, { name: "b", type: "A", address: "69.69.4.20" }, { name: "c", type: "CNAME", address: "ccc.cc" }, ], }); }); }); describe("Domain service", () => { const addZone = jest.fn(async () => ({})); const removeZone = jest.fn(async () => ({})); const addRedir = jest.fn(async () => ({})); const removeRedir = jest.fn(async () => ({})); const addEmail = jest.fn(async () => ({})); const removeEmail = jest.fn(async () => ({})); const mockDS = ({ zones, redirections }) => getDomainService({ cpanel: getCpanel({ zone: async () => zones, redir: async () => redirections, addZone, addEmail, addRedir, removeZone, removeRedir, removeEmail, }), }); const getRecordCalls = (recfn) => recfn.mock.calls .map(R.head) .map( R.pick([ "name", "type", "address", "redirect", "domain", "line", "priority", "exchanger", ]), ); beforeEach(() => { addZone.mockClear(); removeZone.mockClear(); addRedir.mockClear(); removeRedir.mockClear(); addEmail.mockClear(); removeEmail.mockClear(); }); describe("getHosts", () => { it("should resolve with a list of hosts", async () => { const zones = [ { name: "xx", type: "CNAME", address: "fck.com." }, { name: "xx", type: "A", address: "111.1.1212.1" }, ]; const redirections = []; const zone = async () => zones; const redir = async () => redirections; const mockDomainService = getDomainService({ cpanel: getCpanel({ zone, redir }), }); const list = await mockDomainService.getHosts(); expect(list).toEqual([ { name: "xx", type: "CNAME", address: "fck.com" }, { name: "xx", type: "A", address: "111.1.1212.1" }, ]); }); it("should resolve with a redirections", async () => { const zones = [ { line: "111", name: "xx", type: "CNAME", address: "fck.com." }, { line: "112", name: "xx", type: "A", address: "111.1.1212.1" }, ]; const redirections = [ { domain: "foo.booboo.xyz", destination: "https://google.com" }, { domain: "foo1.booboo.xyz", destination: "https://duck.com" }, ]; const zone = async () => zones; const redir = async () => redirections; const mockDomainService = getDomainService({ cpanel: getCpanel({ zone, redir }), }); const list = await mockDomainService.getHosts(); expect(list).toEqual([ { id: "111", name: "xx", type: "CNAME", address: "fck.com" }, { id: "112", name: "xx", type: "A", address: "111.1.1212.1" }, { id: `foo.${DOMAIN_DOMAIN}`, name: "foo", type: "URL", address: "https://google.com", }, { id: `foo1.${DOMAIN_DOMAIN}`, name: "foo1", type: "URL", address: "https://duck.com", }, ]); }); }); describe("updateHosts", () => { it("should append new hosts with existing ones and set it", async () => { const zones = [ { line: 1, name: "a", type: "CNAME", address: "boo" }, { line: 2, name: "b", type: "CNAME", address: "goo" }, ]; const redirections = []; const mockDomainService = mockDS({ zones, redirections }); await mockDomainService.updateHosts([ { name: "a", type: "CNAME", address: "boo" }, { name: "b", type: "CNAME", address: "goo" }, { name: "c", type: "A", address: "12.131321.213" }, { name: "c", type: "MX", address: "foobar.com", priority: 2 }, ]); expect(addZone).toHaveBeenCalledTimes(1); expect(getRecordCalls(addZone)).toEqual([ { name: "c", type: "A", address: "12.131321.213" }, ]); expect(addEmail).toHaveBeenCalledTimes(1); expect(getRecordCalls(addEmail)).toEqual([ { domain: "c.is-a.dev", exchanger: "foobar.com", priority: 2 }, ]); expect(removeZone).toHaveBeenCalledTimes(0); expect(removeEmail).toHaveBeenCalledTimes(0); }); it("should update matching host and set it", async () => { const zones = [ { line: 1, name: "a", type: "CNAME", address: "boo" }, { line: 2, name: "b", type: "CNAME", address: "goo" }, ]; const redirections = []; const mockDomainService = mockDS({ zones, redirections }); await mockDomainService.updateHosts([ { name: "a", type: "CNAME", address: "boo" }, { name: "b", type: "CNAME", address: "googoogaga" }, ]); expect(addZone).toHaveBeenCalledTimes(1); expect(getRecordCalls(addZone)).toEqual([ { name: "b", type: "CNAME", address: "googoogaga" }, ]); expect(removeZone).toHaveBeenCalledTimes(1); expect(getRecordCalls(removeZone)).toEqual([{ line: 2 }]); }); it("should update matching host and set it", async () => { const zones = [ { line: 1, name: "a", type: "CNAME", address: "boo" }, { line: 2, name: "b", type: "CNAME", address: "goo" }, { line: 3, name: "b", type: "CNAME", address: "xaa" }, ]; const redirections = []; const mockDomainService = mockDS({ zones, redirections }); await mockDomainService.updateHosts([ { name: "a", type: "CNAME", address: "boo" }, { name: "b", type: "CNAME", address: "googoogaga" }, { name: "b", type: "CNAME", address: "farboo" }, ]); expect(addZone).toHaveBeenCalledTimes(2); expect(getRecordCalls(addZone)).toEqual([ { name: "b", type: "CNAME", address: "googoogaga" }, { name: "b", type: "CNAME", address: "farboo" }, ]); expect(removeZone).toHaveBeenCalledTimes(2); expect(getRecordCalls(removeZone)).toEqual([ { line: 3 }, { line: 2 }, ]); }); it("should workout this complex example", async () => { const zones = [ { line: 1, name: "a", type: "CNAME", address: "world" }, { line: 2, name: "b", type: "A", address: "1" }, { line: 3, name: "b", type: "A", address: "2" }, { line: 4, name: "c", type: "CNAME", address: "hello.com" }, { line: 5, name: "c", type: "MX", address: "mx1.hello.com", priority: 20, }, { line: 6, name: "c", type: "MX", address: "mx2.hello.com", priority: 21, }, { line: 7, name: "b", type: "MX", address: "foo.bar", priority: 20, }, { line: 101, name: "x", type: "A", address: "1" }, { line: 99, name: "y", type: "A", address: "2" }, { line: 100, name: "z", type: "A", address: "3" }, ]; const redirections = [ { domain: `b.${DOMAIN_DOMAIN}`, destination: "https://foobar.com", }, { domain: `c.${DOMAIN_DOMAIN}`, destination: "https://goobar.com", }, { domain: `x.${DOMAIN_DOMAIN}`, destination: "https://example.com", }, ]; const mockDomainService = mockDS({ zones, redirections }); await mockDomainService.updateHosts([ { name: "a", type: "CNAME", address: "boo" }, { name: "b", type: "A", address: "1" }, { name: "b", type: "A", address: "2" }, { name: "b", type: "A", address: "3" }, { name: "b", type: "URL", address: "https://wowow.com" }, { name: "c", type: "CNAME", address: "hello.com" }, { name: "c", type: "URL", address: "https://goobar.com" }, { name: "d", type: "CNAME", address: "helo.com" }, { name: "d", type: "URL", address: "https://hhh.com" }, { name: "x", type: "URL", address: "https://example69.com" }, { name: "c", type: "MX", address: "mx2.hello.com", priority: 21, }, { name: "a", type: "MX", address: "example.com", priority: 20 }, ]); expect(addZone).toHaveBeenCalledTimes(3); expect(getRecordCalls(addZone)).toEqual([ { name: "a", type: "CNAME", address: "boo" }, { name: "b", type: "A", address: "3" }, { name: "d", type: "CNAME", address: "helo.com" }, ]); expect(removeZone).toHaveBeenCalledTimes(4); expect(getRecordCalls(removeZone)).toEqual([ { line: 101 }, { line: 100 }, { line: 99 }, { line: 1 }, ]); expect(addEmail).toHaveBeenCalledTimes(1); expect(getRecordCalls(addEmail)).toEqual([ { domain: "a.is-a.dev", exchanger: "example.com", priority: 20, }, ]); expect(removeEmail).toHaveBeenCalledTimes(2); expect(getRecordCalls(removeEmail)).toEqual([ { domain: "b.is-a.dev", exchanger: "foo.bar", priority: 20 }, { domain: "c.is-a.dev", exchanger: "mx1.hello.com", priority: 20, }, ]); expect(addRedir).toHaveBeenCalledTimes(3); expect(getRecordCalls(addRedir)).toEqual([ { domain: `b.${DOMAIN_DOMAIN}`, type: "permanent", redirect: "https://wowow.com", }, { domain: `d.${DOMAIN_DOMAIN}`, type: "permanent", redirect: "https://hhh.com", }, { domain: `x.${DOMAIN_DOMAIN}`, type: "permanent", redirect: "https://example69.com", }, ]); expect(removeRedir).toHaveBeenCalledTimes(2); expect(getRecordCalls(removeRedir)).toEqual([ { domain: `b.${DOMAIN_DOMAIN}` }, { domain: `x.${DOMAIN_DOMAIN}` }, ]); }); }); });