(CORE) CORE (2022)

Asynchronous MultiThreaded SSH engine for Web (Net Core 6, Linux) - Part 9,10 (BackendAPI for NotificationController and my technique to testing this engine with xUnit).

9. BackendAPI for NotificationController.

This is last part of my component Asynchronous MultiThreaded SSH engine for Web (Net Core 6, Linux), code of this part is ordinary MVC code.



I have injected INotificationCacheService and use data collected in this service to send notification by SignalR hub.



This is core of logic - checking if client is still alive, adding long Result value from DB and sending notification to client.


 131:          <Jwt.Authorize>
 132:          <HttpGet>
 133:          Public Async Function FlushNotification() As Task(Of IActionResult)
 134:              Dim CurUsers = _UserService.GetCurrentUser(_httpContextAccessor.HttpContext.Request.Headers("JwtUserName")(0))
 135:              If CurUsers.IsAdmin Or CurUsers.UserName = "Notification" Then
 136:                  Dim ListNotification As List(Of BashJobFinishedRequest)
 137:                  Dim ListSignalRConnection As MyConcurrentDictionary(Of String, Integer)
 138:                  Try
 139:                      ListNotification = _NotificationCache.ListNotification
 140:                      ListSignalRConnection = _NotificationCache.AllSignalRClientConnection()
 141:                      For Each OneClient As KeyValuePair(Of String, Integer) In ListSignalRConnection.ToList
 142:                          Dim NotificationForUser = ListNotification.Where(Function(X) X.SubscribeId = OneClient.Key).ToList
 143:                          If NotificationForUser.Count > 0 Then
 144:                              For Each OneNotif As BashJobFinishedRequest In NotificationForUser
 145:                                  _Log.LogWarning($"Notification {OneNotif.i} sending to client {OneClient.Key}")
 146:                                  Dim FullResult = Await _DB.RawSqlQueryAsync(Of BashJob)($"SELECT `i`,`Result`,`Error` FROM `cryptochestmax`.`BashJob` WHERE `i`={OneNotif.i};", Function(X) New BashJob With {
 147:                                                          .i = X("i"),
 148:                                                          .Result = X.CheckDBNull(Of String)(X("Result")),
 149:                                                          .[Error] = X.CheckDBNull(Of String)(X("Error"))
 150:                                                          })
 151:                                  Dim FullNotif As New ClientNotificationMessage With {
 152:                                      .i = OneNotif.i,
 153:                                      .CrDate = OneNotif.CrDate,
 154:                                      .toServer = OneNotif.toServer,
 155:                                      .toVm = OneNotif.toVm,
 156:                                      .toUser = OneNotif.toUser,
 157:                                      .Command = OneNotif.Command,
 158:                                      .SubscribeId = OneNotif.SubscribeId,
 159:                                      .Comment = OneNotif.Comment,
 160:                                      .LastUpdate = OneNotif.LastUpdate,
 161:                                      .Result = FullResult.Item1(0).Result,
 162:                                      .[Error] = FullResult.Item1(0).Error
 163:                                  }
 164:                                  Dim NotifyResultTSK = _NotificationCache.NotifyClient(OneClient.Key, FullNotif)
 165:                                  Await NotifyResultTSK
 166:                                  Dim DbOperationTSK = _NotificationCache.MarkNotificationAsSendedToSubscriberInDb(OneNotif.i)
 167:                                  Await DbOperationTSK
 168:                                  _NotificationCache.DelNotification(OneNotif)
 169:                                  _Log.LogWarning($"Notification {OneNotif.i} sended to client {OneClient.Key}, Time {Now}")
 170:                              Next
 171:                          End If
 172:                      Next
 173:                      For Each OneNotification As BashJobFinishedRequest In ListNotification
 174:                          For Each OneSigConnection As KeyValuePair(Of String, Integer) In ListSignalRConnection
 175:                              If OneNotification.SubscribeId = OneSigConnection.Key Then GoTo Nodel
 176:                          Next
 177:                          _Log.LogWarning($"Notification {OneNotification.i} mark as finished because SignalR client {OneNotification.SubscribeId} is absent, Time {Now}")
 178:                          _NotificationCache.DelNotification(OneNotification)
 179:                          Dim DbOperationErrTSK = _NotificationCache.MarkNotificationAsSendedToSubscriberInDb(OneNotification.i)
 180:                          Await DbOperationErrTSK
 181:  Nodel:
 182:                      Next
 183:                      Return Ok(New With {.NotificationKey = _NotificationCache.PrintNotificationKey, .SignalRConnectionKeys = _NotificationCache.PrintSignalRConnectionKeys})
 184:                  Catch ex As Exception
 185:                      Return StatusCode(StatusCodes.Status500InternalServerError, New With {.Error = ex.Message, .NotificationKey = _NotificationCache.PrintNotificationKey})
 186:                  End Try
 187:              Else
 188:                  Return New JsonResult(Unauthorized())
 189:              End If
 190:          End Function

10. My technique to testing this engine with xUnit.

This component not simple and, of course, I was test all parts of this components one-by-one be DDD technique. Firstly, sending group notification, than notification to each clients. Started from test notification to notification with real data.



So, this is my way to testing this component.


   1:  Imports System.Net
   2:  Imports System.Text
   3:  Imports System.Text.RegularExpressions
   4:  Imports BackendAPI
   5:  Imports BackendAPI.KVM
   6:  Imports BackendAPI.Notification
   7:  Imports BackendAPI.WebApi.Controllers
   8:  Imports Microsoft.AspNetCore.Http.Connections
   9:  Imports Microsoft.AspNetCore.Http.Connections.Client
  10:  Imports Microsoft.AspNetCore.SignalR.Client
  11:  Imports Newtonsoft.Json
  12:  Imports Xunit
  13:  Imports Xunit.Abstractions
  14:   
  15:  Public Class NotificationTest
  16:   
  17:      Friend ReadOnly BaseUrl As String = "http://localhost:4000/"
  18:      Friend ReadOnly Request As MyWebClient
  19:   
  20:      Private ReadOnly Log As ITestOutputHelper
  21:      Const SignalRHubURL As String = "http://localhost:4000/NotificationHub"
  22:   
  23:      Public Sub New(_Log As ITestOutputHelper)
  24:          Request = New MyWebClient
  25:          Request.BaseAddress = BaseUrl
  26:          Request.Headers.Add("Content-Type", "application/json")
  27:          Log = _Log
  28:          'BackendAPI.Program.Main(Nothing)
  29:          'System.Diagnostics.Debugger.Launch()
  30:      End Sub
  31:   
  32:      <Theory>
  33:      <InlineData("SRV")> 'TST or SRV
  34:      Async Sub ConnectToNotificationHub(ApiType As String)
  35:          Dim AToken = GetAdminToken(Request)
  36:          Request.Headers.Add("Content-Type", "application/json")
  37:          Dim Utoken = GetUserToken(Request, "Lux", "test")
  38:          Dim Cn1 As HubConnection = StartClient(1, AToken)
  39:          Dim Cn2 As HubConnection = StartClient(3, Utoken)
  40:          Dim Cn3 As HubConnection = StartClient(3, Utoken)
  41:          Await Task.Delay(10000)
  42:          Dim ServerConnectionID As String() = ListAllClientConnectionToHub(AToken)
  43:          NotifyAllClients(AToken, ApiType)
  44:          NotifyOneClient(AToken, ServerConnectionID(0), ApiType)
  45:          NotifyOneClient(AToken, ServerConnectionID(1), ApiType)
  46:          NotifyOneClient(AToken, ServerConnectionID(2), ApiType)
  47:          Dim Tsk1 As Task = Cn1.StopAsync()
  48:          Await Tsk1
  49:          Dim Tsk2 As Task = Cn2.StopAsync()
  50:          Await Tsk2
  51:          Dim Tsk3 As Task = Cn3.StopAsync()
  52:          Await Tsk3
  53:      End Sub
  54:   
  55:      Function StartClient(UserID As Integer, UserToken As String) As HubConnection
  56:          Dim SignalRConnection As HubConnection = New HubConnectionBuilder().
  57:                      WithUrl(SignalRHubURL, Sub(X) X.Headers.Add("Authorization", UserToken)).
  58:                      WithAutomaticReconnect({TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10)}).
  59:                      Build
  60:          AddHandler SignalRConnection.Closed, Async Function(X)
  61:                                                   Log.WriteLine($"ConnectionClosed {X?.Message}")
  62:                                                   Await Task.Delay(New Random().Next(0, 5) * 1000)
  63:                                                   Await SignalRConnection.StartAsync()
  64:                                               End Function
  65:          AddHandler SignalRConnection.Reconnected, Async Function(X)
  66:                                                        Log.WriteLine($"Reconnected :{X}")
  67:                                                        Await Task.CompletedTask
  68:                                                    End Function
  69:          AddHandler SignalRConnection.Reconnecting, Async Function(X)
  70:                                                         Log.WriteLine($"Reconnecting :{X?.Message}")
  71:                                                         Await Task.CompletedTask
  72:                                                     End Function
  73:          SignalRConnection.On("TestNotification", Sub(X) TestNotification(X))
  74:          SignalRConnection.On("NotifyClient", Sub(X) NotifyClient(X))
  75:          Dim Tsk = SignalRConnection.StartAsync()
  76:          Tsk.Wait()
  77:          Log.WriteLine($"Connection {SignalRHubURL}/{SignalRConnection.ConnectionId} is {SignalRConnection.State}, UserID={UserID}")
  78:          Return SignalRConnection
  79:      End Function
  80:   
  81:      Sub TestNotification(ParamArray X())
  82:          Log.WriteLine($"Recived TestNotification Message :{String.Join(",", X)}")
  83:      End Sub
  84:      Sub NotifyClient(ParamArray X())
  85:          Log.WriteLine($"Recived NotifyClient Message :{String.Join(",", X)}")
  86:      End Sub
  87:   
  88:   
  89:      Function ListAllClientConnectionToHub(Token As String) As String()
  90:          Request.Headers.Add("Content-Type", "application/json")
  91:          Request.Headers.Add("Authorization", "Bearer: " & Token)
  92:          Try
  93:              Dim Response = Request.DownloadString("/Notification/ListAllClientConnectionToHub")
  94:              Log.WriteLine(Response)
  95:              Return Response.Split(",")
  96:          Catch ex As WebException
  97:              Dim Resp As String = ""
  98:              Dim Stream = ex.Response?.GetResponseStream()
  99:              If Stream IsNot Nothing Then
 100:                  Dim Sr = New IO.StreamReader(Stream)
 101:                  Resp = Sr.ReadToEnd
 102:              End If
 103:              Log.WriteLine(Resp & vbCrLf & ex.Message)
 104:          End Try
 105:      End Function
 106:   
 107:      Sub NotifyAllClients(Token As String, ApiType As String)
 108:          Request.Headers.Add("Content-Type", "application/json")
 109:          Request.Headers.Add("Authorization", "Bearer: " & Token)
 110:          Try
 111:              Dim Response = Request.DownloadString($"/Notification/NotifyAllClients{ApiType}")
 112:              Log.WriteLine(Response)
 113:          Catch ex As WebException
 114:              Dim Resp As String = ""
 115:              Dim Stream = ex.Response?.GetResponseStream()
 116:              If Stream IsNot Nothing Then
 117:                  Dim Sr = New IO.StreamReader(Stream)
 118:                  Resp = Sr.ReadToEnd
 119:              End If
 120:              Log.WriteLine(Resp & vbCrLf & ex.Message)
 121:          End Try
 122:      End Sub
 123:   
 124:      Sub NotifyOneClient(Token As String, ConnectionID As String, ApiType As String)
 125:          Request.Headers.Add("Content-Type", "application/json")
 126:          Request.Headers.Add("Authorization", "Bearer: " & Token)
 127:          Try
 128:              Dim Response = Request.DownloadString($"/Notification/NotifyOneClient{ApiType}?ConnectionID={ConnectionID}")
 129:              Log.WriteLine(Response)
 130:          Catch ex As WebException
 131:              Dim Resp As String = ""
 132:              Dim Stream = ex.Response?.GetResponseStream()
 133:              If Stream IsNot Nothing Then
 134:                  Dim Sr = New IO.StreamReader(Stream)
 135:                  Resp = Sr.ReadToEnd
 136:              End If
 137:              Log.WriteLine(Resp & vbCrLf & ex.Message)
 138:          End Try
 139:      End Sub
 140:   
 141:      <Theory>
 142:      <InlineData(1, "XXXXXXXX", "pwd")>
 143:      Sub AddBashJob(ServerI As Integer, ServerDecryptPass As String, BashCmd As String)
 144:          Dim Token = GetAdminToken(Request)
 145:          Request.Headers.Add("Content-Type", "application/json")
 146:          Request.Headers.Add("Authorization", "Bearer: " & Token)
 147:          Dim PostPrm = New BashJobRequest With {
 148:              .toServer = ServerI,
 149:              .SshDecryptPass = ServerDecryptPass,
 150:              .Command = BashCmd,
 151:              .toUser = 1
 152:              }
 153:          Dim JsonSerializer = New JsonSerializer()
 154:          Dim PostData = JsonConvert.SerializeObject(PostPrm)
 155:          Try
 156:              Dim Response = Encoding.UTF8.GetString(Request.UploadData("/Notification/AddBashJob", Encoding.UTF8.GetBytes(PostData)))
 157:              Log.WriteLine(Response)
 158:          Catch ex As WebException
 159:              Dim Resp As String = ""
 160:              Dim Stream = ex.Response?.GetResponseStream()
 161:              If Stream IsNot Nothing Then
 162:                  Dim Sr = New IO.StreamReader(Stream)
 163:                  Resp = Sr.ReadToEnd
 164:              End If
 165:              Log.WriteLine(Resp & vbCrLf & ex.Message)
 166:          End Try
 167:      End Sub
 168:   
 169:      Sub AddBashJobWithSubScribeID(Token As String, ServerI As Integer, ServerDecryptPass As String, BashCmd As String, SubscribeID As String)
 170:          Request.Headers.Add("Content-Type", "application/json")
 171:          Request.Headers.Add("Authorization", "Bearer: " & Token)
 172:          Dim PostPrm = New BashJobRequest With {
 173:              .toServer = ServerI,
 174:              .SshDecryptPass = ServerDecryptPass,
 175:              .Command = BashCmd,
 176:              .toUser = 1,
 177:              .SubscribeId = SubscribeID
 178:              }
 179:          Dim JsonSerializer = New JsonSerializer()
 180:          Dim PostData = JsonConvert.SerializeObject(PostPrm)
 181:          Try
 182:              Dim Response = Encoding.UTF8.GetString(Request.UploadData("/Notification/AddBashJob", Encoding.UTF8.GetBytes(PostData)))
 183:              Log.WriteLine(Response)
 184:          Catch ex As WebException
 185:              Dim Resp As String = ""
 186:              Dim Stream = ex.Response?.GetResponseStream()
 187:              If Stream IsNot Nothing Then
 188:                  Dim Sr = New IO.StreamReader(Stream)
 189:                  Resp = Sr.ReadToEnd
 190:              End If
 191:              Log.WriteLine(Resp & vbCrLf & ex.Message)
 192:          End Try
 193:      End Sub
 194:   
 195:      Sub ListNotificationCacheWaitingToSendToSubscriber(Token As String)
 196:          Request.Headers.Add("Content-Type", "application/json")
 197:          Request.Headers.Add("Authorization", "Bearer: " & Token)
 198:          Try
 199:              Dim Response = Request.DownloadString("/Notification/ListNotificationCacheWaitingToSendToSubscriber")
 200:              Log.WriteLine(Response)
 201:          Catch ex As WebException
 202:              Dim Resp As String = ""
 203:              Dim Stream = ex.Response?.GetResponseStream()
 204:              If Stream IsNot Nothing Then
 205:                  Dim Sr = New IO.StreamReader(Stream)
 206:                  Resp = Sr.ReadToEnd
 207:              End If
 208:              Log.WriteLine(Resp & vbCrLf & ex.Message)
 209:          End Try
 210:      End Sub
 211:   
 212:      <Theory>
 213:      <InlineData(1, "XXXXXXXXXX", "pwd")>
 214:      Async Sub AddBashJobAndReceiveNotification(ServerI As Integer, ServerDecryptPass As String, BashCmd As String)
 215:          Request.Headers.Add("Content-Type", "application/json")
 216:          Dim AToken = GetAdminToken(Request)
 217:          Dim Cn1 As HubConnection = StartClient(1, AToken)
 218:          Await Task.Delay(10000)
 219:          Dim ServerConnectionID As String() = ListAllClientConnectionToHub(AToken)
 220:          Dim AddJob = Task.Run(Sub()
 221:                                    AddBashJobWithSubScribeID(AToken, ServerI, ServerDecryptPass, BashCmd, ServerConnectionID(0))
 222:                                End Sub)
 223:          Await Task.Delay(10000)
 224:          Dim Tsk1 As Task = Cn1.StopAsync()
 225:      End Sub
 226:   
 227:   
 228:  End Class

By the way, for testing other components of this project I use more sophisticated method of testing with ClassData.



That's it about component Asynchronous MultiThreaded SSH engine for Web (Net Core 6, Linux).



Comments ( )
Link to this page: http://www.vb-net.com/SshQueueNotificationServer/Index4.htm
< THANKS ME>