summaryrefslogtreecommitdiffstats
path: root/controller-server/src/test/java/com
diff options
context:
space:
mode:
authorOla Aunrønning <olaa@verizonmedia.com>2020-06-25 17:21:11 +0200
committerOla Aunrønning <olaa@verizonmedia.com>2020-06-26 08:06:35 +0200
commitec08b79dc7a187d52f90855b91781b2744ac7db3 (patch)
tree9441a7566118bf9ff30605b12cbd8a97d228566f /controller-server/src/test/java/com
parent0e441d4aa6ee951367dfbb9aa684b4b556039a13 (diff)
Add BillingApiHandler
Diffstat (limited to 'controller-server/src/test/java/com')
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java16
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java214
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/billing-all-tenants48
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/invoice-creation-response1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/line-item-list9
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view38
6 files changed, 318 insertions, 8 deletions
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
index b7e7c9814e3..1b21f7db7c4 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
@@ -12,14 +12,14 @@ import com.yahoo.vespa.hosted.controller.api.integration.aws.MockAwsEventFetcher
import com.yahoo.vespa.hosted.controller.api.integration.aws.MockResourceTagger;
import com.yahoo.vespa.hosted.controller.api.integration.aws.NoopApplicationRoleService;
import com.yahoo.vespa.hosted.controller.api.integration.aws.ResourceTagger;
-import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanController;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.MockBillingController;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateMock;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServer;
import com.yahoo.vespa.hosted.controller.api.integration.dns.MemoryNameService;
import com.yahoo.vespa.hosted.controller.api.integration.entity.MemoryEntityService;
import com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever;
import com.yahoo.vespa.hosted.controller.api.integration.organization.MockIssueHandler;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.SystemMonitor;
import com.yahoo.vespa.hosted.controller.api.integration.resource.CostReportConsumerMock;
import com.yahoo.vespa.hosted.controller.api.integration.routing.GlobalRoutingService;
import com.yahoo.vespa.hosted.controller.api.integration.routing.MemoryGlobalRoutingService;
@@ -60,7 +60,7 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
private final MockRunDataStore mockRunDataStore = new MockRunDataStore();
private final MockResourceTagger mockResourceTagger = new MockResourceTagger();
private final ApplicationRoleService applicationRoleService = new NoopApplicationRoleService();
- private final PlanController planController = (tenantName) -> null;
+ private final BillingController billingController = new MockBillingController();
public ServiceRegistryMock(SystemName system) {
this.zoneRegistryMock = new ZoneRegistryMock(system);
@@ -187,6 +187,11 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
return systemMonitor;
}
+ @Override
+ public BillingController billingController() {
+ return billingController;
+ }
+
public ConfigServerMock configServerMock() {
return configServerMock;
}
@@ -203,9 +208,4 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
return endpointCertificateMock;
}
- @Override
- public PlanController planController() {
- return planController;
- }
-
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
new file mode 100644
index 00000000000..19cfa95c682
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
@@ -0,0 +1,214 @@
+package com.yahoo.vespa.hosted.controller.restapi.billing;
+
+import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.Invoice;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.MockBillingController;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
+import com.yahoo.vespa.hosted.controller.api.role.Role;
+import com.yahoo.vespa.hosted.controller.restapi.ContainerTester;
+import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerCloudTest;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import static com.yahoo.application.container.handler.Request.Method.*;
+import static org.junit.Assert.*;
+
+/**
+ * @author olaa
+ */
+public class BillingApiHandlerTest extends ControllerContainerCloudTest {
+
+ private static final String responseFiles = "src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/";
+ private static final TenantName tenant = TenantName.from("tenant1");
+ private static final TenantName tenant2 = TenantName.from("tenant2");
+ private static final Set<Role> tenantRole = Set.of(Role.administrator(tenant));
+ private static final Set<Role> financeAdmin = Set.of(Role.hostedAccountant());
+ private MockBillingController billingController;
+
+ private ContainerTester tester;
+
+ @Before
+ public void setup() {
+ tester = new ContainerTester(container, responseFiles);
+ billingController = (MockBillingController) tester.serviceRegistry().billingController();
+ }
+
+ @Override
+ protected SystemName system() {
+ return SystemName.PublicCd;
+ }
+
+ @Override
+ protected String variablePartXml() {
+ return " <component id='com.yahoo.vespa.hosted.controller.security.CloudAccessControlRequests'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.controller.security.CloudAccessControl'/>\n" +
+
+ " <handler id='com.yahoo.vespa.hosted.controller.restapi.billing.BillingApiHandler'>\n" +
+ " <binding>http://*/billing/v1/*</binding>\n" +
+ " </handler>\n" +
+
+ " <http>\n" +
+ " <server id='default' port='8080' />\n" +
+ " <filtering>\n" +
+ " <request-chain id='default'>\n" +
+ " <filter id='com.yahoo.vespa.hosted.controller.restapi.filter.ControllerAuthorizationFilter'/>\n" +
+ " <binding>http://*/*</binding>\n" +
+ " </request-chain>\n" +
+ " </filtering>\n" +
+ " </http>\n";
+ }
+
+ @Test
+ public void setting_and_deleting_instrument() {
+ assertTrue(billingController.getDefaultInstrument(tenant).isEmpty());
+
+ var instrumentRequest = request("/billing/v1/tenant/tenant1/instrument", PATCH)
+ .data("{\"active\": \"id-1\"}")
+ .roles(tenantRole);
+
+ tester.assertResponse(instrumentRequest,"OK");
+ assertEquals("id-1", billingController.getDefaultInstrument(tenant).get().getId());
+
+ var deleteInstrumentRequest = request("/billing/v1/tenant/tenant1/instrument/id-1", DELETE)
+ .roles(tenantRole);
+
+ tester.assertResponse(deleteInstrumentRequest,"OK");
+ assertTrue(billingController.getDefaultInstrument(tenant).isEmpty());
+ }
+
+ @Test
+ public void response_list_bills() {
+ var invoice = createInvoice();
+
+ billingController.addInvoice(tenant, invoice, true);
+ billingController.addInvoice(tenant, invoice, false);
+ billingController.setPlan(tenant, PlanId.from("some-plan"), true);
+
+ var request = request("/billing/v1/tenant/tenant1/billing?until=2020-05-28").roles(tenantRole);
+ tester.assertResponse(request, new File("tenant-billing-view"));
+
+ }
+
+ @Test
+ public void test_invoice_creation() {
+ var invoices = billingController.getInvoices(tenant);
+ assertEquals(0, invoices.size());
+
+ String requestBody = "{\"tenant\":\"tenant1\", \"startTime\":\"2020-04-20\", \"endTime\":\"2020-05-20\"}";
+ var request = request("/billing/v1/invoice", POST)
+ .data(requestBody)
+ .roles(tenantRole);
+
+ tester.assertResponse(request, accessDenied, 403);
+ request.roles(financeAdmin);
+ tester.assertResponse(request, new File("invoice-creation-response"));
+
+ invoices = billingController.getInvoices(tenant);
+ assertEquals(1, invoices.size());
+ Invoice invoice = invoices.get(0);
+ assertEquals(invoice.getStartTime().toString(), "2020-04-20T00:00Z[UTC]");
+ assertEquals(invoice.getEndTime().toString(), "2020-05-20T00:00Z[UTC]");
+ }
+
+ @Test
+ public void adding_and_listing_line_item() {
+
+ var requestBody = "{" +
+ "\"description\":\"some description\"," +
+ "\"amount\":\"123.45\" " +
+ "}";
+
+ var request = request("/billing/v1/invoice/tenant/tenant1/line-item", POST)
+ .data(requestBody)
+ .roles(financeAdmin);
+
+ tester.assertResponse(request, "{\"message\":\"Added line item for tenant tenant1\"}");
+
+ var lineItems = billingController.getUnusedLineItems(tenant);
+ Assert.assertEquals(1, lineItems.size());
+ Invoice.LineItem lineItem = lineItems.get(0);
+ assertEquals("some description", lineItem.description());
+ assertEquals(new BigDecimal("123.45"), lineItem.amount());
+
+ request = request("/billing/v1/invoice/tenant/tenant1/line-item")
+ .roles(financeAdmin);
+
+ tester.assertResponse(request, new File("line-item-list"));
+ }
+
+ @Test
+ public void adding_new_status() {
+ billingController.addInvoice(tenant, createInvoice(), true);
+
+ var requestBody = "{\"status\":\"DONE\"}";
+ var request = request("/billing/v1/invoice/id-1/status", POST)
+ .data(requestBody)
+ .roles(financeAdmin);
+ tester.assertResponse(request, "{\"message\":\"Updated status of invoice id-1\"}");
+
+ var invoice = billingController.getInvoices(tenant).get(0);
+ assertEquals("DONE", invoice.status());
+ }
+
+ @Test
+ public void list_all_uninvoiced_items() {
+ var invoice = createInvoice();
+ billingController.setPlan(tenant, PlanId.from("some-plan"), true);
+ billingController.setPlan(tenant2, PlanId.from("some-plan"), true);
+ billingController.addInvoice(tenant, invoice, false);
+ billingController.addLineItem(tenant, "support", new BigDecimal("42"), "Smith");
+ billingController.addInvoice(tenant2, invoice, false);
+
+
+ var request = request("/billing/v1/billing?until=2020-05-28").roles(financeAdmin);
+
+ tester.assertResponse(request, new File("billing-all-tenants"));
+ }
+
+ @Test
+ public void setting_plans() {
+ var planRequest = request("/billing/v1/tenant/tenant1/plan", PATCH)
+ .data("{\"plan\": \"new-plan\"}")
+ .roles(tenantRole);
+ tester.assertResponse(planRequest, "Plan: new-plan");
+ assertEquals("new-plan", billingController.getPlan(tenant).value());
+ }
+
+ private Invoice createInvoice() {
+ var start = LocalDate.of(2020, 5, 23).atStartOfDay(ZoneId.systemDefault());
+ var end = start.plusDays(5);
+ var statusHistory = new Invoice.StatusHistory(new TreeMap<>(Map.of(start, "OPEN")));
+ return new Invoice(
+ Invoice.Id.of("id-1"),
+ statusHistory,
+ List.of(createLineItem(start)),
+ start,
+ end
+ );
+ }
+
+
+ private Invoice.LineItem createLineItem(ZonedDateTime addedAt) {
+ return new Invoice.LineItem(
+ "some-id",
+ "description",
+ new BigDecimal("123.00"),
+ "plan",
+ "Smith",
+ addedAt
+ );
+ }
+
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/billing-all-tenants b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/billing-all-tenants
new file mode 100644
index 00000000000..c5bf0c88c2c
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/billing-all-tenants
@@ -0,0 +1,48 @@
+{
+ "until":"2020-05-28",
+ "tenants":[
+ {
+ "tenant":"tenant2",
+ "plan":"some-plan",
+ "current":{
+ "amount":"123.00",
+ "status":"accrued",
+ "from":"2020-05-23",
+ "items":[
+ {
+ "id":"some-id",
+ "description":"description",
+ "amount":"123.00"
+ }
+ ]
+ },
+ "additional":{"items":[]}
+ },
+ {
+ "tenant":"tenant1",
+ "plan":"some-plan",
+ "current":{
+ "amount":"123.00",
+ "status":"accrued",
+ "from":"2020-05-23",
+ "items":[
+ {
+ "id":"some-id",
+ "description":"description",
+ "amount":"123.00"
+ }
+ ]
+ },
+ "additional":
+ {
+ "items":[
+ {
+ "id":"line-item-id",
+ "description":"support",
+ "amount":"42.00"
+ }
+ ]
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/invoice-creation-response b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/invoice-creation-response
new file mode 100644
index 00000000000..0a92229025b
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/invoice-creation-response
@@ -0,0 +1 @@
+{"message":"Created invoice with ID id-123"} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/line-item-list b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/line-item-list
new file mode 100644
index 00000000000..cd5aec2f8f4
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/line-item-list
@@ -0,0 +1,9 @@
+{
+ "lineItems":[
+ {
+ "id":"line-item-id",
+ "description":"some description",
+ "amount":"123.45"
+ }
+ ]
+} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view
new file mode 100644
index 00000000000..8bc39771b31
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view
@@ -0,0 +1,38 @@
+{
+ "until":"2020-05-28",
+ "plan":"some-plan",
+ "current":{
+ "amount":"123.00",
+ "status":"accrued",
+ "from":"2020-05-23",
+ "items":[
+ {
+ "id":"some-id",
+ "description":"description",
+ "amount":"123.00"
+ }
+ ]
+ },
+ "additional":{"items":[]},
+ "bills":[
+ {
+ "id":"id-1",
+ "from":"2020-05-23",
+ "to":"2020-05-28","amount":"123.00",
+ "status":"OPEN",
+ "statusHistory":[
+ {
+ "at":"2020-05-23",
+ "status":"OPEN"
+ }
+ ],
+ "items":[
+ {
+ "id":"some-id",
+ "description":"description",
+ "amount":"123.00"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file