Skip to content
Snippets Groups Projects
Commit 52abed81 authored by Dmytro Bogatov's avatar Dmytro Bogatov :two_hearts:
Browse files

Merge branch '33-zoom-to-timeframe-on-metric-page' into 'master'

Resolve "Zoom to timeframe on metric page"

Closes #33

See merge request !18
parents 0aa0d49c 7e480a4f
Branches
No related tags found
No related merge requests found
Pipeline #
Showing
with 402 additions and 47 deletions
...@@ -13,6 +13,7 @@ import "bootstrap" ...@@ -13,6 +13,7 @@ import "bootstrap"
declare var source: string; declare var source: string;
declare var type: number; declare var type: number;
declare var min: number; declare var min: number;
declare var max: number; declare var max: number;
... ...
......
...@@ -55,4 +55,10 @@ export class Constants { ...@@ -55,4 +55,10 @@ export class Constants {
* of 5 minutes and sums of user actions will be displayed per interval. * of 5 minutes and sums of user actions will be displayed per interval.
*/ */
static USER_ACTIONS_AGGREGATION_INTERVAL : number = 30; static USER_ACTIONS_AGGREGATION_INTERVAL : number = 30;
/**
* The interval in milliseconds that defines a default time frame of data
* on metric pages.
*/
static METRIC_PAGE_DATA_PREVIEW : number = 2 * 60 * 60 * 1000;
} }
...@@ -10,8 +10,12 @@ import "../../vendor/jquery.flot.time.js"; ...@@ -10,8 +10,12 @@ import "../../vendor/jquery.flot.time.js";
import "../../vendor/jquery.flot.selection.js"; import "../../vendor/jquery.flot.selection.js";
import "../../vendor/jquery.flot.threshold.js"; import "../../vendor/jquery.flot.threshold.js";
import "../../vendor/jquery.flot.tooltip.js"; import "../../vendor/jquery.flot.tooltip.js";
import { Constants } from "../constants";
declare var start: number;
declare var end: number;
/** /**
* Represents set of procedures for rendering metric page. * Represents set of procedures for rendering metric page.
* *
...@@ -23,6 +27,7 @@ export abstract class MetricPage<T extends Metric<DataPoint>> { ...@@ -23,6 +27,7 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
protected metric: T; protected metric: T;
protected dataTablesRendered: boolean = false; protected dataTablesRendered: boolean = false;
protected dataTable : DataTables.DataTable;
/** /**
* Minimal theoretical value for data series. * Minimal theoretical value for data series.
...@@ -47,13 +52,52 @@ export abstract class MetricPage<T extends Metric<DataPoint>> { ...@@ -47,13 +52,52 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
protected detailedPlotOptions: any; protected detailedPlotOptions: any;
protected overviewPlotOptions: any; protected overviewPlotOptions: any;
/**
* Date as a number of milliseconds of the first data point
*
* @protected
* @type {number}
* @memberof MetricPage
*/
protected minData: number; protected minData: number;
/**
* Date as a number of milliseconds of the last data point
*
* @protected
* @type {number}
* @memberof MetricPage
*/
protected maxData: number; protected maxData: number;
/**
* If given, the timestamp of first data point in selected range
*
* @protected
* @type {Date}
* @memberof MetricPage
*/
protected start: Date = null;
/**
* If given, the timestamp of last data point in selected range
*
* @protected
* @type {Date}
* @memberof MetricPage
*/
protected end: Date = null;
constructor(min: number, max: number) { constructor(min: number, max: number) {
this.max = max; this.max = max;
this.min = min; this.min = min;
if (start > 0) {
this.start = new Date(start);
}
if (end > 0) {
this.end = new Date(end);
}
window.setTimeout(async () => { window.setTimeout(async () => {
await this.metric.loadData(60 * 60 * 24 * 3); // 3 days await this.metric.loadData(60 * 60 * 24 * 3); // 3 days
...@@ -113,19 +157,49 @@ export abstract class MetricPage<T extends Metric<DataPoint>> { ...@@ -113,19 +157,49 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
// don't fire event on the overview to prevent eternal loop // don't fire event on the overview to prevent eternal loop
overview.setSelection(ranges, true); overview.setSelection(ranges, true);
// Re-render data table to include only selected data points
this.renderTable(true, new Date(ranges.xaxis.from), new Date(ranges.xaxis.to));
})); }));
$("#metric-overview-plot").bind("plotselected", <any>((event, ranges) => { $("#metric-overview-plot").bind("plotselected", <any>((event, ranges) => {
plot.setSelection(ranges); plot.setSelection(ranges);
})); }));
if (this.start != null) {
let from = Math.min(
Math.max(
this.start.getTime(),
this.minData
),
this.maxData)
;
let to =
this.end == null ?
Math.min(
this.maxData,
this.start.getTime() + Constants.METRIC_PAGE_DATA_PREVIEW
) :
Math.max(
Math.min(
this.end.getTime(),
this.maxData
),
this.minData)
;
plot.setSelection({ xaxis: { from: from, to: to }, yaxis: { from: 0, to: 0 } });
} else {
// if latest data point is more than 2 hours ago // if latest data point is more than 2 hours ago
// select recent 2 hours in plot // select recent 2 hours in plot
if (new Date().getTime() - this.minData > 2 * 60 * 60 * 1000) { if (new Date().getTime() - this.minData > Constants.METRIC_PAGE_DATA_PREVIEW) {
let from = new Date().getTime() - 2 * 60 * 60 * 1000; let from = new Date().getTime() - Constants.METRIC_PAGE_DATA_PREVIEW;
plot.setSelection({ xaxis: { from: from, to: this.maxData }, yaxis: { from: 0, to: 0 } }); plot.setSelection({ xaxis: { from: from, to: this.maxData }, yaxis: { from: 0, to: 0 } });
} }
} }
}
/** /**
* Renders data tables in the UI. * Renders data tables in the UI.
...@@ -135,7 +209,19 @@ export abstract class MetricPage<T extends Metric<DataPoint>> { ...@@ -135,7 +209,19 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
* *
* @memberOf MetricPage * @memberOf MetricPage
*/ */
protected abstract renderTable(): void;
/**
* Renders data tables in the UI.
* Does not load the data.
*
* @protected
* @abstract
* @param {boolean} redraw if data table has to be force-redrawn; implies non-null values of start and end;
* @param {Date} start start date for filter
* @param {Date} end end date for filter
* @memberof MetricPage
*/
protected abstract renderTable(redraw: boolean, start: Date, end: Date): void;
/** /**
* Renders numeric values in the UI. * Renders numeric values in the UI.
...@@ -164,6 +250,6 @@ export abstract class MetricPage<T extends Metric<DataPoint>> { ...@@ -164,6 +250,6 @@ export abstract class MetricPage<T extends Metric<DataPoint>> {
this.renderPlot(); this.renderPlot();
this.renderValues(); this.renderValues();
this.renderTable(); this.renderTable(false, null, null);
} }
} }
...@@ -106,9 +106,13 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> { ...@@ -106,9 +106,13 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> {
}; };
}; };
protected renderTable(): void { protected renderTable(redraw: boolean, start: Date, end: Date): void {
if (!this.dataTablesRendered) { if (!this.dataTablesRendered || redraw) {
if (this.dataTablesRendered) {
this.dataTable.destroy();
}
let header = ` let header = `
<tr> <tr>
...@@ -124,6 +128,17 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> { ...@@ -124,6 +128,17 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> {
this.metric this.metric
.data .data
.map(dp => <CpuLoadDataPoint>dp) .map(dp => <CpuLoadDataPoint>dp)
.filter((value, index, array) => {
if (start != null && value.timestamp < start) {
return false;
}
if (end != null && value.timestamp > end) {
return false;
}
return true;
})
.map( .map(
dp => ` dp => `
<tr> <tr>
...@@ -135,7 +150,7 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> { ...@@ -135,7 +150,7 @@ export class CpuLoadMetricPage extends MetricPage<Metric<CpuLoadDataPoint>> {
.join() .join()
); );
$('#metric-data').DataTable({ this.dataTable = $('#metric-data').DataTable({
"order": [[0, "desc"]], "order": [[0, "desc"]],
lengthChange: false, lengthChange: false,
searching: false, searching: false,
... ...
......
...@@ -111,9 +111,13 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> { ...@@ -111,9 +111,13 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
}; };
}; };
protected renderTable(): void { protected renderTable(redraw: boolean, start: Date, end: Date): void {
if (!this.dataTablesRendered) { if (!this.dataTablesRendered || redraw) {
if (this.dataTablesRendered) {
this.dataTable.destroy();
}
let header = ` let header = `
<tr> <tr>
...@@ -130,6 +134,17 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> { ...@@ -130,6 +134,17 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
this.metric this.metric
.data .data
.map(dp => <HealthDataPoint>dp) .map(dp => <HealthDataPoint>dp)
.filter((value, index, array) => {
if (start != null && value.timestamp < start) {
return false;
}
if (end != null && value.timestamp > end) {
return false;
}
return true;
})
.map( .map(
dp => ` dp => `
<tr> <tr>
...@@ -160,7 +175,7 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> { ...@@ -160,7 +175,7 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
.join() .join()
); );
$('#metric-data').DataTable({ this.dataTable = $('#metric-data').DataTable({
"order": [[0, "desc"]], "order": [[0, "desc"]],
lengthChange: false, lengthChange: false,
searching: false, searching: false,
...@@ -178,8 +193,8 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> { ...@@ -178,8 +193,8 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
let code = ` let code = `
<div <div
class="modal fade" class="modal fade health-details-modal"
id="modal-details" id="modal-details-${timestamp.getTime()}"
tabindex="-1" tabindex="-1"
role="dialog" role="dialog"
aria-hidden="true" aria-hidden="true"
...@@ -192,7 +207,10 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> { ...@@ -192,7 +207,10 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
<h4 class="modal-title"> <h4 class="modal-title">
Health report details | Health ${e.detail.health}% | ${timestamp} Health report details | Health ${e.detail.health}% | ${timestamp}
<small> <small>
Inspect metric labels at the moment report was generated Inspect metric labels at the moment report was generated.
<a href="/home/metric/${this.metric.metricType}/${this.metric.source}/${new Date(timestamp.getTime() - 2 * 60 * 1000).getTime()}/${new Date(timestamp.getTime() + 2 * 60 * 1000).getTime()}">
View data at that moment.
</a>
</small> </small>
</h4> </h4>
</div> </div>
...@@ -239,16 +257,23 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> { ...@@ -239,16 +257,23 @@ export class HealthMetricPage extends MetricPage<Metric<HealthDataPoint>> {
</div> </div>
`; `;
$("#modal").html(code); $("body").append(code);
$('#details-table').DataTable({ $('#details-table').DataTable({
"order": [[0, "desc"]], destroy: true,
order: [[0, "desc"]],
lengthChange: false, lengthChange: false,
searching: false, searching: false,
pageLength: 10 pageLength: 10
}); });
$("#modal-details").modal(); $(`#modal-details-${timestamp.getTime()}`).modal();
$(`#modal-details-${timestamp.getTime()}`).on(
"hidden.bs.modal",
() => $(".health-details-modal").remove()
);
}, },
false); false);
... ...
......
...@@ -149,9 +149,13 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> { ...@@ -149,9 +149,13 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> {
}; };
}; };
protected renderTable(): void { protected renderTable(redraw: boolean, start: Date, end: Date): void {
if (!this.dataTablesRendered) { if (!this.dataTablesRendered || redraw) {
if (this.dataTablesRendered) {
this.dataTable.destroy();
}
let header = ` let header = `
<tr> <tr>
...@@ -168,6 +172,17 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> { ...@@ -168,6 +172,17 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> {
this.metric this.metric
.data .data
.map(dp => <PingDataPoint>dp) .map(dp => <PingDataPoint>dp)
.filter((value, index, array) => {
if (start != null && value.timestamp < start) {
return false;
}
if (end != null && value.timestamp > end) {
return false;
}
return true;
})
.map( .map(
dp => ` dp => `
<tr> <tr>
...@@ -180,7 +195,7 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> { ...@@ -180,7 +195,7 @@ export class PingMetricPage extends MetricPage<Metric<PingDataPoint>> {
.join() .join()
); );
$('#metric-data').DataTable({ this.dataTable = $('#metric-data').DataTable({
"order": [[0, "desc"]], "order": [[0, "desc"]],
lengthChange: false, lengthChange: false,
searching: false, searching: false,
... ...
......
...@@ -154,9 +154,13 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint> ...@@ -154,9 +154,13 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint>
}; };
}; };
protected renderTable(): void { protected renderTable(redraw: boolean, start: Date, end: Date): void {
if (!this.dataTablesRendered) { if (!this.dataTablesRendered || redraw) {
if (this.dataTablesRendered) {
this.dataTable.destroy();
}
let header = ` let header = `
<tr> <tr>
...@@ -173,6 +177,17 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint> ...@@ -173,6 +177,17 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint>
this.metric this.metric
.data .data
.map(dp => <UserActionDataPoint>dp) .map(dp => <UserActionDataPoint>dp)
.filter((value, index, array) => {
if (start != null && value.timestamp < start) {
return false;
}
if (end != null && value.timestamp > end) {
return false;
}
return true;
})
.map( .map(
dp => ` dp => `
<tr> <tr>
...@@ -185,7 +200,7 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint> ...@@ -185,7 +200,7 @@ export class UserActionMetricPage extends MetricPage<Metric<UserActionDataPoint>
.join() .join()
); );
$('#metric-data').DataTable({ this.dataTable = $('#metric-data').DataTable({
"order": [[0, "desc"]], "order": [[0, "desc"]],
lengthChange: false, lengthChange: false,
searching: false, searching: false,
... ...
......
status-ctl (1.2.0) unstable; urgency=medium
* Update docker-compose.yml.
-- Dmytro Bogatov <dmytro@dbogatov.org> Thu, 08 Aug 2017 04:35:38 +0000
status-ctl (1.1.1) unstable; urgency=medium status-ctl (1.1.1) unstable; urgency=medium
* Minor fixes. * Minor fixes.
... ...
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
. .
.\" Manpage for status-ctl. .\" Manpage for status-ctl.
.\" Contact dmytro@dbogatov.org to correct errors or typos. .\" Contact dmytro@dbogatov.org to correct errors or typos.
.TH man 1 "4 August 2017" "1.1.1" "status-ctl man page" .TH man 1 "4 August 2017" "1.2.0" "status-ctl man page"
.SH NAME .SH NAME
.B status-ctl .B status-ctl
\- control tool for status site \- control tool for status site
... ...
......
...@@ -10,7 +10,7 @@ BAD_PARAMETERS=4 ...@@ -10,7 +10,7 @@ BAD_PARAMETERS=4
# CONSTANTS # CONSTANTS
CONFIG_DIR=/etc/status-site CONFIG_DIR=/etc/status-site
PROJECT="status-site" PROJECT="status-site"
VERSION="1.1.1" VERSION="1.2.0"
BRANCH="master" BRANCH="master"
function usage { function usage {
... ...
......
...@@ -44,7 +44,7 @@ services: ...@@ -44,7 +44,7 @@ services:
- ./appsettings.yml:/srv/appsettings.production.yml - ./appsettings.yml:/srv/appsettings.production.yml
restart: on-failure restart: on-failure
postgres: postgres:
image: postgres:latest image: postgres:9.6.3-alpine
environment: # define connection credentials to be used in app environment: # define connection credentials to be used in app
- POSTGRES_DB=${POSTGRES_DB} - POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER} - POSTGRES_USER=${POSTGRES_USER}
... ...
......
...@@ -22,5 +22,14 @@ namespace StatusMonitor.Shared.Extensions ...@@ -22,5 +22,14 @@ namespace StatusMonitor.Shared.Extensions
? value.ToString() ? value.ToString()
: TimeZoneInfo.ConvertTime(value, TimeZoneInfo.FindSystemTimeZoneById(timeZoneId)).ToString(); : TimeZoneInfo.ConvertTime(value, TimeZoneInfo.FindSystemTimeZoneById(timeZoneId)).ToString();
} }
/// <summary>
/// Return the number of milliseconds between epoch and given date
/// </summary>
/// <param name="value">The end date of selected range</param>
/// <returns>The number of milliseconds between epoch and given date</returns>
public static long TotalMilliseconds(this DateTime value) =>
Convert.ToInt64((value - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds);
} }
} }
File changed. Contains only whitespace changes. Show whitespace changes.
...@@ -65,8 +65,8 @@ namespace StatusMonitor.Web.Controllers.View ...@@ -65,8 +65,8 @@ namespace StatusMonitor.Web.Controllers.View
return View(model); return View(model);
} }
[Route("Home/Metric/{type}/{source}")] [Route("Home/Metric/{type}/{source}/{start?}/{end?}")]
public async Task<IActionResult> Metric(string type, string source) public async Task<IActionResult> Metric(string type, string source, string start = null, string end = null)
{ {
Metrics metricType; Metrics metricType;
...@@ -79,6 +79,41 @@ namespace StatusMonitor.Web.Controllers.View ...@@ -79,6 +79,41 @@ namespace StatusMonitor.Web.Controllers.View
return BadRequest("Bad type. Needs to be one of Metrics type."); return BadRequest("Bad type. Needs to be one of Metrics type.");
} }
if (start != null)
{
try
{
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).AddMilliseconds(Convert.ToInt64(start));
}
catch (System.Exception)
{
return BadRequest("Bad start date. Needs to be the number of milliseconds since Epoch.");
}
}
if (end != null)
{
try
{
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).AddMilliseconds(Convert.ToInt64(end));
}
catch (System.Exception)
{
return BadRequest("Bad end date. Needs to be the number of milliseconds since Epoch.");
}
}
if (start != null && end != null)
{
if (
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).AddMilliseconds(Convert.ToInt64(start)) >=
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).AddMilliseconds(Convert.ToInt64(end))
)
{
return BadRequest("Bad dates. End date needs to be greater than the start date.");
}
}
var model = await _metricService.GetMetricsAsync(metricType, source); var model = await _metricService.GetMetricsAsync(metricType, source);
if (model.Count() == 0) if (model.Count() == 0)
...@@ -107,6 +142,9 @@ namespace StatusMonitor.Web.Controllers.View ...@@ -107,6 +142,9 @@ namespace StatusMonitor.Web.Controllers.View
ViewBag.Uptime = await _uptime.ComputeUptimeAsync(source); ViewBag.Uptime = await _uptime.ComputeUptimeAsync(source);
} }
ViewBag.Start = start ?? 0.ToString();
ViewBag.End = end ?? 0.ToString();
return View(model.First()); return View(model.First());
} }
... ...
......
...@@ -22,7 +22,13 @@ ...@@ -22,7 +22,13 @@
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h2>Plotted data <small>Data is requested for a day back.</small></h2> <h2>
Plotted data
<small>
Data is requested for a 3 days back.
Select a range on the plot to zoom.
</small>
</h2>
</div> </div>
<div class="card-body card-padding"> <div class="card-body card-padding">
<div id="metric-detailed-plot" class="flot-chart"></div> <div id="metric-detailed-plot" class="flot-chart"></div>
...@@ -38,7 +44,7 @@ ...@@ -38,7 +44,7 @@
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h2>Data points <small>Data is requested for a day back.</small></h2> <h2>Data points <small>Data is shown for the same interval as selected plot.</small></h2>
</div> </div>
<div class="card-body card-padding"> <div class="card-body card-padding">
...@@ -186,8 +192,12 @@ ...@@ -186,8 +192,12 @@
<script> <script>
var source = "@Model.Source"; var source = "@Model.Source";
var type = @Model.Type; var type = @Model.Type;
var min = @ViewData["Min"]; var min = @ViewData["Min"];
var max = @ViewData["Max"]; var max = @ViewData["Max"];
var start = @ViewData["Start"];
var end = @ViewData["End"];
</script> </script>
<environment names="Development"> <environment names="Development">
... ...
......
@using StatusMonitor.Shared.Extensions
<div <div
class="list-group-item media discrepancy-card discrepancy-@(Model.Resolved ? "resolved" : "unresolved")" class="list-group-item media discrepancy-card discrepancy-@(Model.Resolved ? "resolved" : "unresolved")"
data-number="@ViewBag.Number" data-number="@ViewBag.Number"
...@@ -39,11 +41,20 @@ ...@@ -39,11 +41,20 @@
<div class="media-body"> <div class="media-body">
<div class="lgi-heading"> <div class="lgi-heading">
Discrepancy of type <strong>@Model.Type</strong> from Discrepancy of type <strong>@Model.Type</strong> from
@{
var start = Convert.ToInt64((Model.DateFirstOffense.AddMinutes(-2) - new DateTime(1970, 1, 1)).TotalMilliseconds);
var end =
Model.Resolved ?
Convert.ToInt64((Model.DateResolved.AddMinutes(2) - new DateTime(1970, 1, 1)).TotalMilliseconds) :
Convert.ToInt64((Model.DateFirstOffense.AddMinutes(15) - new DateTime(1970, 1, 1)).TotalMilliseconds);
}
<a <a
asp-controller="Home" asp-controller="Home"
asp-action="Metric" asp-action="Metric"
asp-route-type="@Model.MetricType" asp-route-type="@Model.MetricType"
asp-route-source="@Model.MetricSource" asp-route-source="@Model.MetricSource"
asp-route-start="@start"
asp-route-end="@end"
> >
<em>@Model.MetricType</em> of <em>@Model.MetricSource</em> <em>@Model.MetricType</em> of <em>@Model.MetricSource</em>
</a> </a>
... ...
......
...@@ -94,5 +94,123 @@ namespace StatusMonitor.Tests.ControllerTests ...@@ -94,5 +94,123 @@ namespace StatusMonitor.Tests.ControllerTests
Assert.Contains("type", (string)badRequestObjectResult.Value); Assert.Contains("type", (string)badRequestObjectResult.Value);
} }
[Fact]
public async Task MetricStartDateRequest()
{
// Act
var result = await _controller.Metric(Metrics.CpuLoad.ToString(), "any-source", "invalid-date");
// Assert
var badRequestObjectResult = Assert.IsType<BadRequestObjectResult>(result);
Assert.Contains("start", (string)badRequestObjectResult.Value);
}
[Fact]
public async Task MetricEndDateRequest()
{
// Act
var result = await _controller.Metric(
Metrics.CpuLoad.ToString(),
"any-source",
DateTime.UtcNow.TotalMilliseconds().ToString(),
"invalid-date"
);
// Assert
var badRequestObjectResult = Assert.IsType<BadRequestObjectResult>(result);
Assert.Contains("end", (string)badRequestObjectResult.Value);
}
[Fact]
public async Task MetricStartAfterEndDateRequest()
{
// Act
var result = await _controller.Metric(
Metrics.CpuLoad.ToString(),
"any-source",
DateTime.UtcNow.TotalMilliseconds().ToString(),
DateTime.UtcNow.AddHours(-1).TotalMilliseconds().ToString()
);
// Assert
var badRequestObjectResult = Assert.IsType<BadRequestObjectResult>(result);
Assert.Contains("greater than", (string)badRequestObjectResult.Value);
}
[Fact]
public async Task MetricDatesOK()
{
// Arrange
_mockMetricService
.Setup(mock => mock.GetMetricsAsync(It.IsAny<Metrics>(), It.IsAny<string>()))
.ReturnsAsync(
new List<Metric> {
new Metric {
CurrentValue = 50,
Public = true
}
}
);
var start = DateTime.UtcNow.AddHours(-1);
var end = DateTime.UtcNow;
// Act
var result = await _controller.Metric(
Metrics.CpuLoad.ToString(),
"existing-source",
start.TotalMilliseconds().ToString(),
end.TotalMilliseconds().ToString()
);
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<Metric>(
viewResult.ViewData.Model
);
Assert.Equal(start.TotalMilliseconds().ToString(), viewResult.ViewData["Start"]);
Assert.Equal(end.TotalMilliseconds().ToString(), viewResult.ViewData["End"]);
}
[Fact]
public async Task MetricDatesEndNullOK()
{
// Arrange
_mockMetricService
.Setup(mock => mock.GetMetricsAsync(It.IsAny<Metrics>(), It.IsAny<string>()))
.ReturnsAsync(
new List<Metric> {
new Metric {
CurrentValue = 50,
Public = true
}
}
);
var start = DateTime.UtcNow;
// Act
var result = await _controller.Metric(
Metrics.CpuLoad.ToString(),
"existing-source",
start.TotalMilliseconds().ToString()
);
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<Metric>(
viewResult.ViewData.Model
);
Assert.Equal(start.TotalMilliseconds().ToString(), viewResult.ViewData["Start"]);
Assert.Equal(0.ToString(), viewResult.ViewData["End"]);
}
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment