// Copyright 2017 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.beam; import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import google.registry.util.ResourceUtils; import java.io.File; import java.io.IOException; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Map.Entry; import org.apache.beam.runners.direct.DirectRunner; import org.apache.beam.sdk.options.PipelineOptions; import org.apache.beam.sdk.options.PipelineOptionsFactory; import org.apache.beam.sdk.options.ValueProvider.StaticValueProvider; import org.apache.beam.sdk.testing.TestPipeline; import org.apache.beam.sdk.transforms.Create; import org.apache.beam.sdk.values.PCollection; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link InvoicingPipeline}. */ @RunWith(JUnit4.class) public class InvoicingPipelineTest { private static PipelineOptions pipelineOptions; @BeforeClass public static void initializePipelineOptions() { pipelineOptions = PipelineOptionsFactory.create(); pipelineOptions.setRunner(DirectRunner.class); } @Rule public final transient TestPipeline p = TestPipeline.fromOptions(pipelineOptions); @Rule public final TemporaryFolder tempFolder = new TemporaryFolder(); private InvoicingPipeline invoicingPipeline; @Before public void initializePipeline() throws IOException { invoicingPipeline = new InvoicingPipeline(); invoicingPipeline.projectId = "test-project"; File beamTempFolder = tempFolder.newFolder(); invoicingPipeline.beamBucketUrl = beamTempFolder.getAbsolutePath(); invoicingPipeline.invoiceStagingUrl = beamTempFolder.getAbsolutePath() + "/staging"; invoicingPipeline.invoiceTemplateUrl = beamTempFolder.getAbsolutePath() + "/templates/invoicing"; invoicingPipeline.billingBucketUrl = tempFolder.getRoot().getAbsolutePath(); } private ImmutableList getInputEvents() { return ImmutableList.of( BillingEvent.create( 1, ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")), ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")), "theRegistrar", "234", "test", "RENEW", "mydomain.test", "REPO-ID", 3, "USD", 20.5, ""), BillingEvent.create( 1, ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")), ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")), "theRegistrar", "234", "test", "RENEW", "mydomain2.test", "REPO-ID", 3, "USD", 20.5, ""), BillingEvent.create( 1, ZonedDateTime.of(2017, 10, 2, 0, 0, 0, 0, ZoneId.of("UTC")), ZonedDateTime.of(2017, 9, 29, 0, 0, 0, 0, ZoneId.of("UTC")), "theRegistrar", "234", "hello", "CREATE", "mydomain3.hello", "REPO-ID", 5, "JPY", 70.75, ""), BillingEvent.create( 1, ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")), ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")), "googledomains", "456", "test", "RENEW", "mydomain4.test", "REPO-ID", 1, "USD", 20.5, "")); } /** Returns a map from filename to expected contents for detail reports. */ private ImmutableMap> getExpectedDetailReportMap() { return ImmutableMap.of( "invoice_details_2017-10_theRegistrar_test.csv", ImmutableList.of( "1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,theRegistrar,234," + "test,RENEW,mydomain2.test,REPO-ID,3,USD,20.50,", "1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,theRegistrar,234," + "test,RENEW,mydomain.test,REPO-ID,3,USD,20.50,"), "invoice_details_2017-10_theRegistrar_hello.csv", ImmutableList.of( "1,2017-10-02 00:00:00 UTC,2017-09-29 00:00:00 UTC,theRegistrar,234," + "hello,CREATE,mydomain3.hello,REPO-ID,5,JPY,70.75,"), "invoice_details_2017-10_googledomains_test.csv", ImmutableList.of( "1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,googledomains,456," + "test,RENEW,mydomain4.test,REPO-ID,1,USD,20.50,")); } private ImmutableList getExpectedInvoiceOutput() { return ImmutableList.of( "2017-10-01,2020-09-30,234,41.00,USD,10125,1,PURCHASE,theRegistrar - test,2," + "RENEW | TLD: test | TERM: 3-year,20.50,USD,", "2017-10-01,2022-09-30,234,70.75,JPY,10125,1,PURCHASE,theRegistrar - hello,1," + "CREATE | TLD: hello | TERM: 5-year,70.75,JPY,", "2017-10-01,2018-09-30,456,20.50,USD,10125,1,PURCHASE,googledomains - test,1," + "RENEW | TLD: test | TERM: 1-year,20.50,USD,"); } @Test public void testEndToEndPipeline_generatesExpectedFiles() throws Exception { ImmutableList inputRows = getInputEvents(); PCollection input = p.apply(Create.of(inputRows)); invoicingPipeline.applyTerminalTransforms(input, StaticValueProvider.of("2017-10")); p.run(); for (Entry> entry : getExpectedDetailReportMap().entrySet()) { ImmutableList detailReport = resultFileContents(entry.getKey()); assertThat(detailReport.get(0)) .isEqualTo("id,billingTime,eventTime,registrarId,billingId,tld,action," + "domain,repositoryId,years,currency,amount,flags"); assertThat(detailReport.subList(1, detailReport.size())) .containsExactlyElementsIn(entry.getValue()); } ImmutableList overallInvoice = resultFileContents("CRR-INV-2017-10.csv"); assertThat(overallInvoice.get(0)) .isEqualTo( "StartDate,EndDate,ProductAccountKey,Amount,AmountCurrency,BillingProductCode," + "SalesChannel,LineItemType,UsageGroupingKey,Quantity,Description,UnitPrice," + "UnitPriceCurrency,PONumber"); assertThat(overallInvoice.subList(1, overallInvoice.size())) .containsExactlyElementsIn(getExpectedInvoiceOutput()); } /** Returns the text contents of a file under the beamBucket/results directory. */ private ImmutableList resultFileContents(String filename) throws Exception { File resultFile = new File( String.format( "%s/invoices/2017-10/%s", tempFolder.getRoot().getAbsolutePath(), filename)); return ImmutableList.copyOf( ResourceUtils.readResourceUtf8(resultFile.toURI().toURL()).split("\n")); } }