Repository: StackExchange/dnscontrol
Pull request #2040 (2023-02-01 12:54:34)

CLOUDFLARE: Adopt diff2
<!--
Before you submit a pull request, please make sure you've run the following commands from the root directory.

go fmt ./...
go generate
go mod tidy
!-->

CC @tresni 

This implements the diff2 algorithm for Cloudflare.

* Use diff2.ByRecord to use the diff2 algorithm.
* nativeToRecord now populates Metadata with proxy state
* splitTTLOnly should use .compareable, not er.GetTargetCombined(), so that proxy changes are seen.
* humanDiff should take targetConfig, not RecordConfig, to show proxy changes to the user.
* comparable is renamed mkCompareBlob to be more searchable
* mkCompareBlob should be aware of proxy settings.
* COSMETIC: in GetDomainCorrections, change the variable `id` to `domainID` to be more clear


tlimoncelli: All tests pass:

```
$ time go test -v -verbose -provider CLOUDFLAREAPI -diff2
=== RUN   TestDNSProviders
=== RUN   TestDNSProviders/dnscontroltest-cf.com
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Clean_Slate:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/00:A:Create_A
    integration_test.go:223: CREATE testa.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/00:A:Change_A_target
    integration_test.go:223: CHANGE testa.dnscontroltest-cf.com A (1.1.1.1 ttl=1 proxy=off) -> (1.2.3.4 ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty
    integration_test.go:223: DELETE testa.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=6ea5ae5bdb274380da3a4ecd6946a8e6
=== RUN   TestDNSProviders/dnscontroltest-cf.com/01:MX:Create_MX
    integration_test.go:223: CREATE testmx.dnscontroltest-cf.com MX 5 foo.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/01:MX:Change_MX_target
    integration_test.go:223: CHANGE testmx.dnscontroltest-cf.com MX (5 foo.com. ttl=1) -> (5 bar.com. ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/01:MX:Change_MX_p
    integration_test.go:223: CHANGE testmx.dnscontroltest-cf.com MX (5 bar.com. ttl=1) -> (100 bar.com. ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#01
    integration_test.go:223: DELETE testmx.dnscontroltest-cf.com MX 100 bar.com. ttl=1 id=44d1dc54d53935dbb92ca5a514e206d4
=== RUN   TestDNSProviders/dnscontroltest-cf.com/02:CNAME:Create_a_CNAME
    integration_test.go:223: CREATE testcname.dnscontroltest-cf.com CNAME www.google.com. ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/02:CNAME:Change_CNAME_target
    integration_test.go:223: CHANGE testcname.dnscontroltest-cf.com CNAME (www.google.com. ttl=1 proxy=off) -> (www.yahoo.com. ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#02
    integration_test.go:223: DELETE testcname.dnscontroltest-cf.com CNAME www.yahoo.com. ttl=1 proxy=off id=34ffc9f5a5413cd8688ad0c204659adc
=== RUN   TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:CreateManyAtLabel
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 2.2.2.2 ttl=1 proxy=off
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 3.3.3.3 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:Empty
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off id=3a285f497420cb353df92886c4f112aa
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 2.2.2.2 ttl=1 proxy=off id=dcd034042408b61739bc829ca6178de4
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 3.3.3.3 ttl=1 proxy=off id=4fe10fd932d969450b281d240e7bdc07
=== RUN   TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:Create_an_A_record
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:Add_at_label1
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 2.2.2.2 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:Add_at_label2
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 3.3.3.3 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#03
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off id=24f0d4fab0d6729f54429ff0b12e1b91
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 2.2.2.2 ttl=1 proxy=off id=6f6ff5e5db0f76b7fc976dd587c00fbc
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 3.3.3.3 ttl=1 proxy=off id=d693ea447c4684bc1c157c2a5a5e9500
=== RUN   TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:CreateManyTypesAtLabel
    integration_test.go:223: CREATE testmx.dnscontroltest-cf.com MX 100 bar.com. ttl=1
    integration_test.go:223: CREATE testmx.dnscontroltest-cf.com MX 5 foo.com. ttl=1
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:Empty
    integration_test.go:223: DELETE testmx.dnscontroltest-cf.com MX 100 bar.com. ttl=1 id=77ea54096c4fe86359f0a9a130ac4911
    integration_test.go:223: DELETE testmx.dnscontroltest-cf.com MX 5 foo.com. ttl=1 id=d0eb0605e27119d9664a46dcda988521
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off id=1a2333ef77e16d9bf22c4ba7777194e7
=== RUN   TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:Create_an_A_record
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:Add_Type_At_Label
    integration_test.go:223: CREATE testmx.dnscontroltest-cf.com MX 5 foo.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:Add_Type_At_Label#01
    integration_test.go:223: CREATE testmx.dnscontroltest-cf.com MX 100 bar.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#04
    integration_test.go:223: DELETE testmx.dnscontroltest-cf.com MX 100 bar.com. ttl=1 id=ff649fa1257027bf7e8970ede0f26ba9
    integration_test.go:223: DELETE testmx.dnscontroltest-cf.com MX 5 foo.com. ttl=1 id=9da7c1a2da3c916df83002d186d3c98f
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off id=514342979ac58fb153e0b8dc2ecd04e3
=== RUN   TestDNSProviders/dnscontroltest-cf.com/05:Apex:Create_A
    integration_test.go:223: CREATE dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/05:Apex:Change_A_target
    integration_test.go:223: CHANGE dnscontroltest-cf.com A (1.1.1.1 ttl=1 proxy=off) -> (1.2.3.4 ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#05
    integration_test.go:223: DELETE dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=1d07802b224f93376789303d428fec29
=== RUN   TestDNSProviders/dnscontroltest-cf.com/06:TTL:Start
    integration_test.go:223: CREATE dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 5.6.7.8 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/06:TTL:Change_a_ttl
    integration_test.go:223: CHANGE dnscontroltest-cf.com A (1.2.3.4 ttl=1 proxy=off ttl=1) -> (1.2.3.4 ttl=1000 proxy=off ttl=1000)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/06:TTL:Change_single_target_from_set
    integration_test.go:223: CHANGE www.dnscontroltest-cf.com A (1.2.3.4 ttl=1 proxy=off) -> (2.2.2.2 ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/06:TTL:Change_all_ttls
    integration_test.go:223: CHANGE dnscontroltest-cf.com A (1.2.3.4 ttl=1000 proxy=off ttl=1000) -> (1.2.3.4 ttl=500 proxy=off ttl=500)
    integration_test.go:223: CHANGE www.dnscontroltest-cf.com A (2.2.2.2 ttl=1 proxy=off ttl=1) -> (2.2.2.2 ttl=400 proxy=off ttl=400)
    integration_test.go:223: CHANGE www.dnscontroltest-cf.com A (5.6.7.8 ttl=1 proxy=off ttl=1) -> (5.6.7.8 ttl=400 proxy=off ttl=400)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#06
    integration_test.go:223: DELETE dnscontroltest-cf.com A 1.2.3.4 ttl=500 proxy=off id=d2836fcf23d46d299464fa87548c681a
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 2.2.2.2 ttl=400 proxy=off id=0f77b3d82c83cb20d8deee6cefeb92e3
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 5.6.7.8 ttl=400 proxy=off id=29e2f3a72954783bf121c3c117ce7038
=== RUN   TestDNSProviders/dnscontroltest-cf.com/07:add_to_label_and_change_orig_ttl:Setup
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 5.6.7.8 ttl=400 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/07:add_to_label_and_change_orig_ttl:Add_at_same_label,_new_ttl
    integration_test.go:223: CHANGE www.dnscontroltest-cf.com A (5.6.7.8 ttl=400 proxy=off ttl=400) -> (1.2.3.4 ttl=700 proxy=off ttl=700)
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 5.6.7.8 ttl=700 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#07
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 1.2.3.4 ttl=700 proxy=off id=dab5a074159d16ea5013485ca4883ea1
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 5.6.7.8 ttl=700 proxy=off id=12fa5f1e600262251a3d633d08cb95fa
=== RUN   TestDNSProviders/dnscontroltest-cf.com/08:Protocol-Wildcard:Create_wildcard
    integration_test.go:223: CREATE *.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: CREATE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/08:Protocol-Wildcard:Delete_wildcard
    integration_test.go:223: DELETE *.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=083859f698ad765205c4b346ea863414
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#08
    integration_test.go:223: DELETE www.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off id=7ae12741c40c0ea8f69d2dbcef7b499a
=== RUN   TestDNSProviders/dnscontroltest-cf.com/09:TypeChange:Create_a_CNAME
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com CNAME google.com. ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/09:TypeChange:Change_to_A_record
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com CNAME google.com. ttl=1 proxy=off id=ac6b0cdf9dd6ed6a3a64d8fb5c24ee82
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/09:TypeChange:Change_back_to_CNAME
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=8d89080c8e098960f46b427a54b46fbc
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com CNAME google2.com. ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#09
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com CNAME google2.com. ttl=1 proxy=off id=2257cb7d634fe2f61406ad8da9b4880d
=== RUN   TestDNSProviders/dnscontroltest-cf.com/10:CommonDNS:Create_1_of_each
    integration_test.go:223: CREATE testcname.dnscontroltest-cf.com CNAME example.com. ttl=1 proxy=off
    integration_test.go:223: CREATE testmx.dnscontroltest-cf.com MX 5 foo.com. ttl=1
    integration_test.go:223: CREATE testtxt.dnscontroltest-cf.com TXT "simple" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/10:CommonDNS:Change_param1
    integration_test.go:223: CHANGE testcname.dnscontroltest-cf.com CNAME (example.com. ttl=1 proxy=off) -> (example2.com. ttl=1 proxy=off)
    integration_test.go:223: CHANGE testmx.dnscontroltest-cf.com MX (5 foo.com. ttl=1) -> (6 foo.com. ttl=1)
    integration_test.go:223: CHANGE testtxt.dnscontroltest-cf.com TXT ("simple" ttl=1) -> ("changed" ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/10:CommonDNS:Change_param2
    integration_test.go:223: CHANGE testmx.dnscontroltest-cf.com MX (6 foo.com. ttl=1) -> (6 bar.com. ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#10
    integration_test.go:223: DELETE testcname.dnscontroltest-cf.com CNAME example2.com. ttl=1 proxy=off id=839cd14633da0d6bb567cae849540e3c
    integration_test.go:223: DELETE testmx.dnscontroltest-cf.com MX 6 bar.com. ttl=1 id=b43fdaf993e6f455bccbd2f86ff55c72
    integration_test.go:223: DELETE testtxt.dnscontroltest-cf.com TXT "changed" ttl=1 id=daeda1f742136ffdfb83f8abd146572b
=== RUN   TestDNSProviders/dnscontroltest-cf.com/11:CNAME:Record_pointing_to_@
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com CNAME dnscontroltest-cf.com. ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#11
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com CNAME dnscontroltest-cf.com. ttl=1 proxy=off id=34683b29e7cffeb9540b1a49b1189ea8
=== RUN   TestDNSProviders/dnscontroltest-cf.com/12:MX:Record_pointing_to_@
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com MX 8 dnscontroltest-cf.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/12:MX:Null_MX
    integration_test.go:223: CREATE dnscontroltest-cf.com MX 0 . ttl=1
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com MX 8 dnscontroltest-cf.com. ttl=1 id=cbfdef03bfc9559c0b51cb0d76f36963
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#12
    integration_test.go:223: DELETE dnscontroltest-cf.com MX 0 . ttl=1 id=d5654064d3836dc88d991d969f693a96
=== RUN   TestDNSProviders/dnscontroltest-cf.com/13:NS:NS_for_subdomain
    integration_test.go:223: CREATE xyz.dnscontroltest-cf.com NS ns2.foo.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/13:NS:Dual_NS_for_subdomain
    integration_test.go:223: CREATE xyz.dnscontroltest-cf.com NS ns1.foo.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/13:NS:NS_Record_pointing_to_@
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com NS dnscontroltest-cf.com. ttl=1
    integration_test.go:223: CREATE dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: DELETE xyz.dnscontroltest-cf.com NS ns1.foo.com. ttl=1 id=3485fcfab34d80aeff0778aaf95048fc
    integration_test.go:223: DELETE xyz.dnscontroltest-cf.com NS ns2.foo.com. ttl=1 id=f8f5c12db958d96b5c2f2195d5ff4802
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#13
    integration_test.go:223: DELETE dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=da13a5aa64bcb115ea528f7e5e2455ad
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com NS dnscontroltest-cf.com. ttl=1 id=fa2a01d8d62b6811801407f429ae4312
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_0-octel_string
    integration_test.go:209: ***SKIPPED(PROVIDER DOES NOT SUPPORT '[txtstring is empty]' ::"14:complex TXT")
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_255-byte_TXT
    integration_test.go:223: CREATE foo255.dnscontroltest-cf.com TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_256-byte_TXT
    integration_test.go:223: DELETE foo255.dnscontroltest-cf.com TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" ttl=1 id=c1451eedf5b31b705689f9dd02c05ec0
    integration_test.go:223: CREATE foo256.dnscontroltest-cf.com TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_512-byte_TXT
    integration_test.go:223: DELETE foo256.dnscontroltest-cf.com TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ttl=1 id=0eeab5a5d0fa939522cb4d0b946c17f7
    integration_test.go:223: CREATE foo512.dnscontroltest-cf.com TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_513-byte_TXT
    integration_test.go:223: DELETE foo512.dnscontroltest-cf.com TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" ttl=1 id=139a114d64467ed0af6c4e2b71773257
    integration_test.go:223: CREATE foo513.dnscontroltest-cf.com TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_1_single-quote
    integration_test.go:223: DELETE foo513.dnscontroltest-cf.com TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ttl=1 id=6a6579f0d3cbee98859cb81a73a1bebb
    integration_test.go:223: CREATE foosq.dnscontroltest-cf.com TXT "quo'te" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_1_backtick
    integration_test.go:223: CREATE foobt.dnscontroltest-cf.com TXT "blah`blah" ttl=1
    integration_test.go:223: DELETE foosq.dnscontroltest-cf.com TXT "quo'te" ttl=1 id=85d8ae02e4d7d83014d93437a9df7ccf
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_1_double-quotes
    integration_test.go:223: DELETE foobt.dnscontroltest-cf.com TXT "blah`blah" ttl=1 id=92c16fe3bbd1729376dc9ae0b59a5750
    integration_test.go:223: CREATE foodq.dnscontroltest-cf.com TXT "quo\"te" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_2_double-quotes
    integration_test.go:223: DELETE foodq.dnscontroltest-cf.com TXT "quo\"te" ttl=1 id=389bf099383664989b5ba76396ed7585
    integration_test.go:223: CREATE foodqs.dnscontroltest-cf.com TXT "q\"uo\"te" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_TXT_with_interior_ws
    integration_test.go:223: DELETE foodqs.dnscontroltest-cf.com TXT "q\"uo\"te" ttl=1 id=167d6893cdeb0817820c69b46f40f9db
    integration_test.go:223: CREATE foosp.dnscontroltest-cf.com TXT "with spaces" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_ws_at_end
    integration_test.go:209: ***SKIPPED(PROVIDER DOES NOT SUPPORT '[txtstring ends with space]' ::"14:complex TXT")
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#14
    integration_test.go:223: DELETE foosp.dnscontroltest-cf.com TXT "with spaces" ttl=1 id=8b2d1cc0def1e14c46367f1cc8650e83
=== RUN   TestDNSProviders/dnscontroltest-cf.com/15:Case_Sensitivity:Create_CAPS
    integration_test.go:223: CREATE bar.dnscontroltest-cf.com MX 5 bar.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/15:Case_Sensitivity:Downcase_label
    integration_test.go:223: CREATE decoy.dnscontroltest-cf.com A 1.1.1.1 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/15:Case_Sensitivity:Downcase_target
    integration_test.go:223: CHANGE decoy.dnscontroltest-cf.com A (1.1.1.1 ttl=1 proxy=off) -> (2.2.2.2 ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/15:Case_Sensitivity:Upcase_both
    integration_test.go:223: CHANGE decoy.dnscontroltest-cf.com A (2.2.2.2 ttl=1 proxy=off) -> (3.3.3.3 ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#15
    integration_test.go:223: DELETE bar.dnscontroltest-cf.com MX 5 bar.com. ttl=1 id=37a85188b7be4f01415ae01798bb4cae
    integration_test.go:223: DELETE decoy.dnscontroltest-cf.com A 3.3.3.3 ttl=1 proxy=off id=e3ac1e109b1392cef766d615c86e6650
=== RUN   TestDNSProviders/dnscontroltest-cf.com/16:IDNA:Internationalized_name
    integration_test.go:223: CREATE xn--ndaaa.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/16:IDNA:Change_IDN
    integration_test.go:223: CHANGE xn--ndaaa.dnscontroltest-cf.com A (1.2.3.4 ttl=1 proxy=off) -> (2.2.2.2 ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/16:IDNA:Internationalized_CNAME_Target
    integration_test.go:223: CREATE a.dnscontroltest-cf.com CNAME xn--ndaaa.com. ttl=1 proxy=off
    integration_test.go:223: DELETE xn--ndaaa.dnscontroltest-cf.com A 2.2.2.2 ttl=1 proxy=off id=d9aa610b49c6e1470c318ec92052c302
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#16
    integration_test.go:223: DELETE a.dnscontroltest-cf.com CNAME xn--ndaaa.com. ttl=1 proxy=off id=a9a920b89c6381b4708e918b6b4d58d5
=== RUN   TestDNSProviders/dnscontroltest-cf.com/17:IDNAs_in_CNAME_targets_***SKIPPED(excluded_by_not("CLOUDFLAREAPI"))***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/18:pager101_***SKIPPED(excluded_by_not("CLOUDFLAREAPI"))***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/19:pager601_***SKIPPED(disabled_by_only)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/20:pager1201_***SKIPPED(disabled_by_only)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/21:NS1_URLFWD_tests_***SKIPPED(disabled_by_only)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_record
    integration_test.go:223: CREATE dnscontroltest-cf.com CAA 0 issue "letsencrypt.org" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_change_tag
    integration_test.go:223: CHANGE dnscontroltest-cf.com CAA (0 issue "letsencrypt.org" ttl=1) -> (0 issuewild "letsencrypt.org" ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_change_target
    integration_test.go:223: CHANGE dnscontroltest-cf.com CAA (0 issuewild "letsencrypt.org" ttl=1) -> (0 issuewild "example.com" ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_change_flag
    integration_test.go:223: CHANGE dnscontroltest-cf.com CAA (0 issuewild "example.com" ttl=1) -> (128 issuewild "example.com" ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_many_records
    integration_test.go:223: CHANGE dnscontroltest-cf.com CAA (128 issuewild "example.com" ttl=1) -> (128 issuewild ";" ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_whitespace
    integration_test.go:223: CHANGE dnscontroltest-cf.com CAA (128 issuewild ";" ttl=1) -> (0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#17
    integration_test.go:223: DELETE dnscontroltest-cf.com CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" ttl=1 id=cd38449ab8e9865e3f17264426e182a1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/23:NAPTR_***SKIPPED(CanUseNAPTR_not_supported)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/24:PTR:Create_PTR_record
    integration_test.go:223: CREATE 4.dnscontroltest-cf.com PTR foo.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/24:PTR:Modify_PTR_record
    integration_test.go:223: CHANGE 4.dnscontroltest-cf.com PTR (foo.com. ttl=1) -> (bar.com. ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#18
    integration_test.go:223: DELETE 4.dnscontroltest-cf.com PTR bar.com. ttl=1 id=fe56800aa354df2625eeb523cae176a5
=== RUN   TestDNSProviders/dnscontroltest-cf.com/25:SOA_***SKIPPED(CanUseSOA_not_supported)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:SRV_record
    integration_test.go:223: CREATE _sip._tcp.dnscontroltest-cf.com SRV 5 6 7 foo.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:Second_SRV_record,_same_prio
    integration_test.go:223: CREATE _sip._tcp.dnscontroltest-cf.com SRV 5 60 70 foo2.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:3_SRV
    integration_test.go:223: CREATE _sip._tcp.dnscontroltest-cf.com SRV 15 65 75 foo3.com. ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:Delete_one
    integration_test.go:223: DELETE _sip._tcp.dnscontroltest-cf.com SRV 5 60 70 foo2.com. ttl=1 id=6c0181d4cc148e8668350f1a6c838b6c
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:Change_Target
    integration_test.go:223: CHANGE _sip._tcp.dnscontroltest-cf.com SRV (15 65 75 foo3.com. ttl=1) -> (15 65 75 foo4.com. ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:Change_Priority
    integration_test.go:223: CHANGE _sip._tcp.dnscontroltest-cf.com SRV (5 6 7 foo.com. ttl=1) -> (52 6 7 foo.com. ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:Change_Weight
    integration_test.go:223: CHANGE _sip._tcp.dnscontroltest-cf.com SRV (52 6 7 foo.com. ttl=1) -> (52 62 7 foo.com. ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:Change_Port
    integration_test.go:223: CHANGE _sip._tcp.dnscontroltest-cf.com SRV (52 62 7 foo.com. ttl=1) -> (52 62 72 foo.com. ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:Empty
    integration_test.go:223: DELETE _sip._tcp.dnscontroltest-cf.com SRV 15 65 75 foo4.com. ttl=1 id=ccd7168d272115d9c651630c221bb8fe
    integration_test.go:223: DELETE _sip._tcp.dnscontroltest-cf.com SRV 52 62 72 foo.com. ttl=1 id=bf1770fa2e2163c3b6f211bfc10978e8
=== RUN   TestDNSProviders/dnscontroltest-cf.com/26:SRV:Null_Target
    integration_test.go:223: CREATE _sip._tcp.dnscontroltest-cf.com SRV 15 65 75 . ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#19
    integration_test.go:223: DELETE _sip._tcp.dnscontroltest-cf.com SRV 15 65 75 . ttl=1 id=9b4597569a1647840dad591ce6d46bde
=== RUN   TestDNSProviders/dnscontroltest-cf.com/27:SSHFP:SSHFP_record
    integration_test.go:223: CREATE dnscontroltest-cf.com SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/27:SSHFP:SSHFP_change_algorithm
    integration_test.go:223: CHANGE dnscontroltest-cf.com SSHFP (1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C ttl=1) -> (2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/27:SSHFP:SSHFP_change_fingerprint_and_type
    integration_test.go:223: CHANGE dnscontroltest-cf.com SSHFP (2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C ttl=1) -> (2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#20
    integration_test.go:223: DELETE dnscontroltest-cf.com SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC ttl=1 id=7d53342dc71d8b3d44d016660d4ba020
=== RUN   TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_record
    integration_test.go:223: CREATE _443._tcp.dnscontroltest-cf.com TLSA 3 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_change_usage
    integration_test.go:223: CHANGE _443._tcp.dnscontroltest-cf.com TLSA (3 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ttl=1) -> (2 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_change_selector
    integration_test.go:223: CHANGE _443._tcp.dnscontroltest-cf.com TLSA (2 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ttl=1) -> (2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_change_matchingtype
    integration_test.go:223: CHANGE _443._tcp.dnscontroltest-cf.com TLSA (2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ttl=1) -> (2 0 2 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_change_certificate
    integration_test.go:223: CHANGE _443._tcp.dnscontroltest-cf.com TLSA (2 0 2 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ttl=1) -> (2 0 2 fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#21
    integration_test.go:223: DELETE _443._tcp.dnscontroltest-cf.com TLSA 2 0 2 fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 ttl=1 id=821f3fda98fcf35d1d504b31d3e0cb10
=== RUN   TestDNSProviders/dnscontroltest-cf.com/29:DS_***SKIPPED(CanUseDS_not_supported)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/30:DS_(children_only)_***SKIPPED(excluded_by_not("CLOUDFLAREAPI"))***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:create_DS
    integration_test.go:223: CREATE child.dnscontroltest-cf.com NS ns101.cloudns.net. ttl=1
    integration_test.go:223: CREATE child.dnscontroltest-cf.com DS 35632 13 1 1E07663FF507A40874B8605463DD41DE482079D6 ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:modify_field_1
    integration_test.go:223: CHANGE child.dnscontroltest-cf.com DS (35632 13 1 1E07663FF507A40874B8605463DD41DE482079D6 ttl=1) -> (2075 13 1 2706D12E256C8FDD9BFB45EFB25FE537E21A82F6 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:modify_field_3
    integration_test.go:223: CHANGE child.dnscontroltest-cf.com DS (2075 13 1 2706D12E256C8FDD9BFB45EFB25FE537E21A82F6 ttl=1) -> (2075 13 2 3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:modify_field_2+3
    integration_test.go:223: CHANGE child.dnscontroltest-cf.com DS (2075 13 2 3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156 ttl=1) -> (2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:modify_field_2
    integration_test.go:223: CHANGE child.dnscontroltest-cf.com DS (2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 ttl=1) -> (63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:delete_1,_create_1
    integration_test.go:223: DELETE child.dnscontroltest-cf.com DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B ttl=1 id=74d5c622556f5b850d13b7226b0ba38f
    integration_test.go:223: CREATE another-child.dnscontroltest-cf.com NS ns101.cloudns.net. ttl=1
    integration_test.go:223: CREATE another-child.dnscontroltest-cf.com DS 35632 13 4 F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429 ttl=1
    integration_test.go:223: DELETE child.dnscontroltest-cf.com NS ns101.cloudns.net. ttl=1 id=b1fef857f29b45aa779a062b4c55f16c
=== RUN   TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:add_2_more_DS
    integration_test.go:223: CREATE another-child.dnscontroltest-cf.com DS 2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 ttl=1
    integration_test.go:223: CREATE another-child.dnscontroltest-cf.com DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#22
    integration_test.go:223: DELETE another-child.dnscontroltest-cf.com DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B ttl=1 id=d5653461a5417f7d02f30db387e3e277
    integration_test.go:223: DELETE another-child.dnscontroltest-cf.com DS 35632 13 4 F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429 ttl=1 id=c8928e1804e066b6a43a7f1ed056a717
    integration_test.go:223: DELETE another-child.dnscontroltest-cf.com DS 2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 ttl=1 id=120245db27aeca9d58bb4592dc4357d5
    integration_test.go:223: DELETE another-child.dnscontroltest-cf.com NS ns101.cloudns.net. ttl=1 id=c14a16e6ffebc4a907c2212ed2872c03
=== RUN   TestDNSProviders/dnscontroltest-cf.com/32:ALIAS:ALIAS_at_root
    integration_test.go:223: CREATE dnscontroltest-cf.com CNAME foo.com. ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/32:ALIAS:change_it
    integration_test.go:223: CHANGE dnscontroltest-cf.com CNAME (foo.com. ttl=1 proxy=off) -> (foo2.com. ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/32:ALIAS:ALIAS_at_subdomain
    integration_test.go:223: DELETE dnscontroltest-cf.com CNAME foo2.com. ttl=1 proxy=off id=561c2c8d55b0dd910c504bc24c158eaa
    integration_test.go:223: CREATE test.dnscontroltest-cf.com CNAME foo.com. ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/32:ALIAS:change_it#01
    integration_test.go:223: CHANGE test.dnscontroltest-cf.com CNAME (foo.com. ttl=1 proxy=off) -> (foo2.com. ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#23
    integration_test.go:223: DELETE test.dnscontroltest-cf.com CNAME foo2.com. ttl=1 proxy=off id=80c315a03ecc625ef8128d8297a6591c
=== RUN   TestDNSProviders/dnscontroltest-cf.com/33:AZURE_ALIAS_***SKIPPED(CanUseAzureAlias_not_supported)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/34:R53_ALIAS2_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/35:R53_ALIAS_ORDER_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/36:R53_ALIAS_CNAME_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:redir
    integration_test.go:223: CREATE dnscontroltest-cf.com PAGE_RULE cnn.dnscontroltest-cf.com/*,https://www.cnn.com/$1,1,301 ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:change
    integration_test.go:223: CHANGE dnscontroltest-cf.com PAGE_RULE (cnn.dnscontroltest-cf.com/*,https://www.cnn.com/$1,1,301 ttl=1) -> (cnn.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,301 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:changelabel
    integration_test.go:223: CHANGE dnscontroltest-cf.com PAGE_RULE (cnn.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,301 ttl=1) -> (cable.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,301 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:Empty
    integration_test.go:223: DELETE dnscontroltest-cf.com PAGE_RULE cable.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,301 ttl=1 id=66e97c9648f6a5f236c44cc294781968
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempredir
    integration_test.go:223: CREATE dnscontroltest-cf.com PAGE_RULE cnn.dnscontroltest-cf.com/*,https://www.cnn.com/$1,1,302 ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempchange
    integration_test.go:223: CHANGE dnscontroltest-cf.com PAGE_RULE (cnn.dnscontroltest-cf.com/*,https://www.cnn.com/$1,1,302 ttl=1) -> (cnn.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,302 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempchangelabel
    integration_test.go:223: CHANGE dnscontroltest-cf.com PAGE_RULE (cnn.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,302 ttl=1) -> (cable.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,302 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:Empty#01
    integration_test.go:223: DELETE dnscontroltest-cf.com PAGE_RULE cable.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,302 ttl=1 id=ba453800a76e20c20e14d64cb2812550
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempmultipleA
    integration_test.go:223: CREATE dnscontroltest-cf.com PAGE_RULE cnn.dnscontroltest-cf.com/*,https://www.cnn.com/$1,2,302 ttl=1
    integration_test.go:223: CREATE dnscontroltest-cf.com PAGE_RULE msnbc.dnscontroltest-cf.com/*,https://msnbc.cnn.com/$1,1,302 ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:Empty#02
    integration_test.go:223: DELETE dnscontroltest-cf.com PAGE_RULE cnn.dnscontroltest-cf.com/*,https://www.cnn.com/$1,2,302 ttl=1 id=6e2894141f81ff4f20fe440dfcad80a1
    integration_test.go:223: DELETE dnscontroltest-cf.com PAGE_RULE msnbc.dnscontroltest-cf.com/*,https://msnbc.cnn.com/$1,1,302 ttl=1 id=d2265f35dbc4ba49106fea78e032a348
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempmultipleB
    integration_test.go:223: CREATE dnscontroltest-cf.com PAGE_RULE cnn.dnscontroltest-cf.com/*,https://www.cnn.com/$1,1,302 ttl=1
    integration_test.go:223: CREATE dnscontroltest-cf.com PAGE_RULE msnbc.dnscontroltest-cf.com/*,https://msnbc.cnn.com/$1,2,302 ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempchange1
    integration_test.go:223: CHANGE dnscontroltest-cf.com PAGE_RULE (cnn.dnscontroltest-cf.com/*,https://www.cnn.com/$1,1,302 ttl=1) -> (cnn.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,302 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempchange1#01
    integration_test.go:223: CHANGE dnscontroltest-cf.com PAGE_RULE (cnn.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,302 ttl=1) -> (cablenews.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,302 ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#24
    integration_test.go:223: DELETE dnscontroltest-cf.com PAGE_RULE cablenews.dnscontroltest-cf.com/*,https://change.cnn.com/$1,1,302 ttl=1 id=42d884f138d7a78790bd3c3b6be3ff1c
    integration_test.go:223: DELETE dnscontroltest-cf.com PAGE_RULE msnbc.dnscontroltest-cf.com/*,https://msnbc.cnn.com/$1,2,302 ttl=1 id=004d013cf5beed998a26c0e39f255646
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxyon
    integration_test.go:223: CREATE proxyme.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=on
        ACTIVATE PROXY for new record proxyme A 1 1.2.3.4
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxychangetarget
    integration_test.go:223: CHANGE proxyme.dnscontroltest-cf.com A (1.2.3.4 ttl=1 proxy=on) -> (1.2.3.5 ttl=1 proxy=on)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxychangeonoff
    integration_test.go:223: CHANGE proxyme.dnscontroltest-cf.com A (1.2.3.5 ttl=1 proxy=on) -> (1.2.3.5 ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxychangeoffon
    integration_test.go:223: CHANGE proxyme.dnscontroltest-cf.com A (1.2.3.5 ttl=1 proxy=off) -> (1.2.3.5 ttl=1 proxy=on)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:Empty
    integration_test.go:223: DELETE proxyme.dnscontroltest-cf.com A 1.2.3.5 ttl=1 proxy=on id=7f4b42f3f646bfe869d424e2e01e23c6
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxycname
    integration_test.go:223: CREATE anewproxy.dnscontroltest-cf.com CNAME example.com. ttl=1 proxy=on
        ACTIVATE PROXY for new record anewproxy CNAME 1 example.com.
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxycnamechange
    integration_test.go:223: CHANGE anewproxy.dnscontroltest-cf.com CNAME (example.com. ttl=1 proxy=on) -> (example.com. ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxycnameoffon
    integration_test.go:223: CHANGE anewproxy.dnscontroltest-cf.com CNAME (example.com. ttl=1 proxy=off) -> (example.com. ttl=1 proxy=on)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxycnameonoff
    integration_test.go:223: CHANGE anewproxy.dnscontroltest-cf.com CNAME (example.com. ttl=1 proxy=on) -> (example.com. ttl=1 proxy=off)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:Empty#01
    integration_test.go:223: DELETE anewproxy.dnscontroltest-cf.com CNAME example.com. ttl=1 proxy=off id=69999c1687206e9cd15a17fabbc0da0a
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#25
=== RUN   TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:simple
    integration_test.go:223: CREATE dnscontroltest-cf.com WORKER_ROUTE cnn.dnscontroltest-cf.com/*,dnscontrol_integrationtest_cnn ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:changeScript
    integration_test.go:223: CHANGE dnscontroltest-cf.com WORKER_ROUTE (cnn.dnscontroltest-cf.com/*,dnscontrol_integrationtest_cnn ttl=1) -> (cnn.dnscontroltest-cf.com/*,dnscontrol_integrationtest_msnbc ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:changePattern
    integration_test.go:223: CHANGE dnscontroltest-cf.com WORKER_ROUTE (cnn.dnscontroltest-cf.com/*,dnscontrol_integrationtest_msnbc ttl=1) -> (cable.dnscontroltest-cf.com/*,dnscontrol_integrationtest_msnbc ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:Empty
    integration_test.go:223: DELETE dnscontroltest-cf.com WORKER_ROUTE cable.dnscontroltest-cf.com/*,dnscontrol_integrationtest_msnbc ttl=1 id=bce258110fb34b69b3c02d0e937b4554
=== RUN   TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:createMultiple
    integration_test.go:223: CREATE dnscontroltest-cf.com WORKER_ROUTE cnn.dnscontroltest-cf.com/*,dnscontrol_integrationtest_cnn ttl=1
    integration_test.go:223: CREATE dnscontroltest-cf.com WORKER_ROUTE msnbc.dnscontroltest-cf.com/*,dnscontrol_integrationtest_msnbc ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:addOne
    integration_test.go:223: CREATE dnscontroltest-cf.com WORKER_ROUTE api.dnscontroltest-cf.com/cnn/*,dnscontrol_integrationtest_cnn ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:changeOne
    integration_test.go:223: CHANGE dnscontroltest-cf.com WORKER_ROUTE (msnbc.dnscontroltest-cf.com/*,dnscontrol_integrationtest_msnbc ttl=1) -> (msn.dnscontroltest-cf.com/*,dnscontrol_integrationtest_msnbc ttl=1)
=== RUN   TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:deleteOne
    integration_test.go:223: DELETE dnscontroltest-cf.com WORKER_ROUTE cnn.dnscontroltest-cf.com/*,dnscontrol_integrationtest_cnn ttl=1 id=e226d589d8dd4a3696c0eead116eb381
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#26
    integration_test.go:223: DELETE dnscontroltest-cf.com WORKER_ROUTE api.dnscontroltest-cf.com/cnn/*,dnscontrol_integrationtest_cnn ttl=1 id=2507ee54710b410e978f4793cad47b28
    integration_test.go:223: DELETE dnscontroltest-cf.com WORKER_ROUTE msn.dnscontroltest-cf.com/*,dnscontrol_integrationtest_msnbc ttl=1 id=0d8013c4a0f044d3bcb6c867b93a781f
=== RUN   TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Create_some_records
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com TXT "simple" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Add_a_new_record_-_ignoring_foo
    integration_test.go:223: CREATE bar.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=2ca467c2ac824a834e19281c82daff2a
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com TXT "simple" ttl=1 id=969b161b39b5b7d399774e4c93e30d81
=== RUN   TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Empty
    integration_test.go:223: DELETE bar.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=fdea60734dd9224cf1566ac50fbce2e8
=== RUN   TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Create_some_records#01
    integration_test.go:223: CREATE bar.foo.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: CREATE bar.foo.dnscontroltest-cf.com TXT "simple" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Add_a_new_record_-_ignoring_*.foo
    integration_test.go:223: CREATE bar.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: DELETE bar.foo.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=28abdbd0123b900a3a67720cd9e8177a
    integration_test.go:223: DELETE bar.foo.dnscontroltest-cf.com TXT "simple" ttl=1 id=3a79de043b04b270e9d05fa8e438182f
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#27
    integration_test.go:223: DELETE bar.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=e6d3dca3aff1fd1b6a0323a87a96f56e
=== RUN   TestDNSProviders/dnscontroltest-cf.com/41:IGNORE_NAME_apex:Create_some_records
    integration_test.go:223: CREATE dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: CREATE dnscontroltest-cf.com TXT "simple" ttl=1
    integration_test.go:223: CREATE bar.dnscontroltest-cf.com A 2.4.6.8 ttl=1 proxy=off
    integration_test.go:223: CREATE bar.dnscontroltest-cf.com TXT "stringbar" ttl=1
=== RUN   TestDNSProviders/dnscontroltest-cf.com/41:IGNORE_NAME_apex:Add_a_new_record_-_ignoring_apex
    integration_test.go:223: DELETE dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=7774bea33c08c0c9a3105f17c306e305
    integration_test.go:223: DELETE dnscontroltest-cf.com TXT "simple" ttl=1 id=3df4fbfeb3e409d5d458a0b305579bc8
    integration_test.go:223: CREATE added.dnscontroltest-cf.com A 4.6.8.9 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#28
    integration_test.go:223: DELETE added.dnscontroltest-cf.com A 4.6.8.9 ttl=1 proxy=off id=59ba4f14fcae4c0c2569344ff5b2aecf
    integration_test.go:223: DELETE bar.dnscontroltest-cf.com A 2.4.6.8 ttl=1 proxy=off id=5e0e60c98613b778562889acab99eb6a
    integration_test.go:223: DELETE bar.dnscontroltest-cf.com TXT "stringbar" ttl=1 id=11cfd7f7c7c83fa20a46ec3e902acaea
=== RUN   TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Create_some_records
    integration_test.go:223: CREATE bar.dnscontroltest-cf.com CNAME test.bar.com. ttl=1 proxy=off
    integration_test.go:223: CREATE foo.dnscontroltest-cf.com CNAME test.foo.com. ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Add_a_new_record_-_ignoring_test.foo.com.
    integration_test.go:223: CHANGE bar.dnscontroltest-cf.com CNAME (test.bar.com. ttl=1 proxy=off) -> (bar.foo.com. ttl=1 proxy=off)
    integration_test.go:223: DELETE foo.dnscontroltest-cf.com CNAME test.foo.com. ttl=1 proxy=off id=9a40a56049f502af2e1ae6e8814af8b7
=== RUN   TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Empty
    integration_test.go:223: DELETE bar.dnscontroltest-cf.com CNAME bar.foo.com. ttl=1 proxy=off id=accc3253fe220d26cc636a3ef54efda8
=== RUN   TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Create_some_records#01
    integration_test.go:223: CREATE bar.foo.dnscontroltest-cf.com CNAME a.b.foo.com. ttl=1 proxy=off
    integration_test.go:223: CREATE test.foo.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
=== RUN   TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Add_a_new_record_-_ignoring_**.foo.com._targets
    integration_test.go:223: CREATE bar.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off
    integration_test.go:223: DELETE bar.foo.dnscontroltest-cf.com CNAME a.b.foo.com. ttl=1 proxy=off id=031f273e4b462e16a9db38b5189f83ed
    integration_test.go:223: DELETE test.foo.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=2c6404ff7f1c5f68f77109b6a566987e
=== RUN   TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#29
    integration_test.go:223: DELETE bar.dnscontroltest-cf.com A 1.2.3.4 ttl=1 proxy=off id=7c5f61f2eaa4d7cc23cb039eb32377d6
--- PASS: TestDNSProviders (323.69s)
    --- PASS: TestDNSProviders/dnscontroltest-cf.com (322.39s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Clean_Slate:Empty (0.90s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/00:A:Create_A (1.83s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/00:A:Change_A_target (2.06s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty (1.07s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/01:MX:Create_MX (1.87s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/01:MX:Change_MX_target (1.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/01:MX:Change_MX_p (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#01 (0.97s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/02:CNAME:Create_a_CNAME (1.86s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/02:CNAME:Change_CNAME_target (1.77s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#02 (1.00s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:CreateManyAtLabel (2.41s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:Empty (1.49s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:Create_an_A_record (1.90s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:Add_at_label1 (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/03:ManyAtOne:Add_at_label2 (1.77s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#03 (1.48s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:CreateManyTypesAtLabel (2.47s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:Empty (1.49s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:Create_an_A_record (1.94s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:Add_Type_At_Label (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/04:manyAtOneTypes:Add_Type_At_Label#01 (1.77s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#04 (1.53s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/05:Apex:Create_A (1.82s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/05:Apex:Change_A_target (1.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#05 (1.02s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/06:TTL:Start (2.29s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/06:TTL:Change_a_ttl (1.82s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/06:TTL:Change_single_target_from_set (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/06:TTL:Change_all_ttls (2.34s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#06 (1.47s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/07:add_to_label_and_change_orig_ttl:Setup (1.83s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/07:add_to_label_and_change_orig_ttl:Add_at_same_label,_new_ttl (2.27s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#07 (1.25s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/08:Protocol-Wildcard:Create_wildcard (2.17s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/08:Protocol-Wildcard:Delete_wildcard (1.81s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#08 (0.92s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/09:TypeChange:Create_a_CNAME (1.86s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/09:TypeChange:Change_to_A_record (2.02s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/09:TypeChange:Change_back_to_CNAME (2.07s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#09 (0.99s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/10:CommonDNS:Create_1_of_each (2.35s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/10:CommonDNS:Change_param1 (2.36s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/10:CommonDNS:Change_param2 (1.75s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#10 (1.51s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/11:CNAME:Record_pointing_to_@ (1.96s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#11 (0.98s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/12:MX:Record_pointing_to_@ (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/12:MX:Null_MX (2.04s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#12 (0.99s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/13:NS:NS_for_subdomain (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/13:NS:Dual_NS_for_subdomain (1.82s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/13:NS:NS_Record_pointing_to_@ (2.87s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#13 (1.24s)
        --- SKIP: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_0-octel_string (0.00s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_255-byte_TXT (1.90s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_256-byte_TXT (1.99s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_512-byte_TXT (2.07s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_513-byte_TXT (2.05s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_1_single-quote (2.13s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_1_backtick (2.08s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_1_double-quotes (2.00s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_2_double-quotes (2.07s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:a_TXT_with_interior_ws (3.39s)
        --- SKIP: TestDNSProviders/dnscontroltest-cf.com/14:complex_TXT:TXT_with_ws_at_end (0.00s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#14 (0.95s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/15:Case_Sensitivity:Create_CAPS (1.85s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/15:Case_Sensitivity:Downcase_label (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/15:Case_Sensitivity:Downcase_target (1.81s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/15:Case_Sensitivity:Upcase_both (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#15 (1.22s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/16:IDNA:Internationalized_name (1.87s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/16:IDNA:Change_IDN (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/16:IDNA:Internationalized_CNAME_Target (2.02s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#16 (1.01s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/17:IDNAs_in_CNAME_targets_***SKIPPED(excluded_by_not("CLOUDFLAREAPI"))***:Empty (0.81s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/18:pager101_***SKIPPED(excluded_by_not("CLOUDFLAREAPI"))***:Empty (0.97s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/19:pager601_***SKIPPED(disabled_by_only)***:Empty (0.77s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/20:pager1201_***SKIPPED(disabled_by_only)***:Empty (0.74s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/21:NS1_URLFWD_tests_***SKIPPED(disabled_by_only)***:Empty (0.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_record (2.05s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_change_tag (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_change_target (1.77s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_change_flag (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_many_records (1.84s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/22:CAA:CAA_whitespace (1.77s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#17 (1.00s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/23:NAPTR_***SKIPPED(CanUseNAPTR_not_supported)***:Empty (0.79s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/24:PTR:Create_PTR_record (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/24:PTR:Modify_PTR_record (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#18 (4.79s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/25:SOA_***SKIPPED(CanUseSOA_not_supported)***:Empty (0.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:SRV_record (1.77s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:Second_SRV_record,_same_prio (1.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:3_SRV (1.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:Delete_one (1.75s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:Change_Target (1.85s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:Change_Priority (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:Change_Weight (1.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:Change_Port (1.83s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:Empty (5.64s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/26:SRV:Null_Target (1.75s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#19 (1.09s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/27:SSHFP:SSHFP_record (1.81s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/27:SSHFP:SSHFP_change_algorithm (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/27:SSHFP:SSHFP_change_fingerprint_and_type (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#20 (0.95s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_record (1.96s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_change_usage (1.75s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_change_selector (1.81s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_change_matchingtype (1.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/28:TLSA:TLSA_change_certificate (1.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#21 (1.00s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/29:DS_***SKIPPED(CanUseDS_not_supported)***:Empty (0.92s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/30:DS_(children_only)_***SKIPPED(excluded_by_not("CLOUDFLAREAPI"))***:Empty (0.79s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:create_DS (2.26s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:modify_field_1 (2.17s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:modify_field_3 (2.01s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:modify_field_2+3 (2.08s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:modify_field_2 (2.02s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:delete_1,_create_1 (2.76s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/31:DS_(children_only)_CLOUDNS:add_2_more_DS (2.52s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#22 (1.70s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/32:ALIAS:ALIAS_at_root (1.89s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/32:ALIAS:change_it (1.83s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/32:ALIAS:ALIAS_at_subdomain (2.05s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/32:ALIAS:change_it#01 (1.81s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#23 (1.10s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/33:AZURE_ALIAS_***SKIPPED(CanUseAzureAlias_not_supported)***:Empty (0.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/34:R53_ALIAS2_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.87s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/35:R53_ALIAS_ORDER_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.74s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/36:R53_ALIAS_CNAME_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.75s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:redir (1.91s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:change (2.28s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:changelabel (2.21s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:Empty (1.00s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempredir (1.89s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempchange (2.07s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempchangelabel (2.16s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:Empty#01 (0.99s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempmultipleA (2.23s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:Empty#02 (1.31s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempmultipleB (2.29s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempchange1 (2.01s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/37:CF_REDIRECT:tempchange1#01 (2.10s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#24 (1.26s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxyon (2.04s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxychangetarget (1.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxychangeonoff (1.85s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxychangeoffon (1.74s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:Empty (1.12s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxycname (1.98s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxycnamechange (1.83s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxycnameoffon (1.81s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:proxycnameonoff (1.80s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/38:CF_PROXY:Empty#01 (0.94s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#25 (0.86s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:simple (1.88s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:changeScript (2.05s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:changePattern (2.04s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:Empty (1.10s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:createMultiple (2.12s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:addOne (1.83s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:changeOne (2.13s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/39:CF_WORKER_ROUTE:deleteOne (1.78s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#26 (1.42s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Create_some_records (2.08s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Add_a_new_record_-_ignoring_foo (4.65s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Empty (1.02s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Create_some_records#01 (4.26s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/40:IGNORE_NAME_function:Add_a_new_record_-_ignoring_*.foo (2.40s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#27 (0.97s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/41:IGNORE_NAME_apex:Create_some_records (6.97s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/41:IGNORE_NAME_apex:Add_a_new_record_-_ignoring_apex (2.29s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#28 (1.51s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Create_some_records (2.04s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Add_a_new_record_-_ignoring_test.foo.com. (2.23s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Empty (1.00s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Create_some_records#01 (2.04s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/42:IGNORE_TARGET_function:Add_a_new_record_-_ignoring_**.foo.com._targets (2.29s)
        --- PASS: TestDNSProviders/dnscontroltest-cf.com/Post_cleanup:Empty#29 (0.98s)
=== RUN   TestDualProviders
    integration_test.go:315: Skipping.  DocDualHost == Cannot
--- SKIP: TestDualProviders (1.22s)
PASS
ok  	github.com/StackExchange/dnscontrol/v3/integrationTest	325.232s

real	5m27.122s
user	0m3.010s
sys	0m2.674s
```

Patch:
diff --git a/pkg/diff2/analyze.go b/pkg/diff2/analyze.go
index 721f6bac..6c142e7f 100644
--- a/pkg/diff2/analyze.go
+++ b/pkg/diff2/analyze.go
@@ -204,10 +204,11 @@ func splitTTLOnly(existing, desired []targetConfig) (
 	for (ei < len(existing)) && (di < len(desired)) {
 		er := existing[ei].rec
 		dr := desired[di].rec
-		ecomp := er.GetTargetCombined()
-		dcomp := dr.GetTargetCombined()
+		ecomp := existing[ei].compareable
+		dcomp := desired[di].compareable
 
 		if ecomp == dcomp && er.TTL == dr.TTL {
+			fmt.Printf("DEBUG: ecomp=%q dcomp=%q er.TTL=%v dr.TTL=%v\n", ecomp, dcomp, er.TTL, dr.TTL)
 			panic("Should not happen. There should be some difference!")
 		}
 
@@ -270,20 +271,22 @@ func filterBy(s []targetConfig, m map[string]*targetConfig) []targetConfig {
 	return s
 }
 
-func humanDiff(a, b *models.RecordConfig) string {
-	acombined := a.GetTargetCombined()
-	bcombined := b.GetTargetCombined()
+func humanDiff(a, b targetConfig) string {
+	aTTL := a.rec.TTL
+	bTTL := b.rec.TTL
+	acombined := a.compareable
+	bcombined := b.compareable
 	combinedDiff := acombined != bcombined
-	ttlDiff := a.TTL != b.TTL
-	// TODO(tlim): It would be nice if we included special cases for MX
-	// records and others.
+	ttlDiff := aTTL != bTTL
+	// TODO(tlim): Records like MX and SRV should have more clever output.
+	// For example if only the MX priority changes, show that.
 	if combinedDiff && ttlDiff {
-		return fmt.Sprintf("(%s ttl=%d) -> (%s ttl=%d)", acombined, a.TTL, bcombined, b.TTL)
+		return fmt.Sprintf("(%s ttl=%d) -> (%s ttl=%d)", acombined, aTTL, bcombined, bTTL)
 	}
 	if combinedDiff {
 		return fmt.Sprintf("(%s) -> (%s)", acombined, bcombined)
 	}
-	return fmt.Sprintf("%s (ttl %d->%d)", acombined, a.TTL, b.TTL)
+	return fmt.Sprintf("%s (ttl %d->%d)", acombined, aTTL, bTTL)
 }
 
 func diffTargets(existing, desired []targetConfig) ChangeList {
@@ -302,7 +305,11 @@ func diffTargets(existing, desired []targetConfig) ChangeList {
 	var instructions ChangeList
 
 	// remove the exact matches.
+	//fmt.Printf("DEBUG: diffTargets BEFORE existing=%+v\n", existing)
+	//fmt.Printf("DEBUG: diffTargets BEFORE desired=%+v\n", desired)
 	existing, desired = removeCommon(existing, desired)
+	//fmt.Printf("DEBUG: diffTargets AFTER existing=%+v\n", existing)
+	//fmt.Printf("DEBUG: diffTargets AFTER desired=%+v\n", desired)
 
 	// At this point the exact matches are removed. However there may be
 	// records that have the same GetTargetCombined() but different
@@ -314,7 +321,7 @@ func diffTargets(existing, desired []targetConfig) ChangeList {
 		er := existingTTL[i]
 		dr := desiredTTL[i]
 
-		m := fmt.Sprintf("CHANGE %s %s ", dr.NameFQDN, dr.Type) + humanDiff(er, dr)
+		m := fmt.Sprintf("CHANGE %s %s ", dr.NameFQDN, dr.Type) + humanDiff(existing[i], desired[i])
 
 		instructions = append(instructions, mkChange(dr.NameFQDN, dr.Type, []string{m},
 			models.Records{er},
@@ -330,7 +337,7 @@ func diffTargets(existing, desired []targetConfig) ChangeList {
 		er := existing[i].rec
 		dr := desired[i].rec
 
-		m := fmt.Sprintf("CHANGE %s %s ", dr.NameFQDN, dr.Type) + humanDiff(existing[i].rec, desired[i].rec)
+		m := fmt.Sprintf("CHANGE %s %s ", dr.NameFQDN, dr.Type) + humanDiff(existing[i], desired[i])
 
 		instructions = append(instructions, mkChange(dr.NameFQDN, dr.Type, []string{m},
 			models.Records{er},
@@ -342,7 +349,7 @@ func diffTargets(existing, desired []targetConfig) ChangeList {
 	for i := mi; i < len(existing); i++ {
 		//fmt.Println(i, "DEL")
 		er := existing[i].rec
-		m := fmt.Sprintf("DELETE %s %s %s", er.NameFQDN, er.Type, er.GetTargetCombined())
+		m := fmt.Sprintf("DELETE %s %s %s", er.NameFQDN, er.Type, existing[i].compareable)
 		instructions = append(instructions, mkDeleteRec(er.NameFQDN, er.Type, []string{m}, er))
 	}
 
@@ -350,7 +357,7 @@ func diffTargets(existing, desired []targetConfig) ChangeList {
 	for i := mi; i < len(desired); i++ {
 		//fmt.Println(i, "CREATE")
 		dr := desired[i].rec
-		m := fmt.Sprintf("CREATE %s %s %s", dr.NameFQDN, dr.Type, dr.GetTargetCombined())
+		m := fmt.Sprintf("CREATE %s %s %s", dr.NameFQDN, dr.Type, desired[i].compareable)
 		instructions = append(instructions, mkAdd(dr.NameFQDN, dr.Type, []string{m}, models.Records{dr}))
 	}
 
diff --git a/pkg/diff2/compareconfig.go b/pkg/diff2/compareconfig.go
index 3835d973..fc381d6e 100644
--- a/pkg/diff2/compareconfig.go
+++ b/pkg/diff2/compareconfig.go
@@ -191,11 +191,15 @@ func (cc *CompareConfig) String() string {
 
 // Generate a string that can be used to compare this record to others
 // for equality.
-func comparable(rc *models.RecordConfig, f func(*models.RecordConfig) string) string {
+func mkCompareBlob(rc *models.RecordConfig, f func(*models.RecordConfig) string) string {
 	if f == nil {
 		return rc.ToDiffable()
 	}
-	return rc.ToDiffable() + " " + f(rc)
+	addOn := f(rc)
+	if addOn != "" {
+		return rc.ToDiffable() + " " + f(rc)
+	}
+	return rc.ToDiffable()
 }
 
 func (cc *CompareConfig) addRecords(recs models.Records, storeInExisting bool) {
@@ -213,7 +217,7 @@ func (cc *CompareConfig) addRecords(recs models.Records, storeInExisting bool) {
 
 		label := rec.NameFQDN
 		rtype := rec.Type
-		comp := comparable(rec, cc.compareableFunc)
+		comp := mkCompareBlob(rec, cc.compareableFunc)
 
 		// Are we seeing this label for the first time?
 		var labelIdx int
diff --git a/providers/cloudflare/cloudflareProvider.go b/providers/cloudflare/cloudflareProvider.go
index 40059932..3f3458a0 100644
--- a/providers/cloudflare/cloudflareProvider.go
+++ b/providers/cloudflare/cloudflareProvider.go
@@ -154,11 +154,11 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 		return nil, err
 	}
 
-	id, err := c.getDomainID(dc.Name)
+	domainID, err := c.getDomainID(dc.Name)
 	if err != nil {
 		return nil, err
 	}
-	records, err := c.getRecordsForDomain(id, dc.Name)
+	records, err := c.getRecordsForDomain(domainID, dc.Name)
 	if err != nil {
 		return nil, err
 	}
@@ -176,7 +176,7 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 	}
 
 	if c.manageRedirects {
-		prs, err := c.getPageRules(id, dc.Name)
+		prs, err := c.getPageRules(domainID, dc.Name)
 		//printer.Printf("GET PAGE RULES:\n")
 		//for i, p := range prs {
 		//	printer.Printf("%03d: %q\n", i, p.GetTargetField())
@@ -188,7 +188,7 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 	}
 
 	if c.manageWorkers {
-		wrs, err := c.getWorkerRoutes(id, dc.Name)
+		wrs, err := c.getWorkerRoutes(domainID, dc.Name)
 		if err != nil {
 			return nil, err
 		}
@@ -224,7 +224,7 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 	// one string in the first element of .TxtStrings.
 
 	var corrections []*models.Correction
-	if !diff2.EnableDiff2 || true { // Remove "|| true" when diff2 version arrives
+	if !diff2.EnableDiff2 {
 
 		differ := diff.New(dc, getProxyMetadata)
 		_, create, del, mod, err := differ.IncrementalDiff(records)
@@ -239,15 +239,15 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 			if ex.Type == "PAGE_RULE" {
 				corrections = append(corrections, &models.Correction{
 					Msg: d.String(),
-					F:   func() error { return c.deletePageRule(ex.Original.(cloudflare.PageRule).ID, id) },
+					F:   func() error { return c.deletePageRule(ex.Original.(cloudflare.PageRule).ID, domainID) },
 				})
 			} else if ex.Type == "WORKER_ROUTE" {
 				corrections = append(corrections, &models.Correction{
 					Msg: d.String(),
-					F:   func() error { return c.deleteWorkerRoute(ex.Original.(cloudflare.WorkerRoute).ID, id) },
+					F:   func() error { return c.deleteWorkerRoute(ex.Original.(cloudflare.WorkerRoute).ID, domainID) },
 				})
 			} else {
-				corr := c.deleteRec(ex.Original.(cloudflare.DNSRecord), id)
+				corr := c.deleteRec(ex.Original.(cloudflare.DNSRecord), domainID)
 				// DS records must always have a corresponding NS record.
 				// Therefore, we remove DS records before any NS records.
 				if d.Existing.Type == "DS" {
@@ -262,15 +262,15 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 			if des.Type == "PAGE_RULE" {
 				corrections = append(corrections, &models.Correction{
 					Msg: d.String(),
-					F:   func() error { return c.createPageRule(id, des.GetTargetField()) },
+					F:   func() error { return c.createPageRule(domainID, des.GetTargetField()) },
 				})
 			} else if des.Type == "WORKER_ROUTE" {
 				corrections = append(corrections, &models.Correction{
 					Msg: d.String(),
-					F:   func() error { return c.createWorkerRoute(id, des.GetTargetField()) },
+					F:   func() error { return c.createWorkerRoute(domainID, des.GetTargetField()) },
 				})
 			} else {
-				corr := c.createRec(des, id)
+				corr := c.createRec(des, domainID)
 				// DS records must always have a corresponding NS record.
 				// Therefore, we create NS records before any DS records.
 				if d.Desired.Type == "NS" {
@@ -287,13 +287,15 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 			if rec.Type == "PAGE_RULE" {
 				corrections = append(corrections, &models.Correction{
 					Msg: d.String(),
-					F:   func() error { return c.updatePageRule(ex.Original.(cloudflare.PageRule).ID, id, rec.GetTargetField()) },
+					F: func() error {
+						return c.updatePageRule(ex.Original.(cloudflare.PageRule).ID, domainID, rec.GetTargetField())
+					},
 				})
 			} else if rec.Type == "WORKER_ROUTE" {
 				corrections = append(corrections, &models.Correction{
 					Msg: d.String(),
 					F: func() error {
-						return c.updateWorkerRoute(ex.Original.(cloudflare.WorkerRoute).ID, id, rec.GetTargetField())
+						return c.updateWorkerRoute(ex.Original.(cloudflare.WorkerRoute).ID, domainID, rec.GetTargetField())
 					},
 				})
 			} else {
@@ -301,13 +303,13 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 				proxy := e.Proxiable && rec.Metadata[metaProxy] != "off"
 				corrections = append(corrections, &models.Correction{
 					Msg: d.String(),
-					F:   func() error { return c.modifyRecord(id, e.ID, proxy, rec) },
+					F:   func() error { return c.modifyRecord(domainID, e.ID, proxy, rec) },
 				})
 			}
 		}
 
 		// Add universalSSL change to corrections when needed
-		if changed, newState, err := c.checkUniversalSSL(dc, id); err == nil && changed {
+		if changed, newState, err := c.checkUniversalSSL(dc, domainID); err == nil && changed {
 			var newStateString string
 			if newState {
 				newStateString = "enabled"
@@ -316,17 +318,154 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
 			}
 			corrections = append(corrections, &models.Correction{
 				Msg: fmt.Sprintf("Universal SSL will be %s for this domain.", newStateString),
-				F:   func() error { return c.changeUniversalSSL(id, newState) },
+				F:   func() error { return c.changeUniversalSSL(domainID, newState) },
 			})
 		}
 
 		return corrections, nil
 	}
 
-	// Insert Future diff2 version here.
+	// Cloudflare is a "ByRecord" API.
+	instructions, err := diff2.ByRecord(records, dc, genComparable)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, inst := range instructions {
+
+		addToFront := false
+		var corrs []*models.Correction
+
+		domainID := domainID
+		msg := inst.Msgs[0]
+
+		switch inst.Type {
+		case diff2.CREATE:
+			createRec := inst.New[0]
+			corrs = c.mkCreateCorrection(createRec, domainID, msg)
+			// DS records must always have a corresponding NS record.
+			// Therefore, we create NS records before any DS records.
+			addToFront = createRec.Type == "NS"
+		case diff2.CHANGE:
+			newrec := inst.New[0]
+			oldrec := inst.Old[0]
+			corrs = c.mkChangeCorrection(oldrec, newrec, domainID, msg)
+		case diff2.DELETE:
+			deleteRec := inst.Old[0]
+			deleteRecType := deleteRec.Type
+			deleteRecOrig := deleteRec.Original
+			corrs = c.mkDeleteCorrection(deleteRecType, deleteRecOrig, domainID, msg)
+			// DS records must always have a corresponding NS record.
+			// Therefore, we remove DS records before any NS records.
+			addToFront = deleteRecType == "DS"
+		}
+
+		if addToFront {
+			corrections = append(corrs, corrections...)
+		} else {
+			corrections = append(corrections, corrs...)
+		}
+	}
+
+	// Add universalSSL change when needed
+	if changed, newState, err := c.checkUniversalSSL(dc, domainID); err == nil && changed {
+		var newStateString string
+		if newState {
+			newStateString = "enabled"
+		} else {
+			newStateString = "disabled"
+		}
+		corrections = append(corrections, &models.Correction{
+			Msg: fmt.Sprintf("Universal SSL will be %s for this domain.", newStateString),
+			F:   func() error { return c.changeUniversalSSL(domainID, newState) },
+		})
+	}
 
 	return corrections, nil
+}
+
+func genComparable(rec *models.RecordConfig) string {
+	//fmt.Printf("DEBUG: genComparable called %v:%v meta=%+v\n", rec.Type, rec.GetLabel(), rec.Metadata)
+	if rec.Type == "A" || rec.Type == "AAAA" || rec.Type == "CNAME" {
+		proxy := rec.Metadata[metaProxy]
+		if proxy != "" {
+			//return "proxy=" + rec.Metadata[metaProxy]
+			return "proxy=" + proxy
+			//return fmt.Sprintf("proxy:%v=%s", rec.Type, proxy)
+		}
+	}
+	return ""
+}
 
+func (c *cloudflareProvider) mkCreateCorrection(newrec *models.RecordConfig, domainID, msg string) []*models.Correction {
+	switch newrec.Type {
+	case "PAGE_RULE":
+		return []*models.Correction{{
+			Msg: msg,
+			F:   func() error { return c.createPageRule(domainID, newrec.GetTargetField()) },
+		}}
+	case "WORKER_ROUTE":
+		return []*models.Correction{{
+			Msg: msg,
+			F:   func() error { return c.createWorkerRoute(domainID, newrec.GetTargetField()) },
+		}}
+	default:
+		return c.createRecDiff2(newrec, domainID, msg)
+	}
+}
+
+func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordConfig, domainID string, msg string) []*models.Correction {
+	switch newrec.Type {
+	case "PAGE_RULE":
+		return []*models.Correction{{
+			Msg: msg,
+			F: func() error {
+				return c.updatePageRule(oldrec.Original.(cloudflare.PageRule).ID, domainID, newrec.GetTargetField())
+			},
+		}}
+	case "WORKER_ROUTE":
+		return []*models.Correction{{
+			Msg: msg,
+			F: func() error {
+				return c.updateWorkerRoute(oldrec.Original.(cloudflare.WorkerRoute).ID, domainID, newrec.GetTargetField())
+			},
+		}}
+	default:
+		e := oldrec.Original.(cloudflare.DNSRecord)
+		proxy := e.Proxiable && newrec.Metadata[metaProxy] != "off"
+		return []*models.Correction{{
+			Msg: msg,
+			F:   func() error { return c.modifyRecord(domainID, e.ID, proxy, newrec) },
+		}}
+	}
+}
+
+func (c *cloudflareProvider) mkDeleteCorrection(recType string, origRec any, domainID string, msg string) []*models.Correction {
+	var idTxt string
+	switch recType {
+	case "PAGE_RULE":
+		idTxt = origRec.(cloudflare.PageRule).ID
+	case "WORKER_ROUTE":
+		idTxt = origRec.(cloudflare.WorkerRoute).ID
+	default:
+		idTxt = origRec.(cloudflare.DNSRecord).ID
+	}
+	msg = msg + fmt.Sprintf(" id=%v", idTxt)
+
+	correction := &models.Correction{
+		Msg: msg,
+		F: func() error {
+			switch recType {
+			case "PAGE_RULE":
+				return c.deletePageRule(origRec.(cloudflare.PageRule).ID, domainID)
+			case "WORKER_ROUTE":
+				return c.deleteWorkerRoute(origRec.(cloudflare.WorkerRoute).ID, domainID)
+			default:
+				return c.deleteDNSRecord(origRec.(cloudflare.DNSRecord), domainID)
+			}
+		},
+	}
+	return []*models.Correction{correction}
 }
 
 func checkNSModifications(dc *models.DomainConfig) {
@@ -669,6 +808,7 @@ func (c *cloudflareProvider) nativeToRecord(domain string, cr cloudflare.DNSReco
 	rc := &models.RecordConfig{
 		TTL:      uint32(cr.TTL),
 		Original: cr,
+		Metadata: map[string]string{},
 	}
 	rc.SetLabelFromFQDN(cr.Name, domain)
 
@@ -677,6 +817,16 @@ func (c *cloudflareProvider) nativeToRecord(domain string, cr cloudflare.DNSReco
 		cr.Type = "TXT"
 	}
 
+	if cr.Type == "A" || cr.Type == "AAAA" || cr.Type == "CNAME" {
+		if cr.Proxied != nil {
+			if *(cr.Proxied) {
+				rc.Metadata[metaProxy] = "on"
+			} else {
+				rc.Metadata[metaProxy] = "off"
+			}
+		}
+	}
+
 	switch rType := cr.Type; rType { // #rtype_variations
 	case "MX":
 		if err := rc.SetTargetMX(*cr.Priority, cr.Content); err != nil {
diff --git a/providers/cloudflare/rest.go b/providers/cloudflare/rest.go
index 8c0bfdf3..08f642fb 100644
--- a/providers/cloudflare/rest.go
+++ b/providers/cloudflare/rest.go
@@ -44,6 +44,10 @@ func (c *cloudflareProvider) getRecordsForDomain(id string, domain string) ([]*m
 	return records, nil
 }
 
+func (c *cloudflareProvider) deleteDNSRecord(rec cloudflare.DNSRecord, domainID string) error {
+	return c.cfClient.DeleteDNSRecord(context.Background(), domainID, rec.ID)
+}
+
 // create a correction to delete a record
 func (c *cloudflareProvider) deleteRec(rec cloudflare.DNSRecord, domainID string) *models.Correction {
 	return &models.Correction{
@@ -168,6 +172,70 @@ func (c *cloudflareProvider) createRec(rec *models.RecordConfig, domainID string
 	return arr
 }
 
+func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID string, msg string) []*models.Correction {
+
+	content := rec.GetTargetField()
+	if rec.Metadata[metaOriginalIP] != "" {
+		content = rec.Metadata[metaOriginalIP]
+	}
+	prio := ""
+	if rec.Type == "MX" {
+		prio = fmt.Sprintf(" %d ", rec.MxPreference)
+	}
+	if rec.Type == "TXT" {
+		content = rec.GetTargetTXTJoined()
+	}
+	if rec.Type == "DS" {
+		content = fmt.Sprintf("%d %d %d %s", rec.DsKeyTag, rec.DsAlgorithm, rec.DsDigestType, rec.DsDigest)
+	}
+	if msg == "" {
+		msg = fmt.Sprintf("CREATE record: %s %s %d%s %s", rec.GetLabel(), rec.Type, rec.TTL, prio, content)
+	}
+	if rec.Metadata[metaProxy] == "on" {
+		msg = msg + fmt.Sprintf("\nACTIVATE PROXY for new record %s %s %d %s", rec.GetLabel(), rec.Type, rec.TTL, rec.GetTargetField())
+	}
+	arr := []*models.Correction{{
+		Msg: msg,
+		F: func() error {
+			cf := cloudflare.DNSRecord{
+				Name:     rec.GetLabel(),
+				Type:     rec.Type,
+				TTL:      int(rec.TTL),
+				Content:  content,
+				Priority: &rec.MxPreference,
+			}
+			if rec.Type == "SRV" {
+				cf.Data = cfSrvData(rec)
+				cf.Name = rec.GetLabelFQDN()
+			} else if rec.Type == "CAA" {
+				cf.Data = cfCaaData(rec)
+				cf.Name = rec.GetLabelFQDN()
+				cf.Content = ""
+			} else if rec.Type == "TLSA" {
+				cf.Data = cfTlsaData(rec)
+				cf.Name = rec.GetLabelFQDN()
+			} else if rec.Type == "SSHFP" {
+				cf.Data = cfSshfpData(rec)
+				cf.Name = rec.GetLabelFQDN()
+			} else if rec.Type == "DS" {
+				cf.Data = cfDSData(rec)
+			}
+			resp, err := c.cfClient.CreateDNSRecord(context.Background(), domainID, cf)
+			if err != nil {
+				return err
+			}
+			// Records are created with the proxy off. If proxy should be
+			// enabled, we do a second API call.
+			resultID := resp.Result.ID
+			if rec.Metadata[metaProxy] == "on" {
+				return c.modifyRecord(domainID, resultID, true, rec)
+			}
+			return nil
+		},
+	}}
+	return arr
+}
+
 func (c *cloudflareProvider) modifyRecord(domainID, recID string, proxied bool, rec *models.RecordConfig) error {
 	if domainID == "" || recID == "" {
 		return fmt.Errorf("cannot modify record if domain or record id are empty")


Test patch:
diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go
index dfccd6e9..119074b0 100644
--- a/integrationTest/integration_test.go
+++ b/integrationTest/integration_test.go
@@ -1300,10 +1300,13 @@ func makeTests(t *testing.T) []*TestGroup {
 			only("CLOUDFLAREAPI"),
 			tc("proxyon", cfProxyA("proxyme", "1.2.3.4", "on")),
 			tc("proxychangetarget", cfProxyA("proxyme", "1.2.3.5", "on")),
-			tc("proxychangeproxy", cfProxyA("proxyme", "1.2.3.5", "off")),
+			tc("proxychangeonoff", cfProxyA("proxyme", "1.2.3.5", "off")),
+			tc("proxychangeoffon", cfProxyA("proxyme", "1.2.3.5", "on")),
 			clear(),
 			tc("proxycname", cfProxyCNAME("anewproxy", "example.com.", "on")),
 			tc("proxycnamechange", cfProxyCNAME("anewproxy", "example.com.", "off")),
+			tc("proxycnameoffon", cfProxyCNAME("anewproxy", "example.com.", "on")),
+			tc("proxycnameonoff", cfProxyCNAME("anewproxy", "example.com.", "off")),
 			clear(),
 		),
 
diff --git a/pkg/diff2/analyze_test.go b/pkg/diff2/analyze_test.go
index b0992377..92dba0bd 100644
--- a/pkg/diff2/analyze_test.go
+++ b/pkg/diff2/analyze_test.go
@@ -116,14 +116,14 @@ func Test_analyzeByRecordSet(t *testing.T) {
 				existing: models.Records{testDataAA1234, testDataAMX10a},
 				desired:  models.Records{testDataAA1234clone, testDataAMX20b},
 			},
-			wantMsgs: "CHANGE laba.f.com MX (10 laba) -> (20 labb)",
+			wantMsgs: "CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)",
 			wantChangeRSet: `
 ChangeList: len=1
 00: Change: verb=CHANGE
     key={laba.f.com MX}
     old=[10 laba]
     new=[20 labb]
-    msg=["CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 `,
 			wantChangeLabel: `
 ChangeList: len=1
@@ -131,7 +131,7 @@ ChangeList: len=1
     key={laba.f.com }
     old=[1.2.3.4 10 laba]
     new=[1.2.3.4 20 labb]
-    msg=["CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 `,
 			wantChangeRec: `
 ChangeList: len=1
@@ -139,7 +139,7 @@ ChangeList: len=1
     key={laba.f.com MX}
     old=[10 laba]
     new=[20 labb]
-    msg=["CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 `,
 		},
 
@@ -150,14 +150,14 @@ ChangeList: len=1
 				existing: models.Records{testDataAA1234, testDataApexMX1aaa},
 				desired:  models.Records{testDataAA1234clone, testDataApexMX22bbb},
 			},
-			wantMsgs: "CHANGE f.com MX (1 aaa) -> (22 bbb)",
+			wantMsgs: "CHANGE f.com MX (1 aaa ttl=300) -> (22 bbb ttl=300)",
 			wantChangeRSet: `
 ChangeList: len=1
 00: Change: verb=CHANGE
     key={f.com MX}
     old=[1 aaa]
     new=[22 bbb]
-    msg=["CHANGE f.com MX (1 aaa) -> (22 bbb)"]
+    msg=["CHANGE f.com MX (1 aaa ttl=300) -> (22 bbb ttl=300)"]
 `,
 			wantChangeLabel: `
 ChangeList: len=1
@@ -165,7 +165,7 @@ ChangeList: len=1
     key={f.com }
     old=[1 aaa]
     new=[22 bbb]
-    msg=["CHANGE f.com MX (1 aaa) -> (22 bbb)"]
+    msg=["CHANGE f.com MX (1 aaa ttl=300) -> (22 bbb ttl=300)"]
 `,
 			wantChangeRec: `
 ChangeList: len=1
@@ -173,7 +173,7 @@ ChangeList: len=1
     key={f.com MX}
     old=[1 aaa]
     new=[22 bbb]
-    msg=["CHANGE f.com MX (1 aaa) -> (22 bbb)"]
+    msg=["CHANGE f.com MX (1 aaa ttl=300) -> (22 bbb ttl=300)"]
 `,
 		},
 
@@ -185,8 +185,8 @@ ChangeList: len=1
 				desired:  models.Records{testDataAA1234clone, testDataAA12345, testDataAMX20b},
 			},
 			wantMsgs: `
-CREATE laba.f.com A 1.2.3.5
-CHANGE laba.f.com MX (10 laba) -> (20 labb)
+CREATE laba.f.com A 1.2.3.5 ttl=300
+CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)
 		`,
 			wantChangeRSet: `
 ChangeList: len=2
@@ -194,12 +194,12 @@ ChangeList: len=2
     key={laba.f.com A}
     old=[1.2.3.4]
     new=[1.2.3.4 1.2.3.5]
-    msg=["CREATE laba.f.com A 1.2.3.5"]
+    msg=["CREATE laba.f.com A 1.2.3.5 ttl=300"]
 01: Change: verb=CHANGE
     key={laba.f.com MX}
     old=[10 laba]
     new=[20 labb]
-    msg=["CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 		`,
 			wantChangeLabel: `
 ChangeList: len=1
@@ -207,19 +207,19 @@ ChangeList: len=1
     key={laba.f.com }
     old=[1.2.3.4 10 laba]
     new=[1.2.3.4 1.2.3.5 20 labb]
-    msg=["CREATE laba.f.com A 1.2.3.5" "CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CREATE laba.f.com A 1.2.3.5 ttl=300" "CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 		`,
 			wantChangeRec: `
 ChangeList: len=2
 00: Change: verb=CREATE
     key={laba.f.com A}
     new=[1.2.3.5]
-    msg=["CREATE laba.f.com A 1.2.3.5"]
+    msg=["CREATE laba.f.com A 1.2.3.5 ttl=300"]
 01: Change: verb=CHANGE
     key={laba.f.com MX}
     old=[10 laba]
     new=[20 labb]
-    msg=["CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 `,
 		},
 
@@ -231,18 +231,18 @@ ChangeList: len=2
 				desired:  desired,
 			},
 			wantMsgs: `
-CREATE laba.f.com A 1.2.3.5
-CHANGE laba.f.com MX (10 laba) -> (20 labb)
-DELETE labc.f.com CNAME laba
-CHANGE labe.f.com A (10.10.10.15) -> (10.10.10.95)
-CHANGE labe.f.com A (10.10.10.16) -> (10.10.10.96)
-CHANGE labe.f.com A (10.10.10.17) -> (10.10.10.97)
-CHANGE labe.f.com A (10.10.10.18) -> (10.10.10.98)
-CREATE labf.f.com TXT "foo"
-CHANGE labg.f.com NS (10.10.10.17) -> (10.10.10.10)
-CHANGE labg.f.com NS (10.10.10.18) -> (10.10.10.97)
-DELETE labh.f.com CNAME labd
-CREATE labh.f.com A 1.2.3.4
+CREATE laba.f.com A 1.2.3.5 ttl=300
+CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)
+DELETE labc.f.com CNAME laba ttl=300
+CHANGE labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)
+CHANGE labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)
+CHANGE labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)
+CHANGE labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)
+CREATE labf.f.com TXT "foo" ttl=300
+CHANGE labg.f.com NS (10.10.10.17 ttl=300) -> (10.10.10.10 ttl=300)
+CHANGE labg.f.com NS (10.10.10.18 ttl=300) -> (10.10.10.97 ttl=300)
+DELETE labh.f.com CNAME labd ttl=300
+CREATE labh.f.com A 1.2.3.4 ttl=300
 		`,
 			wantChangeRSet: `
 ChangeList: len=8
@@ -250,38 +250,38 @@ ChangeList: len=8
     key={laba.f.com A}
     old=[1.2.3.4]
     new=[1.2.3.4 1.2.3.5]
-    msg=["CREATE laba.f.com A 1.2.3.5"]
+    msg=["CREATE laba.f.com A 1.2.3.5 ttl=300"]
 01: Change: verb=CHANGE
     key={laba.f.com MX}
     old=[10 laba]
     new=[20 labb]
-    msg=["CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 02: Change: verb=DELETE
     key={labc.f.com CNAME}
     old=[laba]
-    msg=["DELETE labc.f.com CNAME laba"]
+    msg=["DELETE labc.f.com CNAME laba ttl=300"]
 03: Change: verb=CHANGE
     key={labe.f.com A}
     old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18]
     new=[10.10.10.95 10.10.10.96 10.10.10.97 10.10.10.98]
-    msg=["CHANGE labe.f.com A (10.10.10.15) -> (10.10.10.95)" "CHANGE labe.f.com A (10.10.10.16) -> (10.10.10.96)" "CHANGE labe.f.com A (10.10.10.17) -> (10.10.10.97)" "CHANGE labe.f.com A (10.10.10.18) -> (10.10.10.98)"]
+    msg=["CHANGE labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)" "CHANGE labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)" "CHANGE labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)" "CHANGE labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"]
 04: Change: verb=CREATE
     key={labf.f.com TXT}
     new=["foo"]
-    msg=["CREATE labf.f.com TXT \"foo\""]
+    msg=["CREATE labf.f.com TXT \"foo\" ttl=300"]
 05: Change: verb=CHANGE
     key={labg.f.com NS}
     old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18]
     new=[10.10.10.10 10.10.10.15 10.10.10.16 10.10.10.97]
-    msg=["CHANGE labg.f.com NS (10.10.10.17) -> (10.10.10.10)" "CHANGE labg.f.com NS (10.10.10.18) -> (10.10.10.97)"]
+    msg=["CHANGE labg.f.com NS (10.10.10.17 ttl=300) -> (10.10.10.10 ttl=300)" "CHANGE labg.f.com NS (10.10.10.18 ttl=300) -> (10.10.10.97 ttl=300)"]
 06: Change: verb=DELETE
     key={labh.f.com CNAME}
     old=[labd]
-    msg=["DELETE labh.f.com CNAME labd"]
+    msg=["DELETE labh.f.com CNAME labd ttl=300"]
 07: Change: verb=CREATE
     key={labh.f.com A}
     new=[1.2.3.4]
-    msg=["CREATE labh.f.com A 1.2.3.4"]
+    msg=["CREATE labh.f.com A 1.2.3.4 ttl=300"]
 		`,
 			wantChangeLabel: `
 ChangeList: len=6
@@ -289,88 +289,88 @@ ChangeList: len=6
     key={laba.f.com }
     old=[1.2.3.4 10 laba]
     new=[1.2.3.4 1.2.3.5 20 labb]
-    msg=["CREATE laba.f.com A 1.2.3.5" "CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CREATE laba.f.com A 1.2.3.5 ttl=300" "CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 01: Change: verb=DELETE
     key={labc.f.com }
     old=[laba]
-    msg=["DELETE labc.f.com CNAME laba"]
+    msg=["DELETE labc.f.com CNAME laba ttl=300"]
 02: Change: verb=CHANGE
     key={labe.f.com }
     old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18]
     new=[10.10.10.95 10.10.10.96 10.10.10.97 10.10.10.98]
-    msg=["CHANGE labe.f.com A (10.10.10.15) -> (10.10.10.95)" "CHANGE labe.f.com A (10.10.10.16) -> (10.10.10.96)" "CHANGE labe.f.com A (10.10.10.17) -> (10.10.10.97)" "CHANGE labe.f.com A (10.10.10.18) -> (10.10.10.98)"]
+    msg=["CHANGE labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)" "CHANGE labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)" "CHANGE labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)" "CHANGE labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"]
 03: Change: verb=CREATE
     key={labf.f.com }
     new=["foo"]
-    msg=["CREATE labf.f.com TXT \"foo\""]
+    msg=["CREATE labf.f.com TXT \"foo\" ttl=300"]
 04: Change: verb=CHANGE
     key={labg.f.com }
     old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18]
     new=[10.10.10.10 10.10.10.15 10.10.10.16 10.10.10.97]
-    msg=["CHANGE labg.f.com NS (10.10.10.17) -> (10.10.10.10)" "CHANGE labg.f.com NS (10.10.10.18) -> (10.10.10.97)"]
+    msg=["CHANGE labg.f.com NS (10.10.10.17 ttl=300) -> (10.10.10.10 ttl=300)" "CHANGE labg.f.com NS (10.10.10.18 ttl=300) -> (10.10.10.97 ttl=300)"]
 05: Change: verb=CHANGE
     key={labh.f.com }
     old=[labd]
     new=[1.2.3.4]
-    msg=["DELETE labh.f.com CNAME labd" "CREATE labh.f.com A 1.2.3.4"]
+    msg=["DELETE labh.f.com CNAME labd ttl=300" "CREATE labh.f.com A 1.2.3.4 ttl=300"]
 		`,
 			wantChangeRec: `
 ChangeList: len=12
 00: Change: verb=CREATE
     key={laba.f.com A}
     new=[1.2.3.5]
-    msg=["CREATE laba.f.com A 1.2.3.5"]
+    msg=["CREATE laba.f.com A 1.2.3.5 ttl=300"]
 01: Change: verb=CHANGE
     key={laba.f.com MX}
     old=[10 laba]
     new=[20 labb]
-    msg=["CHANGE laba.f.com MX (10 laba) -> (20 labb)"]
+    msg=["CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"]
 02: Change: verb=DELETE
     key={labc.f.com CNAME}
     old=[laba]
-    msg=["DELETE labc.f.com CNAME laba"]
+    msg=["DELETE labc.f.com CNAME laba ttl=300"]
 03: Change: verb=CHANGE
     key={labe.f.com A}
     old=[10.10.10.15]
     new=[10.10.10.95]
-    msg=["CHANGE labe.f.com A (10.10.10.15) -> (10.10.10.95)"]
+    msg=["CHANGE labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)"]
 04: Change: verb=CHANGE
     key={labe.f.com A}
     old=[10.10.10.16]
     new=[10.10.10.96]
-    msg=["CHANGE labe.f.com A (10.10.10.16) -> (10.10.10.96)"]
+    msg=["CHANGE labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)"]
 05: Change: verb=CHANGE
     key={labe.f.com A}
     old=[10.10.10.17]
     new=[10.10.10.97]
-    msg=["CHANGE labe.f.com A (10.10.10.17) -> (10.10.10.97)"]
+    msg=["CHANGE labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)"]
 06: Change: verb=CHANGE
     key={labe.f.com A}
     old=[10.10.10.18]
     new=[10.10.10.98]
-    msg=["CHANGE labe.f.com A (10.10.10.18) -> (10.10.10.98)"]
+    msg=["CHANGE labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"]
 07: Change: verb=CREATE
     key={labf.f.com TXT}
     new=["foo"]
-    msg=["CREATE labf.f.com TXT \"foo\""]
+    msg=["CREATE labf.f.com TXT \"foo\" ttl=300"]
 08: Change: verb=CHANGE
     key={labg.f.com NS}
     old=[10.10.10.17]
     new=[10.10.10.10]
-    msg=["CHANGE labg.f.com NS (10.10.10.17) -> (10.10.10.10)"]
+    msg=["CHANGE labg.f.com NS (10.10.10.17 ttl=300) -> (10.10.10.10 ttl=300)"]
 09: Change: verb=CHANGE
     key={labg.f.com NS}
     old=[10.10.10.18]
     new=[10.10.10.97]
-    msg=["CHANGE labg.f.com NS (10.10.10.18) -> (10.10.10.97)"]
+    msg=["CHANGE labg.f.com NS (10.10.10.18 ttl=300) -> (10.10.10.97 ttl=300)"]
 10: Change: verb=DELETE
     key={labh.f.com CNAME}
     old=[labd]
-    msg=["DELETE labh.f.com CNAME labd"]
+    msg=["DELETE labh.f.com CNAME labd ttl=300"]
 11: Change: verb=CREATE
     key={labh.f.com A}
     new=[1.2.3.4]
-    msg=["CREATE labh.f.com A 1.2.3.4"]
+    msg=["CREATE labh.f.com A 1.2.3.4 ttl=300"]
 `,
 		},
 	}
@@ -407,7 +407,7 @@ func mkTargetConfig(x ...*models.RecordConfig) []targetConfig {
 	var tc []targetConfig
 	for _, r := range x {
 		tc = append(tc, targetConfig{
-			compareable: comparable(r, nil),
+			compareable: mkCompareBlob(r, nil),
 			rec:         r,
 		})
 	}
@@ -445,8 +445,8 @@ func Test_diffTargets(t *testing.T) {
 					Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "A"},
 					New: models.Records{testDataAA5678ttl700, testDataAA1234ttl700},
 					Msgs: []string{
-						"CHANGE laba.f.com A 5.6.7.8 (ttl 300->700)",
-						"CREATE laba.f.com A 1.2.3.4",
+						"CHANGE laba.f.com A (5.6.7.8 ttl=300 ttl=300) -> (1.2.3.4 ttl=700 ttl=700)",
+						"CREATE laba.f.com A 5.6.7.8 ttl=700",
 					},
 				},
 			},
@@ -471,7 +471,7 @@ func Test_diffTargets(t *testing.T) {
 				Change{Type: CREATE,
 					Key:  models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"},
 					New:  models.Records{testDataAMX10a},
-					Msgs: []string{"CREATE laba.f.com MX 10 laba"},
+					Msgs: []string{"CREATE laba.f.com MX 10 laba ttl=300"},
 				},
 			},
 		},
@@ -486,7 +486,7 @@ func Test_diffTargets(t *testing.T) {
 				Change{Type: DELETE,
 					Key:  models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"},
 					Old:  models.Records{testDataAMX10a},
-					Msgs: []string{"DELETE laba.f.com MX 10 laba"},
+					Msgs: []string{"DELETE laba.f.com MX 10 laba ttl=300"},
 				},
 			},
 		},
@@ -502,7 +502,7 @@ func Test_diffTargets(t *testing.T) {
 					Key:  models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"},
 					Old:  models.Records{testDataAMX10a},
 					New:  models.Records{testDataAMX20b},
-					Msgs: []string{"CHANGE laba.f.com MX (10 laba) -> (20 labb)"},
+					Msgs: []string{"CHANGE laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"},
 				},
 			},
 		},
@@ -518,7 +518,7 @@ func Test_diffTargets(t *testing.T) {
 					Key:  models.RecordKey{NameFQDN: "laba.f.com", Type: "A"},
 					Old:  models.Records{testDataAA1234, testDataAA5678},
 					New:  models.Records{testDataAA1234},
-					Msgs: []string{"DELETE laba.f.com A 5.6.7.8"},
+					Msgs: []string{"DELETE laba.f.com A 5.6.7.8 ttl=300"},
 				},
 			},
 		},
@@ -656,8 +656,8 @@ func Test_splitTTLOnly(t *testing.T) {
 				existing: mkTargetConfig(testDataAA1234),
 				desired:  mkTargetConfig(testDataAA1234ttl700),
 			},
-			wantExistDiff:  mkTargetConfig(),
-			wantDesireDiff: mkTargetConfig(),
+			wantExistDiff:  mkTargetConfig(testDataAA1234),
+			wantDesireDiff: mkTargetConfig(testDataAA1234ttl700),
 			wantExistTTL:   models.Records{testDataAA1234},
 			wantDesireTTL:  models.Records{testDataAA1234ttl700},
 		},