diff --git a/java/google/registry/tools/CountDomainsCommand.java b/java/google/registry/tools/CountDomainsCommand.java new file mode 100644 index 000000000..b79b2e456 --- /dev/null +++ b/java/google/registry/tools/CountDomainsCommand.java @@ -0,0 +1,57 @@ +// Copyright 2018 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.tools; + +import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.model.registry.Registries.assertTldsExist; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; +import com.google.common.collect.Iterators; +import google.registry.model.domain.DomainResource; +import google.registry.tools.Command.RemoteApiCommand; +import google.registry.util.Clock; +import java.util.List; +import javax.inject.Inject; +import org.joda.time.DateTime; + +/** Command to show the count of active domains on a given TLD. */ +@Parameters(separators = " =", commandDescription = "Show count of domains on TLD") +final class CountDomainsCommand implements RemoteApiCommand { + + @Parameter(description = "TLD(s) to count domains on", required = true) + private List mainParameters; + + @Inject Clock clock; + + @Override + public void run() { + DateTime now = clock.nowUtc(); + assertTldsExist(mainParameters) + .forEach(tld -> System.out.printf("%s,%d\n", tld, getCountForTld(tld, now))); + } + + private int getCountForTld(String tld, DateTime now) { + return Iterators.size( + ofy() + .load() + .type(DomainResource.class) + .filter("tld", tld) + .filter("deletionTime >", now) + .chunkAll() + .keys() + .iterator()); + } +} diff --git a/java/google/registry/tools/RegistryTool.java b/java/google/registry/tools/RegistryTool.java index 6ae5e3ae1..5f9c24cae 100644 --- a/java/google/registry/tools/RegistryTool.java +++ b/java/google/registry/tools/RegistryTool.java @@ -36,6 +36,7 @@ public final class RegistryTool { .put("check_domain_fee", CheckDomainFeeCommand.class) .put("check_snapshot", CheckSnapshotCommand.class) .put("convert_idn", ConvertIdnCommand.class) + .put("count_domains", CountDomainsCommand.class) .put("create_anchor_tenant", CreateAnchorTenantCommand.class) .put("create_auction_credits", CreateAuctionCreditsCommand.class) .put("create_cdns_tld", CreateCdnsTld.class) diff --git a/java/google/registry/tools/RegistryToolComponent.java b/java/google/registry/tools/RegistryToolComponent.java index 504584760..99f97a337 100644 --- a/java/google/registry/tools/RegistryToolComponent.java +++ b/java/google/registry/tools/RegistryToolComponent.java @@ -75,6 +75,7 @@ import javax.inject.Singleton; } ) interface RegistryToolComponent { + void inject(CountDomainsCommand command); void inject(CreateAnchorTenantCommand command); void inject(CreateCdnsTld command); void inject(CreateContactCommand command); diff --git a/javatests/google/registry/tools/CountDomainsCommandTest.java b/javatests/google/registry/tools/CountDomainsCommandTest.java new file mode 100644 index 000000000..ee45954f2 --- /dev/null +++ b/javatests/google/registry/tools/CountDomainsCommandTest.java @@ -0,0 +1,70 @@ +// Copyright 2018 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.tools; + +import static google.registry.testing.DatastoreHelper.createTlds; +import static google.registry.testing.DatastoreHelper.persistActiveDomain; +import static google.registry.testing.DatastoreHelper.persistDeletedDomain; +import static org.joda.time.DateTimeZone.UTC; + +import google.registry.model.ofy.Ofy; +import google.registry.testing.FakeClock; +import google.registry.testing.InjectRule; +import org.joda.time.DateTime; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +/** Unit tests for {@link CountDomainsCommand}. */ +public class CountDomainsCommandTest extends CommandTestCase { + + protected FakeClock clock = new FakeClock(DateTime.now(UTC)); + + @Rule public final InjectRule inject = new InjectRule(); + + @Before + public final void before() { + inject.setStaticField(Ofy.class, "clock", clock); + command.clock = clock; + createTlds("foo", "bar", "baz", "qux"); + } + + @Test + public void testSuccess_singleTld() throws Exception { + for (int i = 0; i < 51; i++) { + persistActiveDomain(String.format("test-%d.foo", i)); + if (i > 31) { + persistActiveDomain(String.format("test-%d.baz", i)); + } + } + runCommand("foo"); + assertStdoutIs("foo,51\n"); + } + + @Test + public void testSuccess_multipleTlds() throws Exception { + command.clock = clock; + for (int i = 0; i < 29; i++) { + persistActiveDomain(String.format("test-%d.foo", i)); + } + for (int j = 0; j < 17; j++) { + persistActiveDomain(String.format("test-%d.baz", j)); + persistDeletedDomain(String.format("del-%d.foo", j), clock.nowUtc().minusYears(1)); + } + persistActiveDomain("not-counted.qux"); + runCommand("foo", "bar", "baz"); + assertStdoutIs("foo,29\nbar,0\nbaz,17\n"); + } +}