private async Task ProcessSubscription(AssetUpdateSubscriptionModel subscriptionModel) { try { //Get machines //https://3dproductivity.myvisionlink.com/t/trimble.com/vss-3dproductivity/2.0/projects/a530371d-20a1-40cf-99ce-e11c54140be4/machines var route = $"/projects/{subscriptionModel.ProjectUid}/machines"; var machines = await _productivity3dV2ProxyNotification.ExecuteGenericV2Request <Machine3DStatuses>(route, HttpMethod.Get, null, subscriptionModel.Headers()); if (machines.Code != ContractExecutionStatesEnum.ExecutedSuccessfully || !machines.MachineStatuses.Any()) { //Nothing to do here. Breaking. return; } var processingAssets = new List <Task>(); //Now for each machine try to identify a matching asset foreach (var machine in machines.MachineStatuses) { var task = ProcessAssetEvents(machine, subscriptionModel.ProjectUid, subscriptionModel.CustomerUid, subscriptionModel.Headers()); processingAssets.Add(task); } await Task.WhenAll(processingAssets); } catch (Exception e) { _log.LogError(e, $"Exception when running subscription {JsonConvert.SerializeObject(subscriptionModel)}"); } }
public async Task StartProcessingAssets(Guid projectUid) { // Handy for debugging, but not needed normally Logger.LogInformation($"Client requesting information for ProjectUID: {projectUid}"); var token = AuthorizationToken; var jwt = JwtAssertion; if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(jwt)) { throw new UnauthorizedAccessException("Missing Authentication Headers"); } // Do we need to check authentication here??? var model = new AssetUpdateSubscriptionModel() { AuthorizationHeader = token, JWTAssertion = jwt, CustomerUid = Guid.Parse(CustomerUid), ProjectUid = projectUid }; // SignalR needs to await tasks, note from Microsoft Site: // Use await when calling asynchronous methods that depend on the hub staying alive. For example, a method such as Clients.All.SendAsync(...) can fail if it's called without await and the hub method completes before SendAsync finishes. await assetState.AddSubscription(Context.ConnectionId, model); }
/// <inheritdoc /> public Task AddSubscription(string clientIdentifier, AssetUpdateSubscriptionModel model) { lock (lockObj) { // Remove it it exists, a connection can only subscribe to one project // (multiple browsers will have multiple connections) connectionMapping.Remove(clientIdentifier); connectionMapping.Add(clientIdentifier, model); } return(Task.CompletedTask); }
public void TestProcessing3dand2dAssets() { var job = serviceProvider.GetService <IJob>(); Assert.IsNotNull(job); var subscription = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("7842662B-F8E5-4752-A64B-261CE7EDA152"), CustomerUid = Guid.Parse("8BB0D3A3-A755-4AD9-A4FA-999D6C1C104C"), AuthorizationHeader = "TEST AUTH", JWTAssertion = "TEST JWT" }; var assetUid = "47C03885-4845-4637-90B5-4CCE5D8DA040"; var machine = new MachineStatus(55743, "Test Machine from 3d", true, "LAST DESIGN FROM 3D", 15215, new DateTime(2018, 1, 2, 3, 4, 5, DateTimeKind.Utc), 0.59915074193701334, // radians -1.470376021323053, // radians null, null, Guid.Parse(assetUid)); var machineResult = new Machine3DStatuses(ContractExecutionStatesEnum.ExecutedSuccessfully); machineResult.MachineStatuses.Add(machine); var assetDetails = new AssetDetails() { AssetId = "55743 - test", AssetUid = assetUid, LastReportedLocationLatitude = 123.45d, LastReportedLocationLongitude = 43.1d, LastLocationUpdateUtc = machine.lastKnownTimeStamp.Value.AddSeconds(1), FuelLevelLastReported = 2.1d, LastPercentFuelRemainingUtc = new DateTime(2019, 1, 1, 23, 41, 23, DateTimeKind.Utc) }; var expectedResult = new AssetAggregateStatus() { CustomerUid = subscription.CustomerUid, ProjectUid = subscription.ProjectUid, LocationLastUpdatedUtc = assetDetails.LastLocationUpdateUtc.ToUniversalTime(), AssetUid = Guid.Parse(assetUid), Design = machine.lastKnownDesignName, FuelLevel = assetDetails.FuelLevelLastReported, FuelLevelLastUpdatedUtc = assetDetails.FuelReportedTimeUtc, Latitude = assetDetails.LastReportedLocationLatitude, Longitude = assetDetails.LastReportedLocationLongitude, LiftNumber = 15215, AssetIdentifier = "55743 - test", // will take this from the 2d data, as a higher priority that the 3d machine name MachineName = "Test Machine from 3d" }; var expectedHeaders = GetExpectedHeaders(subscription.CustomerUid, subscription.AuthorizationHeader, subscription.JWTAssertion); AssetAggregateStatus resultStatus = null; // Keep a reference to the event generated for comparasion // Setup the returns mockAssetStatusServerHubClient .Setup(m => m.GetSubscriptions()) .Returns(Task.FromResult(new List <AssetUpdateSubscriptionModel> { subscription })); mockProductivity3dV2ProxyNotification.Setup(m => m.ExecuteGenericV2Request <Machine3DStatuses>( It.IsAny <string>(), It.IsAny <HttpMethod>(), It.IsAny <Stream>(), It.IsAny <IHeaderDictionary>())) .Returns(Task.FromResult(machineResult)); mockFleetAssetDetails .Setup(m => m.GetAssetDetails( It.IsAny <string>(), It.IsAny <IHeaderDictionary>())) .Returns(Task.FromResult(assetDetails)); mockAssetStatusServerHubClient .Setup(m => m.UpdateAssetLocationsForClient(It.IsAny <AssetAggregateStatus>())) .Returns(Task.FromResult(true)) .Callback <AssetAggregateStatus>((e) => { resultStatus = e; }); // Run the test job.Run(null).Wait(); // Validate the calls // We should have this called for our asset uid which matched to the 3d asset id mockFleetAssetDetails .Verify(m => m.GetAssetDetails( It.Is <string>(s => Guid.Parse(s) == Guid.Parse(assetDetails.AssetUid)), It.Is <IHeaderDictionary>(d => DictionaryContentEquals(d, expectedHeaders))), Times.Once); // We should have received one event mockAssetStatusServerHubClient .Verify(m => m.UpdateAssetLocationsForClient(It.IsAny <AssetAggregateStatus>()), Times.Once()); // Validate it is the expected result Assert.IsNotNull(resultStatus); resultStatus.Should().BeEquivalentTo(expectedResult); }
public void TestProcessing3dAssetsOnly() { var job = serviceProvider.GetService <IJob>(); Assert.IsNotNull(job); var subscription = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("038A3ACB-C985-4E3A-AB98-FF3C939B30BF"), CustomerUid = Guid.Parse("12DCFAF5-96A4-4E27-BE53-28A226A7AAB6"), AuthorizationHeader = "TEST AUTH", JWTAssertion = "TEST JWT" }; var machine1 = new MachineStatus(123, "Test Machine1", true, "LAST DESIGN 1", 6433, new DateTime(2010, 1, 2, 3, 4, 5, DateTimeKind.Utc), 0.59915074193701334, // radians -1.470376021323053, // radians null, null); var machineResult = new Machine3DStatuses(ContractExecutionStatesEnum.ExecutedSuccessfully); machineResult.MachineStatuses.Add(machine1); var expectedResult = new AssetAggregateStatus() { AssetIdentifier = "Test Machine1", LiftNumber = 6433, CustomerUid = subscription.CustomerUid, ProjectUid = subscription.ProjectUid, LocationLastUpdatedUtc = machine1.lastKnownTimeStamp, AssetUid = null, Design = machine1.lastKnownDesignName, FuelLevel = null, FuelLevelLastUpdatedUtc = null, Latitude = machine1.lastKnownLatitude * RADIANS_TO_DEGREES, Longitude = machine1.lastKnownLongitude * RADIANS_TO_DEGREES, MachineName = "Test Machine1" }; var expectedHeaders = GetExpectedHeaders(subscription.CustomerUid, subscription.AuthorizationHeader, subscription.JWTAssertion); AssetAggregateStatus resultStatus = null; // Keep a reference to the event generated for comparasion // Setup the returns mockAssetStatusServerHubClient .Setup(m => m.GetSubscriptions()) .Returns(Task.FromResult(new List <AssetUpdateSubscriptionModel> { subscription })); mockProductivity3dV2ProxyNotification.Setup(m => m.ExecuteGenericV2Request <Machine3DStatuses>( It.IsAny <string>(), It.IsAny <HttpMethod>(), It.IsAny <Stream>(), It.IsAny <IHeaderDictionary>())) .Returns(Task.FromResult(machineResult)); mockAssetStatusServerHubClient .Setup(m => m.UpdateAssetLocationsForClient(It.IsAny <AssetAggregateStatus>())) .Returns(Task.FromResult(true)) .Callback <AssetAggregateStatus>((e) => { resultStatus = e; }); // Run the test job.Run(null).Wait(); // Validate the calls // CCSSSCON-85 not possible with WM devices //// We should not call this if we have not matching 3d/2d assets //mockAssetResolverProxy // .Verify(m => m.GetMatching3D2DAssets(It.IsAny<MatchingAssetsDisplayModel>(), // It.IsAny<IHeaderDictionary>()), // Times.Never); // We should have received one event mockAssetStatusServerHubClient .Verify(m => m.UpdateAssetLocationsForClient(It.IsAny <AssetAggregateStatus>()), Times.Once()); // Validate it is the expected result Assert.IsNotNull(resultStatus); resultStatus.Should().BeEquivalentTo(expectedResult); }
public void TestProcessingSubscriptions() { var job = serviceProvider.GetService <IJob>(); Assert.IsNotNull(job); var subscription1 = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("4A856F8C-08D7-4C6E-B6BF-6852658E6A72"), CustomerUid = Guid.Parse("A66D7657-59FC-4C56-8E92-495AADEFD819"), AuthorizationHeader = "TEST AUTH", JWTAssertion = "TEST JWT" }; var subscription2 = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("5DADE1FA-7FAF-4822-93D9-DAE9CFC9BA77"), CustomerUid = Guid.Parse("E04F38AD-44C7-4C8B-95E3-F597E4A1C205"), AuthorizationHeader = "TEST AUTH", JWTAssertion = "TEST JWT" }; Assert.AreNotEqual(subscription1.ProjectUid, subscription2.ProjectUid, "Mock subscriptions must be different"); Assert.AreNotEqual(subscription1.CustomerUid, subscription2.CustomerUid, "Mock subscriptions must be different"); var subscriptions = new List <AssetUpdateSubscriptionModel> { subscription1, subscription2 }; // We will ensure that we get the correct subscriptions, and process each subscription mockAssetStatusServerHubClient.Setup(m => m.GetSubscriptions()).Returns(Task.FromResult(subscriptions)); // The first step is to call out to 3dp for each subscription, ensure we do this (with the correct headers) mockProductivity3dV2ProxyNotification.Setup(m => m.ExecuteGenericV2Request <Machine3DStatuses>( It.IsAny <string>(), It.IsAny <HttpMethod>(), It.IsAny <Stream>(), It.IsAny <IHeaderDictionary>())) .Returns(Task.FromResult(new Machine3DStatuses())); // Execute the call to the job job.Run(null).Wait(); // Now we should have called out for the subscriptions, and for each one called out to raptor with the correct project UID and headers // First Confirm the subscriptions mockAssetStatusServerHubClient.Verify(m => m.GetSubscriptions(), Times.Once); var subscription1Headers = GetExpectedHeaders(subscription1.CustomerUid, subscription1.AuthorizationHeader, subscription1.JWTAssertion); var subscription1Route = string.Format(EXPECTED_RAPTOR_MACHINE_ROUTE_FORMAT, subscription1.ProjectUid); mockProductivity3dV2ProxyNotification.Verify(m => m.ExecuteGenericV2Request <Machine3DStatuses>( It.Is <string>(s => s == subscription1Route), It.IsAny <HttpMethod>(), It.IsAny <Stream>(), It.Is <IHeaderDictionary>(d => DictionaryContentEquals(d, subscription1Headers))), Times.Once); // Ensure the second subscription was called too var subscription2Headers = GetExpectedHeaders(subscription2.CustomerUid, subscription2.AuthorizationHeader, subscription2.JWTAssertion); var subscription2Route = string.Format(EXPECTED_RAPTOR_MACHINE_ROUTE_FORMAT, subscription2.ProjectUid); mockProductivity3dV2ProxyNotification.Verify(m => m.ExecuteGenericV2Request <Machine3DStatuses>( It.Is <string>(s => s == subscription2Route), It.IsAny <HttpMethod>(), It.IsAny <Stream>(), It.Is <IHeaderDictionary>(d => DictionaryContentEquals(d, subscription2Headers))), Times.Once); // And confirm there are no other calls to the request mockProductivity3dV2ProxyNotification.Verify(m => m.ExecuteGenericV2Request <Machine3DStatuses>( It.IsAny <string>(), It.IsAny <HttpMethod>(), It.IsAny <Stream>(), It.IsAny <IHeaderDictionary>()), Times.Exactly(2)); }
public void TestAddAndRemove() { var state = new InMemoryAssetStatusState() as IAssetStatusState; Assert.NotNull(state); { var count = state.GetSubscriptions().Result.Count; Assert.True(count == 0, $"Expected a zero count with a new state, got ${count} instead"); } const string clientId1 = "307CA37C-2422-4AD9-A512-34DFB3BC7507"; const string clientId2 = "B0CCDF38-AA7E-4BCB-8692-53C898D6A469"; var model1 = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("2A131E56-880E-44E8-901F-86D3CD3CBDBB") }; var model2 = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("D5C5A0FA-2480-4ACB-BDCE-0CDF10998BF8") }; var model3 = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("BDE14152-1B1B-4809-85B2-384DA1D91B43") }; // Add the first model state.AddSubscription(clientId1, model1); // count should be 1 { var items = state.GetSubscriptions().Result; Assert.True(items.Count == 1, $"Added a model, count should be one but it is ${items.Count}"); Assert.Equal(model1, items[0]); } // Add the second model, with the same identifier (this should replace the existing one) state.AddSubscription(clientId1, model2); // count should be 1 { var items = state.GetSubscriptions().Result; Assert.True(items.Count == 1, $"Added a model with the same identifier, count should be one but it is ${items.Count}"); Assert.Equal(model2, items[0]); } // Add another model, with another identifier state.AddSubscription(clientId2, model3); // Count should be 2 { var items = state.GetSubscriptions().Result; Assert.True(items.Count == 2, $"Added a model with a new identifier, count should be two but it is ${items.Count}"); Assert.Contains(model2, items); Assert.Contains(model3, items); } // Remove the first subscription and an unknown subscription state.RemoveSubscription(clientId1); state.RemoveSubscription("does not exist id"); // Count should be 1 { var items = state.GetSubscriptions().Result; Assert.True(items.Count == 1, $"Removed a subscription, count should be one but it is ${items.Count}"); Assert.Contains(model3, items); } state.RemoveSubscription(clientId2); // should be empty { var count = state.GetSubscriptions().Result.Count; Assert.True(count == 0, $"Expected a zero count with all clients removed, got ${count} instead"); } }