package denominator; import org.junit.AssumptionViolatedException; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized.Parameter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import denominator.model.ResourceRecordSet; import denominator.model.Zone; import static denominator.assertj.ModelAssertions.assertThat; import static denominator.model.ResourceRecordSets.a; import static denominator.model.ResourceRecordSets.ns; import static java.lang.String.format; import static org.junit.Assume.assumeTrue; import static org.junit.runners.MethodSorters.NAME_ASCENDING; @FixMethodOrder(NAME_ASCENDING) @RunWith(Live.Write.class) public class ZoneWriteCommandsLiveTest { @Parameter(0) public DNSApiManager manager; @Parameter(1) public String zoneName; @Test public void test1_putNewZone() { assumeZoneAbsent(zoneName); String id = zoneApi().put(Zone.create(null, zoneName, 3601, "test@denominator.io")); assertThat(id).isNotNull(); Zone zone = zoneApi().iterateByName(zoneName).next(); assertThat(zone) .hasName(zoneName) .hasId(id) .hasEmail("test@denominator.io") .hasTtl(3601); } @Test public void test2_zoneTtlIsEqualToSOATtl() { assertZoneTtlIsEqualToSOATtl(); } @Test public void test2_createDuplicateZone() { Zone zone = assumeZonePresent(zoneName); // Regardless of whether the provider supports duplicate zones, putting an existing zone without // changes should be a no-op. String zoneId = zoneApi().put(zone); assertThat(zoneId).isEqualTo(zone.id()); // When duplicate zones are supported, putting a new zone (and not supplying an id) means you // intend to create a duplicate zone as opposed to updating the first. String maybeDuplicate = zoneApi().put(Zone.create(null, zone.name(), zone.ttl(), zone.email())); if (manager.provider().supportsDuplicateZoneNames()) { assertThat(zone.id()).isNotEqualTo(maybeDuplicate); zoneApi().delete(maybeDuplicate); } else { assertThat(zone.id()).isEqualTo(maybeDuplicate); } } @Test public void test3_putChangingDefaultTTL() { Zone zone = assumeZonePresent(zoneName); String zoneId = zoneApi().put(Zone.create(zone.id(), zone.name(), 200000, zone.email())); assertThat(zoneId).isEqualTo(zone.id()); assertThat(zoneApi().iterateByName(zoneName).next()) .hasTtl(200000); } @Test public void test4_zoneTtlIsEqualToSOATtl() { assertZoneTtlIsEqualToSOATtl(); } @Test public void test4_putChangingEmail() { Zone zone = assumeZonePresent(zoneName); String zoneId = zoneApi().put(Zone.create(zone.id(), zone.name(), zone.ttl(), "nil@denominator.io")); assertThat(zoneId).isEqualTo(zone.id()); assertThat(zoneApi().iterateByName(zoneName).next()) .hasEmail("nil@denominator.io"); } @Test public void test5_deleteZoneWhenNotEmpty() { Zone zone = assumeZonePresent(zoneName); // Ensure even custom top-level NS records are deleted. manager.api().basicRecordSetsInZone(zone.id()).put(a("ns-google." + zoneName, "8.8.8.8")); manager.api().basicRecordSetsInZone(zone.id()) .put(ns(zoneName, nsValues(zone, "ns-google." + zoneName))); // We expect all providers (even route53 which requires clearing first) to act the same. zoneApi().delete(zone.id()); assertThat(zoneApi()) .doesNotContain(zone); assertThat(zoneApi().iterateByName(zone.name())) .isEmpty(); // deleting again is ok zoneApi().delete(zone.id()); } private ZoneApi zoneApi() { return manager.api().zones(); } private void assumeZoneAbsent(String zoneName) { Iterator<Zone> existing = zoneApi().iterateByName(zoneName); if (existing.hasNext()) { throw new AssumptionViolatedException(format("zone(%s) already exists", existing.next())); } } private Zone assumeZonePresent(String zoneName) { Iterator<Zone> existing = zoneApi().iterateByName(zoneName); if (!existing.hasNext()) { throw new AssumptionViolatedException(format("zone(%s) doesn't exist", zoneName)); } return existing.next(); } /** * @see ReadOnlyLiveTest#zoneTtlIsEqualToSOATtl() */ private void assertZoneTtlIsEqualToSOATtl() { Zone zone = assumeZonePresent(zoneName); ResourceRecordSet<?> soa = manager.api().basicRecordSetsInZone(zone.id()).getByNameAndType(zone.name(), "SOA"); assumeTrue("SOA records aren't exposed", soa != null); // Ex. designate doesn't expose SOA assertThat(zone.ttl()) .overridingErrorMessage("zone %s should have the same ttl as soa %s", zone, soa) .isEqualTo(soa.ttl()); } /** * Returns {@code nsdname} prefixed by any existing NS values. */ private List<String> nsValues(Zone zone, String nsdname) { List<String> result = new ArrayList<String>(); ResourceRecordSet<?> rrset = manager.api().basicRecordSetsInZone(zone.id()).getByNameAndType(zoneName, "NS"); if (rrset != null) { // Ex. designate doesn't expose default NS records for (Map<String, Object> record : rrset.records()) { result.add(record.get("nsdname").toString()); } } result.add(nsdname); return result; } }