Skip to content

Commit

Permalink
Added the Get Charge State API
Browse files Browse the repository at this point in the history
  • Loading branch information
JSkimming committed Jan 8, 2018
1 parent 3f9c879 commit 39b4365
Show file tree
Hide file tree
Showing 5 changed files with 349 additions and 10 deletions.
45 changes: 39 additions & 6 deletions src/Tesla.NET/ITeslaClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,21 @@ Task<MessageResponse<ResponseDataWrapper<IReadOnlyList<Vehicle>>>> GetVehiclesAs
CancellationToken cancellationToken = default);

/// <summary>
/// Gets the <see cref="VehicleState"/> of the <see cref="Vehicle"/> with the specified
/// Gets the <see cref="ChargeState"/> of the <see cref="Vehicle"/> with the specified
/// <see cref="Vehicle.Id"/>.
/// </summary>
/// <param name="vehicleId">The unique <see cref="Vehicle.Id"/> of a <see cref="Vehicle"/>.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for a task to
/// complete.</param>
/// <returns>
/// The <see cref="VehicleState"/> of the <see cref="Vehicle"/> with the specified <see cref="Vehicle.Id"/>.
/// The <see cref="ChargeState"/> of the <see cref="Vehicle"/> with the specified <see cref="Vehicle.Id"/>.
/// </returns>
Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
Task<MessageResponse<ResponseDataWrapper<ChargeState>>> GetChargeStateAsync(
long vehicleId,
CancellationToken cancellationToken = default);

/// <summary>
/// Gets the <see cref="VehicleState"/> of the <see cref="Vehicle"/> with the specified
/// Gets the <see cref="ChargeState"/> of the <see cref="Vehicle"/> with the specified
/// <see cref="Vehicle.Id"/>.
/// </summary>
/// <param name="vehicleId">The unique <see cref="Vehicle.Id"/> of a <see cref="Vehicle"/>.</param>
Expand All @@ -63,9 +63,9 @@ Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for a task to
/// complete.</param>
/// <returns>
/// The <see cref="VehicleState"/> of the <see cref="Vehicle"/> with the specified <see cref="Vehicle.Id"/>.
/// The <see cref="ChargeState"/> of the <see cref="Vehicle"/> with the specified <see cref="Vehicle.Id"/>.
/// </returns>
Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
Task<MessageResponse<ResponseDataWrapper<ChargeState>>> GetChargeStateAsync(
long vehicleId,
string accessToken,
CancellationToken cancellationToken = default);
Expand Down Expand Up @@ -102,5 +102,38 @@ Task<MessageResponse<ResponseDataWrapper<DriveState>>> GetDriveStateAsync(
long vehicleId,
string accessToken,
CancellationToken cancellationToken = default);

/// <summary>
/// Gets the <see cref="VehicleState"/> of the <see cref="Vehicle"/> with the specified
/// <see cref="Vehicle.Id"/>.
/// </summary>
/// <param name="vehicleId">The unique <see cref="Vehicle.Id"/> of a <see cref="Vehicle"/>.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for a task to
/// complete.</param>
/// <returns>
/// The <see cref="VehicleState"/> of the <see cref="Vehicle"/> with the specified <see cref="Vehicle.Id"/>.
/// </returns>
Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
long vehicleId,
CancellationToken cancellationToken = default);

/// <summary>
/// Gets the <see cref="VehicleState"/> of the <see cref="Vehicle"/> with the specified
/// <see cref="Vehicle.Id"/>.
/// </summary>
/// <param name="vehicleId">The unique <see cref="Vehicle.Id"/> of a <see cref="Vehicle"/>.</param>
/// <param name="accessToken">
/// The access token used to authenticate the request; can be <see langword="null"/> if the authentication is
/// added by default.
/// </param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for a task to
/// complete.</param>
/// <returns>
/// The <see cref="VehicleState"/> of the <see cref="Vehicle"/> with the specified <see cref="Vehicle.Id"/>.
/// </returns>
Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
long vehicleId,
string accessToken,
CancellationToken cancellationToken = default);
}
}
36 changes: 36 additions & 0 deletions src/Tesla.NET/Requests/HttpClientExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,42 @@ public static Task<MessageResponse<ResponseDataWrapper<IReadOnlyList<Vehicle>>>>
.ReadJsonAsAsync<ResponseDataWrapper<IReadOnlyList<Vehicle>>>(cancellationToken);
}

/// <summary>
/// Gets the <see cref="ChargeState"/> of the <see cref="Vehicle"/> with the specified
/// <see cref="Vehicle.Id"/>.
/// </summary>
/// <param name="client">The <see cref="HttpClient"/>.</param>
/// <param name="baseUri">The base <see cref="Uri"/> of the Tesla Owner API.</param>
/// <param name="vehicleId">The unique <see cref="Vehicle.Id"/> of a <see cref="Vehicle"/>.</param>
/// <param name="accessToken">
/// The access token used to authenticate the request; can be <see langword="null"/> if the authentication is
/// added by default.
/// </param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for a task to
/// complete.</param>
/// <returns>
/// The <see cref="ChargeState"/> of the <see cref="Vehicle"/> with the specified <see cref="Vehicle.Id"/>.
/// </returns>
public static Task<MessageResponse<ResponseDataWrapper<ChargeState>>> GetChargeStateAsync(
this HttpClient client,
Uri baseUri,
long vehicleId,
string accessToken = null,
CancellationToken cancellationToken = default)
{
if (client == null)
throw new ArgumentNullException(nameof(client));
if (baseUri == null)
throw new ArgumentNullException(nameof(baseUri));

Uri requestUri = new Uri(baseUri, $"api/1/vehicles/{vehicleId}/data_request/charge_state");

return
client
.GetWithAuthAsync(requestUri, accessToken, cancellationToken)
.ReadJsonAsAsync<ResponseDataWrapper<ChargeState>>(cancellationToken);
}

/// <summary>
/// Gets the <see cref="DriveState"/> of the <see cref="Vehicle"/> with the specified
/// <see cref="Vehicle.Id"/>.
Expand Down
28 changes: 24 additions & 4 deletions src/Tesla.NET/TeslaClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,23 @@ public Task<MessageResponse<ResponseDataWrapper<IReadOnlyList<Vehicle>>>> GetVeh
}

/// <inheritdoc />
public Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
public Task<MessageResponse<ResponseDataWrapper<ChargeState>>> GetChargeStateAsync(
long vehicleId,
CancellationToken cancellationToken = default)
{
return Client.GetVehicleStateAsync(BaseUri, vehicleId, cancellationToken: cancellationToken);
return Client.GetChargeStateAsync(BaseUri, vehicleId, cancellationToken: cancellationToken);
}

/// <inheritdoc />
public Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
public Task<MessageResponse<ResponseDataWrapper<ChargeState>>> GetChargeStateAsync(
long vehicleId,
string accessToken,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(accessToken))
throw new ArgumentNullException(nameof(accessToken));

return Client.GetVehicleStateAsync(BaseUri, vehicleId, accessToken, cancellationToken);
return Client.GetChargeStateAsync(BaseUri, vehicleId, accessToken, cancellationToken);
}

/// <inheritdoc />
Expand All @@ -110,5 +110,25 @@ public Task<MessageResponse<ResponseDataWrapper<DriveState>>> GetDriveStateAsync

return Client.GetDriveStateAsync(BaseUri, vehicleId, accessToken, cancellationToken);
}

/// <inheritdoc />
public Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
long vehicleId,
CancellationToken cancellationToken = default)
{
return Client.GetVehicleStateAsync(BaseUri, vehicleId, cancellationToken: cancellationToken);
}

/// <inheritdoc />
public Task<MessageResponse<ResponseDataWrapper<VehicleState>>> GetVehicleStateAsync(
long vehicleId,
string accessToken,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(accessToken))
throw new ArgumentNullException(nameof(accessToken));

return Client.GetVehicleStateAsync(BaseUri, vehicleId, accessToken, cancellationToken);
}
}
}
178 changes: 178 additions & 0 deletions test/Tesla.NET.Tests/GetChargeStateTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright (c) 2018 James Skimming. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace Tesla.NET
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using AutoFixture;
using FluentAssertions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Tesla.NET.Models;
using Xunit;
using Xunit.Abstractions;

public abstract class GetChargeStateSuccessTestsBase : ClientRequestContext
{
private readonly ResponseDataWrapper<ChargeState> _expected;
private readonly long _vehicleId;
private readonly Uri _expectedRequestUri;

protected GetChargeStateSuccessTestsBase(ITestOutputHelper output, bool useCustomBaseUri)
: base(output, useCustomBaseUri)
{
// Arrange
_expected = Fixture.Create<ResponseDataWrapper<ChargeState>>();
_vehicleId = Fixture.Create<long>();
Handler.SetResponseContent(_expected);
_expectedRequestUri = new Uri(BaseUri, $"/api/1/vehicles/{_vehicleId}/data_request/charge_state");
}

[Fact]
public async Task Should_make_a_GET_request()
{
// Act
await Sut.GetChargeStateAsync(_vehicleId, AccessToken).ConfigureAwait(false);

// Assert
Handler.Request.Method.Should().Be(HttpMethod.Get);
}

[Fact]
public async Task Should_request_the_charge_state_endpoint()
{
// Act
await Sut.GetChargeStateAsync(_vehicleId, AccessToken).ConfigureAwait(false);

// Assert
Handler.Request.RequestUri.Should().Be(_expectedRequestUri);
}

[Fact]
public async Task Should_return_the_expected_charge_state()
{
// Act
MessageResponse<ResponseDataWrapper<ChargeState>> actual =
await Sut.GetChargeStateAsync(_vehicleId, AccessToken).ConfigureAwait(false);

// Assert
actual.HttpStatusCode.Should().Be(HttpStatusCode.OK);
actual.Data.ShouldBeEquivalentTo(_expected, WithStrictOrdering);
}

[Fact]
public async Task Should_set_the_bearer_token_with_the_specified_access_token()
{
// Act
await Sut.GetChargeStateAsync(_vehicleId, AccessToken).ConfigureAwait(false);

// Assert
Handler.Request.Headers.Authorization.Scheme.Should().Be("Bearer");
Handler.Request.Headers.Authorization.Parameter.Should().Be(AccessToken);
}

[Fact]
public async Task Should_NOT_set_the_bearer_token_if_the_access_token_is_not_specified()
{
// Act
await Sut.GetChargeStateAsync(_vehicleId).ConfigureAwait(false);

// Assert
Handler.Request.Headers.Authorization.Should().BeNull();
}
}

public class When_getting_the_charge_state_for_a_vehicle_using_the_default_base_Uri : GetChargeStateSuccessTestsBase
{
public When_getting_the_charge_state_for_a_vehicle_using_the_default_base_Uri(ITestOutputHelper output)
: base(output, useCustomBaseUri: false)
{
}
}

public class When_getting_the_charge_state_for_a_vehicle_using_a_custom_base_Uri : GetChargeStateSuccessTestsBase
{
public When_getting_the_charge_state_for_a_vehicle_using_a_custom_base_Uri(ITestOutputHelper output)
: base(output, useCustomBaseUri: true)
{
}
}

public abstract class GetChargeStateFailureTestsBase : ClientRequestContext
{
private readonly long _vehicleId;

protected GetChargeStateFailureTestsBase(ITestOutputHelper output, bool useCustomBaseUri)
: base(output, useCustomBaseUri)
{
// Arrange
_vehicleId = Fixture.Create<long>();
Handler.SetResponseContent(new JObject(), HttpStatusCode.BadGateway);
}

[Fact]
public void Should_throw_an_HttpRequestException()
{
// Act
Func<Task> action = () => Sut.GetChargeStateAsync(_vehicleId, AccessToken);

// Assert
action.ShouldThrowExactly<HttpRequestException>();
}
}

public class When_failing_to_get_the_charge_state_for_a_vehicle_using_the_default_base_Uri
: GetChargeStateFailureTestsBase
{
public When_failing_to_get_the_charge_state_for_a_vehicle_using_the_default_base_Uri(ITestOutputHelper output)
: base(output, useCustomBaseUri: false)
{
}
}

public class When_failing_to_get_the_charge_state_for_a_vehicle_using_a_custom_base_Uri
: GetChargeStateFailureTestsBase
{
public When_failing_to_get_the_charge_state_for_a_vehicle_using_a_custom_base_Uri(ITestOutputHelper output)
: base(output, useCustomBaseUri: true)
{
}
}

public class When_getting_the_charge_state_for_a_vehicle_the_raw_JSON : ClientRequestContext
{
private readonly JObject _expected;
private readonly long _vehicleId;

public When_getting_the_charge_state_for_a_vehicle_the_raw_JSON(ITestOutputHelper output)
: base(output, useCustomBaseUri: false)
{
// Arrange
_expected = SampleJson.GetChargeStateResponse;
_vehicleId = Fixture.Create<long>();

// Add random values to test whether it is correctly passed through.
_expected["randomValue1"] = Fixture.Create("randomValue1");
_expected["randomValue2"] = JObject.FromObject(new { fakeId = Guid.NewGuid() });
_expected["response"]["randomValue3"] = Fixture.Create("randomValue3");

Handler.SetResponseContent(_expected);
}

[Fact]
public async Task Should_be_passed_through_in_the_response()
{
// Act
MessageResponse<ResponseDataWrapper<ChargeState>> response =
await Sut.GetChargeStateAsync(_vehicleId).ConfigureAwait(false);

// Assert
response.RawJsonAsString.Should().Be(_expected.ToString(Formatting.None));
}
}
}
Loading

0 comments on commit 39b4365

Please sign in to comment.