summaryrefslogtreecommitdiffstats
path: root/controller-api
diff options
context:
space:
mode:
authorØyvind Grønnesby <oyving@verizonmedia.com>2021-07-06 11:21:14 +0200
committerØyvind Grønnesby <oyving@verizonmedia.com>2021-07-06 11:21:14 +0200
commitd65f9d0f47fe2c33f5047ce3aa70434f333de1b5 (patch)
tree39124976e65d3ebe92e0e4de0fa717ac154033d5 /controller-api
parente99187fab622e620eb25bad4ac05ed19d7878ba9 (diff)
Move interface mocks to some location as interface
Diffstat (limited to 'controller-api')
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingDatabaseClient.java185
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MockDatabaseClient.java127
2 files changed, 312 insertions, 0 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingDatabaseClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingDatabaseClient.java
new file mode 100644
index 00000000000..38888a0ad05
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingDatabaseClient.java
@@ -0,0 +1,185 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.api.integration.billing;
+
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingDatabaseClient;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.CollectionMethod;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.InstrumentOwner;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.Invoice;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.Plan;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistry;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistryMock;
+
+import java.time.Clock;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * @author olaa
+ */
+public class MockBillingDatabaseClient implements BillingDatabaseClient {
+ private final Clock clock;
+ private final PlanRegistry planRegistry;
+ private final Map<TenantName, Plan> tenantPlans = new HashMap<>();
+ private final Map<Invoice.Id, TenantName> invoices = new HashMap<>();
+ private final Map<Invoice.Id, List<Invoice.LineItem>> lineItems = new HashMap<>();
+ private final Map<TenantName, List<Invoice.LineItem>> uncommittedLineItems = new HashMap<>();
+
+ private final Map<Invoice.Id, Invoice.StatusHistory> statuses = new HashMap<>();
+ private final Map<Invoice.Id, ZonedDateTime> startTimes = new HashMap<>();
+ private final Map<Invoice.Id, ZonedDateTime> endTimes = new HashMap<>();
+
+ private final ZonedDateTime startTime = LocalDate.of(2020, 4, 1).atStartOfDay(ZoneId.of("UTC"));
+ private final ZonedDateTime endTime = LocalDate.of(2020, 5, 1).atStartOfDay(ZoneId.of("UTC"));
+
+ private final List<InstrumentOwner> paymentInstruments = new ArrayList<>();
+ private final Map<TenantName, CollectionMethod> collectionMethods = new HashMap<>();
+
+ public MockBillingDatabaseClient(Clock clock, PlanRegistry planRegistry) {
+ this.clock = clock;
+ this.planRegistry = planRegistry;
+ }
+
+ @Override
+ public boolean setActivePaymentInstrument(InstrumentOwner paymentInstrument) {
+ return paymentInstruments.add(paymentInstrument);
+ }
+
+ @Override
+ public Optional<InstrumentOwner> getDefaultPaymentInstrumentForTenant(TenantName tenantName) {
+ return paymentInstruments.stream()
+ .filter(paymentInstrument -> paymentInstrument.getTenantName().equals(tenantName))
+ .findFirst();
+ }
+
+ public String getStatus(Invoice.Id invoiceId) {
+ return statuses.get(invoiceId).current();
+ }
+
+ @Override
+ public Invoice.Id createInvoice(TenantName tenant, ZonedDateTime startTime, ZonedDateTime endTime, String agent) {
+ var invoiceId = Invoice.Id.generate();
+ invoices.put(invoiceId, tenant);
+ statuses.computeIfAbsent(invoiceId, l -> Invoice.StatusHistory.open(clock));
+ startTimes.put(invoiceId, startTime);
+ endTimes.put(invoiceId, endTime);
+ return invoiceId;
+ }
+
+ @Override
+ public Optional<Invoice> readInvoice(Invoice.Id invoiceId) {
+ var invoice = Optional.ofNullable(invoices.get(invoiceId));
+ var lines = lineItems.getOrDefault(invoiceId, List.of());
+ var status = statuses.getOrDefault(invoiceId, Invoice.StatusHistory.open(clock));
+ var start = startTimes.getOrDefault(invoiceId, startTime);
+ var end = endTimes.getOrDefault(invoiceId, endTime);
+ return invoice.map(tenant -> new Invoice(invoiceId, tenant, status, lines, start, end));
+ }
+
+ @Override
+ public String addLineItem(TenantName tenantName, Invoice.LineItem lineItem, Optional<Invoice.Id> invoiceId) {
+ var lineItemId = UUID.randomUUID().toString();
+ invoiceId.ifPresentOrElse(
+ invoice -> lineItems.computeIfAbsent(invoice, l -> new ArrayList<>()).add(lineItem),
+ () -> uncommittedLineItems.computeIfAbsent(tenantName, l -> new ArrayList<>()).add(lineItem)
+ );
+ return lineItemId;
+ }
+
+ @Override
+ public void setStatus(Invoice.Id invoiceId, String agent, String status) {
+ statuses.computeIfAbsent(invoiceId, k -> Invoice.StatusHistory.open(clock))
+ .getHistory()
+ .put(ZonedDateTime.now(), status);
+ }
+
+ @Override
+ public List<Invoice.LineItem> getUnusedLineItems(TenantName tenantName) {
+ return uncommittedLineItems.getOrDefault(tenantName, new ArrayList<>());
+ }
+
+ @Override
+ public void deleteLineItem(String lineItemId) {
+ uncommittedLineItems.values()
+ .forEach(list ->
+ list.removeIf(lineItem -> lineItem.id().equals(lineItemId))
+ );
+ }
+
+ @Override
+ public void commitLineItems(TenantName tenantName, Invoice.Id invoiceId) {
+
+ }
+
+ @Override
+ public Optional<Plan> getPlan(TenantName tenantName) {
+ return Optional.ofNullable(tenantPlans.get(tenantName));
+ }
+
+ @Override
+ public Map<TenantName, Optional<Plan>> getPlans(List<TenantName> tenants) {
+ return tenantPlans.entrySet().stream()
+ .filter(entry -> tenants.contains(entry.getKey()))
+ .collect(Collectors.toMap(
+ entry -> entry.getKey(),
+ entry -> planRegistry.plan(entry.getValue().id())
+ ));
+ }
+
+ @Override
+ public void setPlan(TenantName tenantName, Plan plan) {
+ tenantPlans.put(tenantName, plan);
+ }
+
+ @Override
+ public void deactivateDefaultPaymentInstrument(TenantName tenant) {
+ paymentInstruments.removeIf(instrumentOwner -> instrumentOwner.getTenantName().equals(tenant));
+ }
+
+ @Override
+ public Optional<CollectionMethod> getCollectionMethod(TenantName tenantName) {
+ return Optional.ofNullable(collectionMethods.get(tenantName));
+ }
+
+ @Override
+ public void setCollectionMethod(TenantName tenantName, CollectionMethod collectionMethod) {
+ collectionMethods.put(tenantName, collectionMethod);
+ }
+
+ @Override
+ public List<Invoice> readInvoicesForTenant(TenantName tenant) {
+ return invoices.entrySet().stream()
+ .filter(entry -> entry.getValue().equals(tenant))
+ .map(Map.Entry::getKey)
+ .map(invoiceId -> {
+ var items = lineItems.getOrDefault(invoiceId, List.of());
+ var status = statuses.get(invoiceId);
+ var start = startTimes.get(invoiceId);
+ var end = endTimes.get(invoiceId);
+ return new Invoice(invoiceId, tenant, status, items, start, end);
+ })
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<Invoice> readInvoices() {
+ return invoices.keySet().stream()
+ .map(invoiceId -> {
+ var tenant = invoices.get(invoiceId);
+ var items = lineItems.getOrDefault(invoiceId, List.of());
+ var status = statuses.get(invoiceId);
+ var start = startTimes.get(invoiceId);
+ var end = endTimes.get(invoiceId);
+ return new Invoice(invoiceId, tenant, status, items, start, end);
+ })
+ .collect(Collectors.toList());
+ }
+}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MockDatabaseClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MockDatabaseClient.java
new file mode 100644
index 00000000000..eb6b55a6c9e
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MockDatabaseClient.java
@@ -0,0 +1,127 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.api.integration.resource;
+
+import com.yahoo.config.provision.ApplicationName;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.Plan;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistry;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistryMock;
+import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceDatabaseClient;
+import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshot;
+import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceUsage;
+
+import java.math.BigDecimal;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+/**
+ * @author olaa
+ */
+public class MockDatabaseClient implements ResourceDatabaseClient {
+
+ PlanRegistry planRegistry;
+ Map<TenantName, Plan> planMap = new HashMap<>();
+ List<ResourceSnapshot> resourceSnapshots = new ArrayList<>();
+ private boolean hasRefreshedMaterializedView = false;
+
+ public MockDatabaseClient(PlanRegistry planRegistry) {
+ this.planRegistry = planRegistry;
+ }
+
+ @Override
+ public void writeResourceSnapshots(Collection<ResourceSnapshot> items) {
+ this.resourceSnapshots.addAll(items);
+ }
+
+ @Override
+ public List<ResourceSnapshot> getResourceSnapshotsForMonth(TenantName tenantName, ApplicationName applicationName, YearMonth month) {
+ return resourceSnapshots.stream()
+ .filter(resourceSnapshot -> {
+ LocalDate snapshotDate = LocalDate.ofInstant(resourceSnapshot.getTimestamp(), ZoneId.of("UTC"));
+ return YearMonth.from(snapshotDate).equals(month) &&
+ snapshotDate.getYear() == month.getYear() &&
+ resourceSnapshot.getApplicationId().tenant().equals(tenantName) &&
+ resourceSnapshot.getApplicationId().application().equals(applicationName);
+ })
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Set<YearMonth> getMonthsWithSnapshotsForTenant(TenantName tenantName) {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public List<ResourceSnapshot> getRawSnapshotHistoryForTenant(TenantName tenantName, YearMonth yearMonth) {
+ return resourceSnapshots;
+ }
+
+ @Override
+ public Set<TenantName> getTenants() {
+ return resourceSnapshots.stream()
+ .map(snapshot -> snapshot.getApplicationId().tenant())
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public List<ResourceUsage> getResourceSnapshotsForPeriod(TenantName tenantName, long start, long end) {
+ return resourceSnapshots.stream()
+ .filter(snapshot -> snapshot.getTimestamp().isAfter(Instant.ofEpochMilli(start)))
+ .filter(snapshot -> snapshot.getTimestamp().isBefore(Instant.ofEpochMilli(end)))
+ .filter(snapshot -> snapshot.getApplicationId().tenant().equals(tenantName))
+ .map(snapshot -> new ResourceUsage(
+ snapshot.getApplicationId(),
+ snapshot.getZoneId(),
+ planMap.getOrDefault(tenantName, planRegistry.defaultPlan()),
+ BigDecimal.valueOf(snapshot.getCpuCores()),
+ BigDecimal.valueOf(snapshot.getMemoryGb()),
+ BigDecimal.valueOf(snapshot.getDiskGb())))
+ .collect(
+ Collectors.groupingBy(
+ (ResourceUsage usage) -> Objects.hash(usage.getApplicationId(), usage.getZoneId(), usage.getPlan()),
+ TreeMap::new,
+ Collectors.reducing(
+ (a, b) -> new ResourceUsage(
+ a.getApplicationId(),
+ b.getZoneId(),
+ a.getPlan(),
+ a.getCpuMillis().add(b.getCpuMillis()),
+ a.getMemoryMillis().add(b.getMemoryMillis()),
+ a.getDiskMillis().add(b.getDiskMillis())
+ )
+ )
+ )
+ )
+ .values()
+ .stream()
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ @Override
+ public void refreshMaterializedView() {
+ hasRefreshedMaterializedView = true;
+ }
+
+ public void setPlan(TenantName tenant, Plan plan) {
+ planMap.put(tenant, plan);
+ }
+
+ public boolean hasRefreshedMaterializedView() {
+ return hasRefreshedMaterializedView;
+ }
+}