diff options
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 |
commit | d65f9d0f47fe2c33f5047ce3aa70434f333de1b5 (patch) | |
tree | 39124976e65d3ebe92e0e4de0fa717ac154033d5 /controller-api | |
parent | e99187fab622e620eb25bad4ac05ed19d7878ba9 (diff) |
Move interface mocks to some location as interface
Diffstat (limited to 'controller-api')
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; + } +} |