Adjust JobMetrics component tests and add AwsEstimate component tests

This commit is contained in:
Rendani Gangazhe
2023-06-02 10:08:17 -04:00
committed by Dannon Baker
parent 7e02181d20
commit dc1a24e4d4
4 changed files with 122 additions and 112 deletions
@@ -0,0 +1,86 @@
import ec2 from "./ec2.json";
import flushPromises from "flush-promises";
import { getLocalVue } from "tests/jest/helpers";
import AwsEstimate from "./AwsEstimate";
import { mount } from "@vue/test-utils";
// Ignore all axios calls, data is mocked locally -- just say "OKAY!"
jest.mock("axios", () => ({
get: async () => {
return { response: { status: 200 } };
},
}));
const localVue = getLocalVue();
describe("JobMetrics/AwsEstimate.vue", () => {
it("renders nothing if no matching EC2 instance exists.", async () => {
const wrapper = mount(AwsEstimate, {
propsData: {
jobId: "0",
jobRuntime: 0,
coresAllocated: -999,
memoryAllocated: -999,
},
localVue,
});
await wrapper.vm.$nextTick();
expect(wrapper.find("#aws-name").exists()).toBe(false);
});
it("renders correct AWS estimates.", async () => {
const deriveRenderedAwsEstimate = async (cores, seconds, memory) => {
const JOB_ID = Math.random().toString(36).substring(2);
const wrapper = mount(AwsEstimate, {
localVue,
propsData: {
jobId: JOB_ID,
jobRuntime: Number(seconds),
coresAllocated: Number(cores),
memoryAllocated: Number(memory),
},
});
// Wait for axios and rendering.
await flushPromises();
if (wrapper.find("#aws-estimate").exists()) {
return {
cost: wrapper.find("#aws-cost").text(),
vcpus: wrapper.find("#aws-vcpus").text(),
cpu: wrapper.find("#aws-cpu").text(),
mem: wrapper.find("#aws-mem").text(),
name: wrapper.find("#aws-name").text(),
};
}
return {};
};
const assertAwsInstance = (estimates) => {
const instance = ec2.find((instance) => estimates.name === instance.name);
expect(estimates.mem).toBe(instance.mem.toString());
expect(estimates.vcpus).toBe(instance.vcpus.toString());
expect(estimates.cpu).toBe(instance.cpu.join(", "));
};
const estimates_small = await deriveRenderedAwsEstimate("1.0000000", "9.0000000", "2048.0000000");
expect(estimates_small.name).toBe("t2.small");
expect(estimates_small.cost).toBe("0.00 USD");
assertAwsInstance(estimates_small);
const estimates_large = await deriveRenderedAwsEstimate("40.0000000", "18000.0000000", "194560.0000000");
expect(estimates_large.name).toBe("m5d.12xlarge");
expect(estimates_large.cost).toBe("16.32 USD");
assertAwsInstance(estimates_large);
const estimates_not_available = await deriveRenderedAwsEstimate(
"99999.0000000",
"18000.0000000",
"99999.0000000"
);
expect(estimates_not_available).toEqual({});
});
});
@@ -5,60 +5,55 @@ import ec2 from "./ec2.json";
export interface AwsEstimateProps {
jobRuntime: number;
coresAllocated: number;
memoryAllocated: number;
memoryAllocated?: number;
}
const props = withDefaults(defineProps<AwsEstimateProps>(), {
memoryAllocated: 0.5,
});
const props = defineProps<AwsEstimateProps>();
const computedAwsEstimate = computed(() => {
const aws: Record<string, any> = {};
const { coresAllocated, jobRuntime, memoryAllocated } = props;
aws.seconds = jobRuntime;
aws.vcpus = coresAllocated;
aws.memory = memoryAllocated;
if (aws.memory) {
aws.memory /= 1024;
} else {
// if memory was not specified, assign the smallest amount (we judge based on CPU-count only)
aws.memory = 0.5;
}
// Estimate EC2 instance. Data is already sorted
aws.instance = ec2.find((ec) => {
return ec.mem >= aws.memory && ec.vcpus >= aws.vcpus;
});
if (!aws.instance) {
if (coresAllocated <= 0 || jobRuntime <= 0) {
return;
}
aws.price = ((aws.seconds * aws.instance.price) / 3600).toFixed(2);
const adjustedMemoryAllocated = memoryAllocated ? memoryAllocated / 1024 : 0.5;
return aws;
// Estimate EC2 instance. Data is already sorted
const ec2Instance = ec2.find((ec) => {
return ec.mem >= adjustedMemoryAllocated && ec.vcpus >= coresAllocated;
});
if (!ec2Instance) {
return;
}
return {
seconds: jobRuntime,
vcpus: coresAllocated,
memory: adjustedMemoryAllocated,
price: ((jobRuntime * ec2Instance.price) / 3600).toFixed(2),
instance: ec2Instance
};
});
</script>
<template>
<div v-if="computedAwsEstimate" class="aws mt-4">
<div v-if="computedAwsEstimate" id="aws-estimate" class="mt-4">
<h3>AWS estimate</h3>
<strong>{{ computedAwsEstimate.price }} USD</strong>
<strong id="aws-cost">{{ computedAwsEstimate.price }} USD</strong>
<br />
This job requested {{ computedAwsEstimate.vcpus }} core{{ computedAwsEstimate.vcpus > 1 ? "s" : "" }} and
{{ computedAwsEstimate.memory.toFixed(3) }} GiB of memory. Given this information, the smallest EC2 machine we
could find is:
This job requested {{ computedAwsEstimate.vcpus }} core(s) and
{{ computedAwsEstimate.memory.toFixed(3) }} GiB of memory. Given this
information, the smallest EC2 machine we could find is:
<span id="aws_name">{{ computedAwsEstimate.instance.name }}</span>
(<span id="aws_mem">{{ computedAwsEstimate.instance.mem }}</span> GB /
<span id="aws_vcpus">{{ computedAwsEstimate.instance.vcpus }}</span> vCPUs /
<span v-for="cpu in computedAwsEstimate.instance.cpu" id="aws_cpu" :key="cpu">{{ cpu }}</span
<span id="aws-name">{{ computedAwsEstimate.instance.name }}</span>
(<span id="aws-mem">{{ computedAwsEstimate.instance.mem }}</span> GB /
<span id="aws-vcpus">{{ computedAwsEstimate.instance.vcpus }}</span> vCPUs /
<span id="aws-cpu">{{ computedAwsEstimate.instance.cpu.join(", ") }}</span
>). This instance is priced at {{ computedAwsEstimate.instance.price }} USD/hour.
<br />
@@ -1,5 +1,4 @@
import { createTestingPinia } from "@pinia/testing";
import ec2 from "./ec2.json";
import flushPromises from "flush-promises";
import { getLocalVue } from "tests/jest/helpers";
import JobMetrics from "./JobMetrics";
@@ -69,76 +68,4 @@ describe("JobMetrics/JobMetrics.vue", () => {
expect(metricsTables.at(1).find(".metrics_plugin_title").text()).toBe("extended");
expect(metricsTables.at(1).findAll("tr").length).toBe(1);
});
it("renders correct AWS estimates", async () => {
const deriveRenderedAwsEstimate = async (cores, seconds, memory) => {
const JOB_ID = Math.random().toString(36).substring(2);
const mockMetricsResponse = [
{ plugin: "core", name: "galaxy_slots", raw_value: cores },
{ plugin: "core", name: "runtime_seconds", raw_value: seconds },
{ plugin: "core", name: "galaxy_memory_mb", raw_value: memory },
];
const pinia = createTestingPinia({
initialState: {
jobMetricsStore: {
jobMetricsByJobId: {
[`${JOB_ID}`]: mockMetricsResponse,
},
jobMetricsByHdaId: {},
jobMetricsByLddaId: {},
},
},
});
setActivePinia(pinia);
const wrapper = mount(JobMetrics, {
localVue,
pinia,
propsData: {
jobId: JOB_ID,
shouldShowAwsEstimate: true,
},
});
// Wait for axios and rendering.
await flushPromises();
if (wrapper.find("#aws-estimate").exists()) {
return {
cost: wrapper.find("#aws-estimate b").text(),
vcpus: wrapper.find("#aws_vcpus").text(),
cpu: wrapper.find("#aws_cpu").text(),
mem: wrapper.find("#aws_mem").text(),
name: wrapper.find("#aws_name").text(),
};
}
return {};
};
const assertAwsInstance = (estimates) => {
const instance = ec2.find((instance) => estimates.name === instance.name);
expect(estimates.mem).toBe(instance.mem.toString());
expect(estimates.vcpus).toBe(instance.vcpus.toString());
expect(estimates.cpu).toBe(instance.cpu.toString());
};
const estimates_small = await deriveRenderedAwsEstimate("1.0000000", "9.0000000", "2048.0000000");
expect(estimates_small.name).toBe("t2.small");
expect(estimates_small.cost).toBe("0.00 USD");
assertAwsInstance(estimates_small);
const estimates_large = await deriveRenderedAwsEstimate("40.0000000", "18000.0000000", "194560.0000000");
expect(estimates_large.name).toBe("m5d.12xlarge");
expect(estimates_large.cost).toBe("16.32 USD");
assertAwsInstance(estimates_large);
const estimates_not_available = await deriveRenderedAwsEstimate(
"99999.0000000",
"18000.0000000",
"99999.0000000"
);
expect(estimates_not_available).toEqual({});
});
});
@@ -6,18 +6,20 @@ import { useJobMetricsStore } from "@/stores/jobMetricsStore";
import { computed, unref } from "vue";
export interface JobMetricsProps {
jobId: string;
datasetId: string;
shouldShowAwsEstimate: boolean;
datasetType?: string;
datasetFilesize?: number;
datasetId?: string;
datasetType?: string;
includeTitle?: boolean;
jobId: string;
shouldShowAwsEstimate?: boolean;
}
const props = withDefaults(defineProps<JobMetricsProps>(), {
datasetType: "hda",
datasetFilesize: 0,
datasetId: "",
datasetType: "hda",
includeTitle: true,
shouldShowAwsEstimate: false
});
const jobMetricsStore = useJobMetricsStore();