Tests fixed.

This commit is contained in:
Oliver Hauff 2021-11-08 23:11:56 +01:00
parent 4df8aa98aa
commit 8aa3089f32
15 changed files with 779 additions and 82 deletions

View file

@ -23,7 +23,7 @@
<br />Version ACTIVE_APPNAME: <b>CURRENT_VERSION_TINKAPP</b>.
<div class="content_title2">Entwickler</div>
<div style=""></div>
<br />Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.<br />
<br />Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike<br />
<div class="content_title2">Verwendete Bibliotheken</div>
<div style=""></div>
<br /><table>

View file

@ -23,7 +23,7 @@
<br />Version ACTIVE_APPNAME: <b>CURRENT_VERSION_TINKAPP</b>.
<div class="content_title2">Entwickler</div>
<div style=""></div>
<br />Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.<br />
<br />Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike<br />
<div class="content_title2">Verwendete Bibliotheken</div>
<div style=""></div>
<br /><table>

View file

@ -23,7 +23,7 @@
<br />Version ACTIVE_APPNAME: <b>CURRENT_VERSION_TINKAPP</b>.
<div class="content_title2">Entwickler</div>
<div style=""></div>
<br />Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.<br />
<br />Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike<br />
<div class="content_title2">Verwendete Bibliotheken</div>
<div style=""></div>
<br /><table>

View file

@ -36,36 +36,36 @@ namespace TINK.Model.Connector
/// If communication fails an exception is thrown.
/// </summary>
public async Task<IAccount> DoLogin(
string p_strMail,
string p_strPassword,
string p_strDeviceId)
string mail,
string password,
string deviceId)
{
if (string.IsNullOrEmpty(p_strMail))
if (string.IsNullOrEmpty(mail))
{
throw new ArgumentNullException("Can not loging user. Mail address must not be null or empty.");
}
if (string.IsNullOrEmpty(p_strPassword))
if (string.IsNullOrEmpty(password))
{
throw new ArgumentNullException("Can not loging user. Password must not be null or empty.");
}
if (string.IsNullOrEmpty(p_strDeviceId))
if (string.IsNullOrEmpty(deviceId))
{
throw new ArgumentNullException("Can not loging user. Device not be null or empty.");
}
AuthorizationResponse l_oResponse;
AuthorizationResponse response;
try
{
l_oResponse = (await CopriServer.DoAuthorizationAsync(p_strMail, p_strPassword, p_strDeviceId)).GetIsResponseOk(p_strMail);
response = (await CopriServer.DoAuthorizationAsync(mail, password, deviceId)).GetIsResponseOk(mail);
}
catch (System.Exception)
{
throw;
}
var l_oAccount = l_oResponse.GetAccount(MerchantId, p_strMail, p_strPassword);
var l_oAccount = response.GetAccount(MerchantId, mail, password);
// Log in state changes. Notify parent object to update.
LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs(l_oAccount.SessionCookie, l_oAccount.Mail));
@ -83,9 +83,9 @@ namespace TINK.Model.Connector
/// <summary>
/// Request to reserve a bike.
/// </summary>
/// <param name="p_oBike">Bike to book.</param>
/// <param name="bike">Bike to book.</param>
public async Task DoReserve(
Bikes.Bike.BC.IBikeInfoMutable p_oBike)
Bikes.Bike.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
await Task.CompletedTask;

View file

@ -5,12 +5,13 @@ namespace TINK.Model.Connector
public static class FilteredConnectorFactory
{
/// <summary> Creates a filter object. </summary>
/// <param name="group"></param>
/// <param name="group">Filter to apply on stations and bikes.</param>
/// <param name="connector">Connector to connect to COPRI.</param>
public static IFilteredConnector Create(IEnumerable<string> group, IConnector connector)
{
return group != null
? (IFilteredConnector) new FilteredConnector(group, connector)
: new NullFilterConnector(connector);
: new NullFilterConnector(connector); // Do not apply filtering.
}
}
}

View file

@ -91,7 +91,7 @@ namespace TINK.Model.Connector
{
if (loginResponse == null)
{
throw new ArgumentNullException("p_oLoginResponse");
throw new ArgumentNullException(nameof(loginResponse));
}
return new Account(
@ -165,13 +165,13 @@ namespace TINK.Model.Connector
}
/// <summary> Gets bikes available from copri server response.</summary>
/// <param name="p_oBikesAvailableResponse">Response to create collection from.</param>
/// <param name="bikesAvailableResponse">Response to create collection from.</param>
/// <returns>New collection of available bikes.</returns>
public static BikeCollection GetBikesAvailable(
this BikesAvailableResponse p_oBikesAvailableResponse)
this BikesAvailableResponse bikesAvailableResponse)
{
return GetBikesAll(
p_oBikesAvailableResponse,
bikesAvailableResponse,
new BikesReservedOccupiedResponse(), // There are no occupied bikes.
string.Empty,
() => DateTime.Now);
@ -198,8 +198,8 @@ namespace TINK.Model.Connector
public static BikeCollection GetBikesAll(
BikesAvailableResponse bikesAvailableResponse,
BikesReservedOccupiedResponse bikesOccupiedResponse,
string p_strMail,
Func<DateTime> p_oDateTimeProvider)
string mail,
Func<DateTime> dateTimeProvider)
{
var bikesDictionary = new Dictionary<string, BikeInfo>();
var duplicates = new Dictionary<string, BikeInfo>();
@ -242,8 +242,8 @@ namespace TINK.Model.Connector
{
BikeInfo bikeInfo = BikeInfoFactory.Create(
bikeInfoResponse,
p_strMail,
p_oDateTimeProvider);
mail,
dateTimeProvider);
if (bikeInfo == null)
{

View file

@ -147,7 +147,7 @@ namespace TINK.Model
public TinkApp(
Settings.Settings settings,
IStore accountStore,
Func<bool, Uri, string, string, TimeSpan, IConnector> connectorFactory,
Func<bool, Uri, string /* session cookie*/, string /* mail address*/, TimeSpan, IConnector> connectorFactory,
IServicesContainer<IGeolocation> geolocationServicesContainer,
ILocksService locksService,
ISmartDevice device,

View file

@ -6,12 +6,12 @@ namespace TINK.Model.User.Account
public static class AccountExtensions
{
/// <summary> Gets information whether user is logged in or not from account object. </summary>
/// <param name="p_oAccount">Object to get information from.</param>
/// <param name="account">Object to get information from.</param>
/// <returns>True if user is logged in, false if not.</returns>
public static bool GetIsLoggedIn(this IAccount p_oAccount)
public static bool GetIsLoggedIn(this IAccount account)
{
return !string.IsNullOrEmpty(p_oAccount.Mail)
&& !string.IsNullOrEmpty(p_oAccount.SessionCookie);
return !string.IsNullOrEmpty(account.Mail)
&& !string.IsNullOrEmpty(account.SessionCookie);
}
/// <summary>

View file

@ -12,10 +12,6 @@ namespace TINK.Model.User.Account
/// </summary>
private Account m_oAccount;
/// <summary> Prevents an invalid instance to be created. </summary>
private AccountMutable()
{
}
public AccountMutable(IAccount p_oSource)
{

View file

@ -13,15 +13,13 @@ namespace TINK.Model.User
/// </summary>
public class User : IUser
{
/// <summary>
/// Holds account data.
/// </summary>
private readonly AccountMutable m_oAccount;
/// <summary> Holds account data. </summary>
private AccountMutable Account { get; }
/// <summary>
/// Provides storing functionality.
/// </summary>
private IStore m_oStore;
private IStore Store { get; }
/// <summary> Holds the id of the device. </summary>
public string DeviceId { get; }
@ -34,10 +32,10 @@ namespace TINK.Model.User
IAccount account,
string deviceId)
{
m_oStore = accountStore
Store = accountStore
?? throw new ArgumentException("Can not instantiate user- object. No store functionality available.");
DeviceId = deviceId;
m_oAccount = new AccountMutable(account);
Account = new AccountMutable(account);
}
/// <summary> Is fired wheneverlogin state changes. </summary>
@ -46,19 +44,14 @@ namespace TINK.Model.User
/// <summary>
/// Holds a value indicating whether user is logged in or not.
/// </summary>
public bool IsLoggedIn {
get
{
return m_oAccount.GetIsLoggedIn();
}
}
public bool IsLoggedIn => Account.GetIsLoggedIn();
/// <summary>
/// Holds the mail address.
/// </summary>
public string Mail
{
get { return m_oAccount.Mail; }
get { return Account.Mail; }
}
/// <summary>
@ -66,24 +59,24 @@ namespace TINK.Model.User
/// </summary>
public string SessionCookie
{
get { return m_oAccount.SessionCookie; }
get { return Account.SessionCookie; }
}
/// <summary>
/// Holds the password.
/// </summary>
public string Password
{
get { return m_oAccount.Pwd; }
get { return Account.Pwd; }
}
/// <summary>Holds the debug level.</summary>
public Permissions DebugLevel
{
get { return m_oAccount.DebugLevel; }
get { return Account.DebugLevel; }
}
/// <summary> Holds the group of the bike (TINK, Konrad, ...).</summary>
public IEnumerable<string> Group { get { return m_oAccount.Group; } }
public IEnumerable<string> Group { get { return Account.Group; } }
/// <summary> Logs in user. </summary>
/// <param name="p_oAccount">Account to use for login.</param>
@ -93,7 +86,7 @@ namespace TINK.Model.User
{
if (IsLoggedIn)
{
throw new Exception($"Can not log in user {mail} because user {m_oAccount} is already logged in.");
throw new Exception($"Can not log in user {mail} because user {Account} is already logged in.");
}
// Check if password might be valid before connecting to copri.
@ -113,10 +106,10 @@ namespace TINK.Model.User
public async Task Login(IAccount account)
{
// Update account instance from copri data.
m_oAccount.Copy(account);
Account.Copy(account);
// Save data to store.
await m_oStore.Save(m_oAccount);
await Store.Save(Account);
// Nothing to do because state did not change.
StateChanged?.Invoke(this, new EventArgs());
@ -128,7 +121,7 @@ namespace TINK.Model.User
{
var l_oPreviousState = IsLoggedIn;
m_oAccount.Copy(m_oStore.Delete(m_oAccount));
Account.Copy(Store.Delete(Account));
if (IsLoggedIn == l_oPreviousState)
{
@ -144,11 +137,11 @@ namespace TINK.Model.User
/// Some user may be "TINK"- user only, some "Konrad" and some may be "TINK" and "Konrad" users.
/// </summary>
/// <param name="p_oAccount">Account to filter with.</param>
/// <param name="p_oSource">Groups to filter..</param>
/// <param name="source">Groups to filter..</param>
/// <returns>Filtered bike groups.</returns>
public IEnumerable<string> DoFilter(IEnumerable<string> p_oSource = null)
public IEnumerable<string> DoFilter(IEnumerable<string> source = null)
{
return m_oAccount.DoFilter(p_oSource);
return Account.DoFilter(source);
}
}
}

View file

@ -1264,7 +1264,7 @@ namespace TINK.Repository
}
}";
private const SampleSets DEFAULT_SAMPLE_SET = SampleSets.Set2;
private const SampleSets DEFAULT_SAMPLE_SET = SampleSets.Set2;
private const int DEFAULT_STAGE_INDEX = 1;

View file

@ -2,9 +2,7 @@
using System;
using TINK.Model;
using TINK.Model.Connector;
using TINK.Repository;
using TINK.Model.Services.CopriApi.ServerUris;
using static TINK.Repository.CopriCallsMemory;
using TINK.Services;
using NSubstitute;
using TINK.Model.Services.Geolocation;
@ -12,8 +10,8 @@ using TINK.Services.BluetoothLock;
using TINK.Model.Device;
using TINK.Model.User.Account;
using Plugin.Permissions.Abstractions;
using System.Threading.Tasks;
using System.Collections.Generic;
using TestShareeLib.Repository;
namespace TestTINKLib.Fixtures.UseCases.Logout
{
@ -32,9 +30,8 @@ namespace TestTINKLib.Fixtures.UseCases.Logout
accountStore.Load().Returns(account);
account.Mail.Returns("javaminister@gmail.com");
account.Pwd.Returns("javaminister");
account.SessionCookie.Returns("4da3044c8657a04ba60e2eaa753bc51a");
account.Group.Returns(new List<string> { "TINK" });
account.Pwd.Returns("*********");
account.SessionCookie.Returns("6103_112e96b36ba33de245943c5ffaf369cd_");
// No user logged in is initial state to verify.
var l_oTinkApp = new TinkApp(
@ -44,8 +41,8 @@ namespace TestTINKLib.Fixtures.UseCases.Logout
activeUri: new Uri(CopriServerUriList.TINK_DEVEL)),
accountStore,
(isConnected, uri, sessionCookie, mail, expiresAfter) => string.IsNullOrEmpty(sessionCookie)
? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1))
: new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001())
: new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001(sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
locksService,
device,
@ -57,17 +54,29 @@ namespace TestTINKLib.Fixtures.UseCases.Logout
lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to
Assert.IsTrue(l_oTinkApp.ActiveUser.IsLoggedIn);
Assert.AreEqual(13, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count);
Assert.AreEqual(2, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count);
Assert.AreEqual("4da3044c8657a04ba60e2eaa753bc51a", l_oTinkApp.GetConnector(true).Command.SessionCookie);
// There are 6 bikes available and 2, one reserved and one rented by javaminsiter.
Assert.AreEqual(
8,
l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count,
"Sum of bikes is 6 occupied plus 2 occupied.");
Assert.AreEqual(2,
l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count,
"Javaminster occupies 2 bikes.");
Assert.AreEqual("6103_112e96b36ba33de245943c5ffaf369cd_", l_oTinkApp.GetConnector(true).Command.SessionCookie);
// Log user out.
l_oTinkApp.GetConnector(true).Command.DoLogout().Wait();
l_oTinkApp.ActiveUser.Logout();
Assert.IsFalse(l_oTinkApp.ActiveUser.IsLoggedIn);
Assert.AreEqual(11, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count);
Assert.AreEqual(0, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count);
Assert.AreEqual(
6,
l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count,
"Sum of bikes is 6 occupied, no one occupied because no user is logged in");
Assert.AreEqual(
0,
l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count,
"If no user is logged in no occupied bikes are shown.");
Assert.IsNull(l_oTinkApp.GetConnector(true).Command.SessionCookie);
}
}

View file

@ -13,10 +13,10 @@ using TINK.Model.Device;
using TINK.Model.User.Account;
using Plugin.Permissions.Abstractions;
using System.Threading.Tasks;
using TestShareeLib.Repository;
namespace TestTINKLib.Fixtures.UseCases.Login
{
[TestFixture]
public class TestTinkApp
{
@ -37,8 +37,8 @@ namespace TestTINKLib.Fixtures.UseCases.Login
activeUri: new Uri(CopriServerUriList.TINK_DEVEL)),
accountStore,
(isConnected, uri, sessionCookie, mail, expiresAfter) => string.IsNullOrEmpty(sessionCookie)
? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1)) as IConnector
: new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001()) as IConnector
: new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001(sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
locksService,
device,
@ -50,18 +50,30 @@ namespace TestTINKLib.Fixtures.UseCases.Login
lastVersion: new Version(3, 0, 173) /* Current app version. Must be larger or equal 3.0.173 to lastVersion*/);
Assert.IsFalse(l_oTinkApp.ActiveUser.IsLoggedIn);
Assert.AreEqual(11, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count);
Assert.AreEqual(0, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count);
Assert.AreEqual(
6,
l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count,
"Sum of bikes is 6 occupied, no one occupied because no user is logged in");
Assert.AreEqual(
0,
l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count,
"If no user is logged in no occupied bikes are shown.");
Assert.IsNull(l_oTinkApp.GetConnector(true).Command.SessionCookie);
// Log user out.
var l_oAccount = l_oTinkApp.GetConnector(true).Command.DoLogin("javaminister@gmail.com", "javaminister", "HwId1000000000000").Result;
var l_oAccount = l_oTinkApp.GetConnector(true).Command.DoLogin("javaminister@gmail.com", "*********", "HwId1000000000000").Result;
await l_oTinkApp.ActiveUser.Login(l_oAccount);
Assert.IsTrue(l_oTinkApp.ActiveUser.IsLoggedIn);
Assert.AreEqual(13, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count);
Assert.AreEqual(2, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count);
Assert.AreEqual("4da3044c8657a04ba60e2eaa753bc51a", l_oTinkApp.GetConnector(true).Command.SessionCookie);
Assert.AreEqual(
8,
l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count,
"Sum of bikes is 6 occupied plus 2 occupied.");
Assert.AreEqual(
2,
l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count,
"Javaminster occupies 2 bikes.");
Assert.AreEqual("6103_112e96b36ba33de245943c5ffaf369cd_", l_oTinkApp.GetConnector(true).Command.SessionCookie);
}
}
}

View file

@ -0,0 +1,283 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TINK.Model;
using TINK.Model.Device;
using TINK.Repository;
using TINK.Repository.Request;
using TINK.Repository.Response;
namespace TestShareeLib.Repository
{
/// <summary> Provides functionality for keeping a set of COPRI responses. </summary>
public abstract class CopriCallMemoryBase
{
private string BikesAvailableResponse { get; }
private string BikesOccupiedResponse { get; }
private string AuthResponse { get; }
private string AuthOutResponse { get; }
private string Stations { get; }
private string BookingRequestResponse { get; }
private string CancelBookingRequestResponse { get; }
private IRequestBuilder requestBuilder;
public CopriCallMemoryBase(
string bikesAvailableResponse = null,
string bikesOccupiedResponse = null,
string authResponse = null,
string authOutResponse = null,
string stations = null,
string bookingRequestResponse = null,
string cancelBookingRequestResponse = null,
string sessionCookie = null)
{
SessionCookie = sessionCookie;
BikesAvailableResponse = bikesAvailableResponse;
BikesOccupiedResponse = bikesOccupiedResponse;
AuthResponse = authResponse;
AuthOutResponse = authOutResponse;
BookingRequestResponse = bookingRequestResponse;
CancelBookingRequestResponse = cancelBookingRequestResponse;
Stations = stations;
requestBuilder = string.IsNullOrEmpty(sessionCookie)
? new RequestBuilder(MerchantId) as IRequestBuilder
: new RequestBuilderLoggedIn(MerchantId, sessionCookie);
}
/// <summary> Holds the session id of the logged in user, null otherwise. </summary>
public string SessionCookie { get; private set; }
/// <summary> Logs user in. </summary>
/// <param name="p_oUser">User to log in.</param>
/// <param name="deviceId">Id specifying user and hardware.</param>
/// <param name="mailAddress">Mailaddress of user to log in.</param>
/// <param name="password">Password to log in.</param>
/// <remarks>Response which holds auth cookie <see cref="ResponseBase.authcookie"/></remarks>
public async Task<AuthorizationResponse> DoAuthorizationAsync(
string mailAddress,
string password,
string deviceId)
=> await Task.Run(() => DoAuthorize(AuthResponse, mailAddress, password, deviceId));
/// <summary> Logs user out. </summary>
/// <param name="sessionCookie">User to log in.</param>
/// <remarks>Response which holds auth cookie <see cref="ResponseBase.authcookie"/></remarks>
public async Task<AuthorizationoutResponse> DoAuthoutAsync()
=> await Task.Run(() => DoAuthout(AuthOutResponse, SessionCookie));
/// <summary>
/// Gets list of bikes from memory.
/// </summary>
/// <returns></returns>
public async Task<BikesAvailableResponse> GetBikesAvailableAsync()
=> await Task.Run(() => GetBikesAvailable(BikesAvailableResponse, null, SessionCookie));
/// <summary>
/// Gets a list of bikes reserved/ booked by acctive user from Copri.
/// </summary>
/// <param name="p_strSessionCookie">Cookie to authenticate user.</param>
/// <returns>Response holding list of bikes.</returns>
public async Task<BikesReservedOccupiedResponse> GetBikesOccupiedAsync()
{
try
{
requestBuilder.GetBikesOccupied(); // Non mock implementation if ICopriServer call this member as well. To ensure comparable behaviour this member is called here as well.
}
catch (NotSupportedException)
{
// No user logged in.
await Task.CompletedTask;
return ResponseHelper.GetBikesOccupiedNone();
}
return await Task.Run(() => GetBikesOccupied(BikesOccupiedResponse, SessionCookie));
}
/// <summary>
/// Get list of stations from file.
/// </summary>
/// <param name="p_strCookie">Auto cookie of user if user is logged in.</param>
/// <returns>List of files.</returns>
public async Task<StationsAvailableResponse> GetStationsAsync()
=> await Task.Run(() => GetStationsAll(Stations, null, SessionCookie));
/// <summary>
/// Gets booking request response.
/// </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <returns>Booking response.</returns>
public async Task<ReservationBookingResponse> DoReserveAsync(string bikeId, Uri operatorUri)
=> await Task.Run(() => DoReserve(BookingRequestResponse, bikeId, SessionCookie));
/// <summary>
/// Gets canel booking request response.
/// </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="p_strCookie">Cookie of the logged in user.</param>
/// <returns>Response on cancel booking request.</returns>
public async Task<ReservationCancelReturnResponse> DoCancelReservationAsync(string bikeId, Uri operatorUri)
=> await Task.Run(() => DoCancelReservation(CancelBookingRequestResponse, bikeId, SessionCookie));
/// <summary> Gets the merchant id.</summary>
public string MerchantId => TinkApp.MerchantId;
/// <summary> Returns false because cached values are returned. </summary>
public bool IsConnected => false;
/// <summary> Logs user in. </summary>
/// <param name="p_oUser">User to log in.</param>
/// <param name="p_strDeviceId">Id specifying user and hardware.</param>
/// <param name="p_strMailAddress">Mailaddress of user to log in.</param>
/// <param name="p_strPassword">Password to log in.</param>
/// <remarks>Response which holds auth cookie <see cref="ResponseBase.authcookie"/></remarks>
public static AuthorizationResponse DoAuthorize(
string DoAuthResponse,
string p_strMailAddress,
string p_strPassword,
string p_strDeviceId)
{
return p_strMailAddress == "javaminister@gmail.com"
&& p_strPassword == "*********" &&
p_strDeviceId == "HwId1000000000000"
? JsonConvertRethrow.DeserializeObject<ResponseContainer<AuthorizationResponse>>(DoAuthResponse).shareejson
: JsonConvertRethrow.DeserializeObject<ResponseContainer<AuthorizationResponse>>(DO_AUTH_Unknown_User_FILE).shareejson;
}
/// <summary> Logs user in. </summary>
/// <remarks>Response which holds auth cookie <see cref="ResponseBase.authcookie"/></remarks>
public static AuthorizationoutResponse DoAuthout(
string authOutResponse,
string sessionCookie)
{
// Response contains auth cookie of user "JavaministerHardwareNr1"
// For this reason do not return answer if mail and pwd do not match.
return !string.IsNullOrEmpty(sessionCookie)
? JsonConvertRethrow.DeserializeObject<ResponseContainer<AuthorizationoutResponse>>(authOutResponse).shareejson
: throw new NotSupportedException();
}
/// <summary>
/// Gets list of bikes from memory.
/// </summary>
/// <param name="p_strMerchantId">Id of the merchant.</param>
/// <param name="p_strSessionCookie">Auto cookie of user if user is logged in.</param>
/// <param name="p_eSampleSet">Set of samples.</param>
/// <param name="p_lStageIndex">Index of the stage.</param>
/// <returns></returns>
public static BikesAvailableResponse GetBikesAvailable(
string BikesAvailableResponse,
string p_strMerchantId,
string p_strSessionCookie = null) => CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BikesAvailableResponse);
/// <summary>
/// Gets stations response.
/// </summary>
/// <param name="merchantId">Id of the merchant.</param>
/// <param name="cookie">Auto cookie of user if user is logged in.</param>
/// <param name="p_eSampleSet"></param>
/// <param name="p_lStageIndex"></param>
/// <returns></returns>
public static StationsAvailableResponse GetStationsAll(
string stations,
string merchantId,
string cookie = null)
=> JsonConvertRethrow.DeserializeObject<ResponseContainer<StationsAvailableResponse>>(stations).shareejson;
/// <summary>
/// Gets booking request response.
/// </summary>
/// <param name="bikeId">Id of the bike.</param>
/// <param name="sessionCookie">Identifies the logged in user.</param>
/// <param name="sampleSet">Sample set to use.</param>
/// <param name="stageIndex">Index of the stage.</param>
/// <returns></returns>
public static ReservationBookingResponse DoReserve(
string bookingRequestResponse,
string bikeId,
string sessionCookie)
=> JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(bookingRequestResponse).shareejson;
/// <summary>
/// Gets canel booking request response.
/// </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="cookie">Cookie of the logged in user.</param>
/// <returns>Response on cancel booking request.</returns>
public static ReservationCancelReturnResponse DoCancelReservation(
string cancelBookingRequestResponse,
string bikeId,
string cookie)
=> JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationCancelReturnResponse>>(cancelBookingRequestResponse).shareejson;
public Task<ReservationBookingResponse> CalculateAuthKeysAsync(string bikeId, Uri operatorUri)
=> null;
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
string bikeId,
LocationDto geolocation,
lock_state state,
double batteryLevel,
Uri operatorUri)
=> null;
public Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
=> null;
public Task<ReservationCancelReturnResponse> DoReturn(
string bikeId,
LocationDto geolocation,
ISmartDevice smartDevice,
Uri operatorUri)
=> null;
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri)
=> null;
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
public Task<ResponseBase> DoSubmitMiniSurvey(IDictionary<string, string> answers)
=> null;
/// <summary>
/// Gets a list of bikes reserved/ booked by acctive user from Copri.
/// </summary>
/// <param name="sessionCookie">Cookie to authenticate user.</param>
/// <param name="SampleSet">Sample set to use.</param>
/// <param name="p_lStageIndex">Index of the stage.</param>
/// <returns>Response holding list of bikes.</returns>
public static BikesReservedOccupiedResponse GetBikesOccupied(
string bikesOccupied,
string sessionCookie = null)
{
var response = CopriCallsStatic.DeserializeResponse<BikesReservedOccupiedResponse>(bikesOccupied);
return sessionCookie != null && (response?.authcookie?.Contains(sessionCookie) ?? false)
? response
: ResponseHelper.GetBikesOccupiedNone(sessionCookie);
}
public const string DO_AUTH_Unknown_User_FILE = @"
{
""shareejson"" : {
""response"" : ""authorization"",
""authcookie"" : 0,
""response_state"" : ""Failure: cannot generate authcookie"",
""apiserver"" : ""https://tinkwwp.copri-bike.de""
}
}";
}
}

View file

@ -0,0 +1,403 @@
using TINK.Repository;
namespace TestShareeLib.Repository
{
/// <summary>
/// Holds some COPRI responses for testing purposes.
/// </summary>
/// <remarks> Holds some demo Meinkonrad and LastenradBayern bikes
/// </remarks>
public class CopriCallsMemory001 : CopriCallMemoryBase, ICopriServer
{
public CopriCallsMemory001(string sessionCookie = null) : base(
bikesAvailableResponse: BikesAvailableResponse,
bikesOccupiedResponse: BikesOccupiedResponse,
authResponse: AuthResponse,
authOutResponse: AuthOutResponse,
sessionCookie: sessionCookie)
{ }
private static string AuthResponse => @"{
""shareejson"": {
""clearing_cache"": ""0"",
""privacy_html"": ""site/privacy.html"",
""user_id"": ""javaminister@gmail.com"",
""impress_html"": ""site/impress.html"",
""tariff_info_html"": ""site/tariff_info_1.html"",
""lang"": ""DE"",
""last_used_operator"": {
""operator_name"": ""sharee.bike | TeilRad GmbH"",
""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
""operator_phone"": ""+49 761 45370097"",
""operator_email"": ""hotline@sharee.bike"",
""operator_color"": ""#009699""
},
""response"": ""authorization"",
""agb_checked"": ""0"",
""agb_html"": ""site/agb.html"",
""response_text"": ""Herzlich willkommen im Fahrradmietsystem"",
""bike_info_html"": ""site/bike_info.html"",
""debuglevel"": ""1"",
""uri_primary"": ""https://shareeapp-primary.copri.eu"",
""response_state"": ""OK, nothing todo"",
""new_authcoo"": ""1"",
""user_tour"": [],
""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"",
""copri_version"": ""4.1.8.21"",
""apiserver"": ""https://shareeapp-fr01.copri.eu"",
""user_group"": []
}
}";
private static string AuthOutResponse = @"{
""shareejson"": {
""copri_version"": ""4.1.8.21"",
""authcookie"": ""1"",
""user_tour"": [],
""user_group"": null,
""apiserver"": ""https://shareeapp-fr01.copri.eu"",
""debuglevel"": ""1"",
""uri_primary"": ""https://shareeapp-primary.copri.eu"",
""bike_info_html"": ""site/bike_info.html"",
""response_state"": ""OK, logout"",
""new_authcoo"": ""0"",
""lang"": ""DE"",
""last_used_operator"": {
""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
""operator_name"": ""sharee.bike | TeilRad GmbH"",
""operator_email"": ""hotline@sharee.bike"",
""operator_phone"": ""+49 761 45370097"",
""operator_color"": ""#009699""
},
""tariff_info_html"": ""site/tariff_info_1.html"",
""impress_html"": ""site/impress.html"",
""response_text"": ""Auf Wiedersehen."",
""agb_html"": ""site/agb.html"",
""response"": ""authout"",
""agb_checked"": ""0"",
""privacy_html"": ""site/privacy.html"",
""clearing_cache"": ""0"",
""user_id"": ""javaminister@gmail.com""
}
}";
private static string BikesOccupiedResponse => @"{
""shareejson"": {
""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"",
""copri_version"": ""4.1.8.21"",
""user_tour"": [],
""user_group"": [
""FR300103"",
""FR300101""
],
""bikes_occupied"": {
""157056"": {
""K_seed"": ""[-20, -104, -112, -49, 3, -74, -43, -115, -53, 34, -48, -29, -64, -90, -26, -74]"",
""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
""bike"": ""FR1544"",
""unit_price"": ""3.00"",
""description"": ""Contributor-Paul"",
""station"": ""FR103"",
""request_time"": ""2021-11-06 18:57:20.034438+01"",
""Ilockit_ID"": ""ISHAREIT-2200544"",
""total_price"": ""25.50"",
""bike_group"": [
""FR300103""
],
""K_u"": ""[43, -16, 72, -5, 23, -117, 43, 57, 124, -106, -115, 97, -93, -30, -34, -7, -21, 119, 109, 92, 0, 0, 0, 0]"",
""computed_hours"": ""8.50"",
""end_time"": ""2021-11-08 21:14:35"",
""state"": ""occupied"",
""tariff_description"": {
""eur_per_hour"": ""3.00"",
""number"": ""5494"",
""max_eur_per_day"": ""10.00"",
""name"": ""Tester Basic"",
""free_hours"": ""0.50"",
""track_info"": ""Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!"",
""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html'>AGB</a> zugestimmt (als Demo sharee AGB).""
},
""lock_state"": ""locked"",
""system"": ""Ilockit"",
""gps"": {
""latitude"": ""47.9994661873206"",
""longitude"": ""7.7904340904206""
},
""real_hours"": ""50.2833333333333"",
""Ilockit_GUID"": ""00000000-0000-0000-0000-dc969f648732"",
""start_time"": ""2021-11-06 18:57:25.445447+01""
},
""157072"": {
""bike"": ""FR1004"",
""K_seed"": ""[-31, -81, -41, 95, 112, -113, -78, -22, 84, -112, -73, 31, -125, -49, 125, 10]"",
""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
""bike_group"": [
""FR300103""
],
""total_price"": ""0.00"",
""description"": ""Contributor-Recumbent"",
""station"": ""FR103"",
""request_time"": ""2021-11-08 21:10:24.829395+01"",
""Ilockit_ID"": ""ISHAREIT-2302373"",
""unit_price"": ""3.00"",
""end_time"": ""2021-11-08 21:10:00+01"",
""state"": ""requested"",
""tariff_description"": {
""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html'>AGB</a> zugestimmt (als Demo sharee AGB)."",
""free_hours"": ""0.50"",
""name"": ""Tester Basic"",
""max_eur_per_day"": ""10.00"",
""eur_per_hour"": ""3.00"",
""number"": ""5494""
},
""computed_hours"": ""0"",
""K_u"": ""[126, -125, 125, 83, 104, -121, -80, 40, 77, -35, 81, 27, 89, -124, -37, 57, 118, -113, 71, -37, 0, 0, 0, 0]"",
""start_time"": ""2021-11-08 21:10:24.829395+01"",
""gps"": {
""latitude"": ""47.9980777"",
""longitude"": ""7.7848769""
},
""lock_state"": ""locked"",
""system"": ""Ilockit"",
""real_hours"": ""0"",
""Ilockit_GUID"": ""00000000-0000-0000-0000-fe3962c08bcc""
}
},
""apiserver"": ""https://shareeapp-fr01.copri.eu"",
""uri_primary"": ""https://shareeapp-primary.copri.eu"",
""debuglevel"": ""1"",
""bike_info_html"": ""site/bike_info.html"",
""new_authcoo"": ""0"",
""response_state"": ""OK, nothing todo"",
""last_used_operator"": {
""operator_color"": ""#008dd2"",
""operator_phone"": ""+49 089 / 111111111"",
""operator_email"": ""hotline@lastenraddemo.bayern"",
""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
""operator_name"": ""Lastenrad Bayern"",
""operator_logo"": """"
},
""lang"": ""DE"",
""impress_html"": ""site/impress.html"",
""tariff_info_html"": ""site/tariff_info_1.html"",
""agb_html"": ""site/agb.html"",
""response"": ""user_bikes_occupied"",
""agb_checked"": ""1"",
""privacy_html"": ""site/privacy.html"",
""clearing_cache"": ""0"",
""user_id"": ""ohauff@posteo.de""
}
}";
private static string BikesAvailableResponse => @"{
""shareejson"": {
""agb_checked"": ""1"",
""response"": ""bikes_available"",
""agb_html"": ""site/agb.html"",
""impress_html"": ""site/impress.html"",
""tariff_info_html"": ""site/tariff_info_1.html"",
""lang"": ""DE"",
""last_used_operator"": {
""operator_color"": ""#008dd2"",
""operator_email"": ""hotline@lastenraddemo.bayern"",
""operator_phone"": ""+49 089 / 111111111"",
""operator_name"": ""Lastenrad Bayern"",
""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
""operator_logo"": """"
},
""user_id"": ""ohauff@posteo.de"",
""clearing_cache"": ""0"",
""privacy_html"": ""site/privacy.html"",
""bikes"": {
""FR1543"": {
""system"": ""Ilockit"",
""gps"": {
""longitude"": ""7.8255321"",
""latitude"": ""47.9767121""
},
""lock_state"": ""locked"",
""Ilockit_GUID"": ""00000000-0000-0000-0000-cc141a6f68bb"",
""state"": ""available"",
""tariff_description"": {
""free_hours"": ""0.50"",
""name"": ""Tester Basic"",
""eur_per_hour"": ""3.00"",
""number"": ""5494"",
""1543"": {
""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html'>AGB</a> zugestimmt (als Demo sharee AGB).""
},
""max_eur_per_day"": ""10.00""
},
""bike_group"": [
""FR300103""
],
""station"": ""FR101"",
""description"": ""Contributor-bike Dominik"",
""Ilockit_ID"": ""ISHAREIT-2200543"",
""authed"": ""1"",
""bike"": ""FR1543"",
""uri_operator"": ""https://shareeapp-fr01.copri.eu""
},
""FR1003"": {
""bike"": ""FR1003"",
""authed"": ""1"",
""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
""bike_group"": [
""FR300101""
],
""Ilockit_ID"": ""ISHAREIT-2200545"",
""station"": ""FR101"",
""description"": ""Stadtrad"",
""tariff_description"": {
""max_eur_per_day"": ""10.00"",
""number"": ""5491"",
""eur_per_hour"": ""2.00"",
""1003"": {
""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html'>AGB</a> zugestimmt (als Demo sharee AGB).""
},
""free_hours"": ""0.50"",
""name"": ""Vauban Basic""
},
""state"": ""available"",
""Ilockit_GUID"": ""00000000-0000-0000-0000-e38bf9d32234"",
""system"": ""Ilockit"",
""gps"": {
""longitude"": ""7.8255772"",
""latitude"": ""47.9765188""
},
""lock_state"": ""locked""
},
""FR1540"": {
""bike_group"": [
""FR300103""
],
""Ilockit_ID"": ""ISHAREIT-2200540"",
""description"": ""Contributor-bike Dieter"",
""station"": ""FR101"",
""bike"": ""FR1540"",
""authed"": ""1"",
""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
""Ilockit_GUID"": ""00000000-0000-0000-0000-fc3c002a2add"",
""system"": ""Ilockit"",
""gps"": {
""longitude"": ""7.8256267"",
""latitude"": ""47.976803""
},
""lock_state"": ""locked"",
""tariff_description"": {
""1540"": {
""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html'>AGB</a> zugestimmt (als Demo sharee AGB).""
},
""free_hours"": ""0.50"",
""name"": ""Tester Basic"",
""max_eur_per_day"": ""10.00"",
""eur_per_hour"": ""3.00"",
""number"": ""5494""
},
""state"": ""available""
},
""FR1002"": {
""bike_group"": [
""FR300101""
],
""description"": ""Lasten-Dreirad"",
""station"": ""FR101"",
""Ilockit_ID"": ""ISHAREIT-2200539"",
""authed"": ""1"",
""bike"": ""FR1002"",
""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
""gps"": {
""latitude"": ""47.976552"",
""longitude"": ""7.8255068""
},
""system"": ""Ilockit"",
""lock_state"": ""locked"",
""Ilockit_GUID"": ""00000000-0000-0000-0000-f0b4a692e169"",
""state"": ""available"",
""tariff_description"": {
""max_eur_per_day"": ""10.00"",
""1002"": {
""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html'>AGB</a> zugestimmt (als Demo sharee AGB).""
},
""eur_per_hour"": ""2.00"",
""number"": ""5491"",
""free_hours"": ""0.50"",
""name"": ""Vauban Basic""
}
},
""FR1538"": {
""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
""authed"": ""1"",
""bike"": ""FR1538"",
""station"": ""FR105"",
""description"": ""Contributor-bike Rainer"",
""Ilockit_ID"": ""ISHAREIT-2200538"",
""bike_group"": [
""FR300103""
],
""state"": ""available"",
""tariff_description"": {
""max_eur_per_day"": ""10.00"",
""eur_per_hour"": ""3.00"",
""number"": ""5494"",
""1538"": {
""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html'>AGB</a> zugestimmt (als Demo sharee AGB).""
},
""free_hours"": ""0.50"",
""name"": ""Tester Basic""
},
""gps"": {
""latitude"": ""47.9275957"",
""longitude"": ""7.973976""
},
""lock_state"": ""locked"",
""system"": ""Ilockit"",
""Ilockit_GUID"": ""00000000-0000-0000-0000-db0319a2555b""
},
""FR1001"": {
""bike_group"": [
""FR300101""
],
""station"": ""FR101"",
""description"": ""Lastenrad"",
""Ilockit_ID"": ""ISHAREIT-2200536"",
""authed"": ""1"",
""bike"": ""FR1001"",
""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
""lock_state"": ""locked"",
""gps"": {
""latitude"": ""47.9765091"",
""longitude"": ""7.8255631""
},
""system"": ""Ilockit"",
""Ilockit_GUID"": ""00000000-0000-0000-0000-caa87760e53e"",
""state"": ""available"",
""tariff_description"": {
""free_hours"": ""0.50"",
""name"": ""Vauban Basic"",
""eur_per_hour"": ""2.00"",
""number"": ""5491"",
""max_eur_per_day"": ""10.00"",
""1001"": {
""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html'>AGB</a> zugestimmt (als Demo sharee AGB).""
}
}
}
},
""user_group"": [
""FR300103"",
""FR300101""
],
""apiserver"": ""https://shareeapp-fr01.copri.eu"",
""user_tour"": [],
""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"",
""copri_version"": ""4.1.8.21"",
""response_state"": ""OK, nothing todo"",
""new_authcoo"": ""0"",
""bike_info_html"": ""site/bike_info.html"",
""debuglevel"": ""1"",
""uri_primary"": ""https://shareeapp-primary.copri.eu""
}
}";
}
}