diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js index f1b07408671..57394097944 100644 --- a/app/assets/javascripts/lib/utils/number_utils.js +++ b/app/assets/javascripts/lib/utils/number_utils.js @@ -42,3 +42,13 @@ export function formatRelevantDigits(number) { export function bytesToKiB(number) { return number / BYTES_IN_KIB; } + +/** + * Utility function that calculates MiB of the given bytes. + * + * @param {Number} number bytes + * @return {Number} MiB + */ +export function bytesToMiB(number) { + return number / (BYTES_IN_KIB * BYTES_IN_KIB); +} diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js index 486b13e60af..8155218681c 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js @@ -1,4 +1,6 @@ import statusCodes from '~/lib/utils/http_status'; +import { bytesToMiB } from '~/lib/utils/number_utils'; + import MemoryGraph from '../../vue_shared/components/memory_graph'; import MRWidgetService from '../services/mr_widget_service'; @@ -9,8 +11,8 @@ export default { }, data() { return { - // memoryFrom: 0, - // memoryTo: 0, + memoryFrom: 0, + memoryTo: 0, memoryMetrics: [], deploymentTime: 0, hasMetrics: false, @@ -35,18 +37,38 @@ export default { shouldShowMetricsUnavailable() { return !this.loadingMetrics && !this.hasMetrics && !this.loadFailed; }, + memoryChangeType() { + const memoryTo = Number(this.memoryTo); + const memoryFrom = Number(this.memoryFrom); + + if (memoryTo > memoryFrom) { + return 'increased'; + } else if (memoryTo < memoryFrom) { + return 'decreased'; + } + + return 'unchanged'; + }, }, methods: { + getMegabytes(bytesString) { + const valueInBytes = Number(bytesString).toFixed(2); + return (bytesToMiB(valueInBytes)).toFixed(2); + }, computeGraphData(metrics, deploymentTime) { this.loadingMetrics = false; - const { memory_values } = metrics; - // if (memory_previous.length > 0) { - // this.memoryFrom = Number(memory_previous[0].value[1]).toFixed(2); - // } - // - // if (memory_current.length > 0) { - // this.memoryTo = Number(memory_current[0].value[1]).toFixed(2); - // } + const { memory_before, memory_after, memory_values } = metrics; + + // Both `memory_before` and `memory_after` objects + // have peculiar structure where accessing only a specific + // index yeilds correct value that we can use to show memory delta. + if (memory_before.length > 0) { + this.memoryFrom = this.getMegabytes(memory_before[0].value[1]); + } + + if (memory_after.length > 0) { + this.memoryTo = this.getMegabytes(memory_after[0].value[1]); + } if (memory_values.length > 0) { this.hasMetrics = true; @@ -102,7 +124,7 @@ export default {

- Deployment memory usage: + Memory usage {{memoryChangeType}} from {{memoryFrom}}MB to {{memoryTo}}MB

{ describe('formatRelevantDigits', () => { @@ -45,4 +45,11 @@ describe('Number Utils', () => { expect(bytesToKiB(1000)).toEqual(0.9765625); }); }); + + describe('bytesToMiB', () => { + it('calculates MiB for the given bytes', () => { + expect(bytesToMiB(1048576)).toEqual(1); + expect(bytesToMiB(1000000)).toEqual(0.95367431640625); + }); + }); }); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js index da9dff18ada..2c3d0ddff28 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js @@ -7,6 +7,18 @@ const url = '/root/acets-review-apps/environments/15/deployments/1/metrics'; const metricsMockData = { success: true, metrics: { + memory_before: [ + { + metric: {}, + value: [1495785220.607, '9572875.906976745'], + }, + ], + memory_after: [ + { + metric: {}, + value: [1495787020.607, '4485853.130206379'], + }, + ], memory_values: [ { metric: {}, @@ -39,7 +51,7 @@ const createComponent = () => { const messages = { loadingMetrics: 'Loading deployment statistics.', - hasMetrics: 'Deployment memory usage:', + hasMetrics: 'Memory usage unchanged from 0MB to 0MB', loadFailed: 'Failed to load deployment statistics.', metricsUnavailable: 'Deployment statistics are not available currently.', }; @@ -89,17 +101,52 @@ describe('MemoryUsage', () => { }); }); + describe('computed', () => { + describe('memoryChangeType', () => { + it('should return "increased" if memoryFrom value is less than memoryTo value', () => { + vm.memoryFrom = 4.28; + vm.memoryTo = 9.13; + + expect(vm.memoryChangeType).toEqual('increased'); + }); + + it('should return "decreased" if memoryFrom value is less than memoryTo value', () => { + vm.memoryFrom = 9.13; + vm.memoryTo = 4.28; + + expect(vm.memoryChangeType).toEqual('decreased'); + }); + + it('should return "unchanged" if memoryFrom value equal to memoryTo value', () => { + vm.memoryFrom = 1; + vm.memoryTo = 1; + + expect(vm.memoryChangeType).toEqual('unchanged'); + }); + }); + }); + describe('methods', () => { const { metrics, deployment_time } = metricsMockData; + describe('getMegabytes', () => { + it('should return Megabytes from provided Bytes value', () => { + const memoryInBytes = '9572875.906976745'; + + expect(vm.getMegabytes(memoryInBytes)).toEqual('9.13'); + }); + }); + describe('computeGraphData', () => { it('should populate sparkline graph', () => { vm.computeGraphData(metrics, deployment_time); - const { hasMetrics, memoryMetrics, deploymentTime } = vm; + const { hasMetrics, memoryMetrics, deploymentTime, memoryFrom, memoryTo } = vm; expect(hasMetrics).toBeTruthy(); expect(memoryMetrics.length > 0).toBeTruthy(); expect(deploymentTime).toEqual(deployment_time); + expect(memoryFrom).toEqual('9.13'); + expect(memoryTo).toEqual('4.28'); }); });