Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/assets/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image15.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/image9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 2 additions & 3 deletions EchoTcpServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class EchoServer : IDisposable
public int Port { get; private set; }
public bool IsRunning { get; private set; }

// Added logger injection for testability (defaults to Console.WriteLine)
// Added logger injection for testability
public EchoServer(int port, Action<string>? logger = null)
{
Port = port;
Expand Down Expand Up @@ -139,9 +139,8 @@ private void SendMessageCallback(object? state)
{
try
{
Random rnd = new Random();
byte[] samples = new byte[1024];
rnd.NextBytes(samples);
Random.Shared.NextBytes(samples);
_sequence++;

byte[] msg = new byte[] { 0x04, 0x84 }
Expand Down
4 changes: 3 additions & 1 deletion NetSdrClientApp/Networking/TcpClientWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public void Disconnect()
if (Connected)
{
_cts?.Cancel();
_cts?.Dispose(); // Properly disposes the CancellationTokenSource

_stream?.Close();
_tcpClient?.Close();

Expand Down Expand Up @@ -84,7 +86,7 @@ public async Task SendMessageAsync(byte[] data)
}
}

// Fixed Duplication: Delegates the actual sending logic to the byte[] overload
// Delegates the actual sending logic to the byte[] overload
public async Task SendMessageAsync(string str)
{
var data = Encoding.UTF8.GetBytes(str);
Expand Down
198 changes: 198 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
## Лабораторна робота 1

**Підключення SonarCloud і CI**

Створено новий репозиторій на основі репозиторію курсу та підключено SonarCloud, вимкнено автоматичний аналіз.

Посилання – https://github.com/m4xym/NetSDR_Lab.git


Перший PR (https://github.com/m4xym/NetSDR_Lab/pull/2) – не пройшов перевірку через недостатнє покриття коду та ризики безпеки, пов’язані з використанням ${{ secrets.SONAR_TOKEN }} безпосередньо в блоці run (sonarcloud.yml)

![alt text](.github/assets/image.png)

---

## Лабораторна робота 2

**Code Smells через PR + “gated merge”**

Виявлено та виправлено 6 нових Code smells (Mantainability):

![alt text](.github/assets/image1.png)

- Make '_sampleWriter' 'readonly'. Fields that are only assigned in the constructor should be "readonly"
https://github.com/m4xym/NetSDR_Lab/commit/7a581ea95651b465146e14e95d0946a234ba1ee8

- Cannot convert null literal to non-nullable reference type.
https://github.com/m4xym/NetSDR_Lab/commit/edea573f091dcbd044110bfeaf5def14b119c7af

- Non-nullable event 'UnsolicitedMessageReceived' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the event as nullable.
https://github.com/m4xym/NetSDR_Lab/commit/f1e6ef1a45b5b058cf224b84d20bdcd3000a73c0

- Remove the unused local variable 'code', 'sequenceNum', 'body'.
https://github.com/m4xym/NetSDR_Lab/commit/da7a11f287afc9bd4d9f5024ab24a8be5e3facc5

Результат:

![alt text](.github/assets/image2.png)

---

## Лабораторна робота 3

**Тести та покриття**

Поточне покриття – 0%.

![alt text](.github/assets/image3.png)

Додано 6 unit тестів (PR https://github.com/m4xym/NetSDR_Lab/pull/5 ):

- ConnectAsync_WhenAlreadyConnected_DoesNotConnectOrSend
Перевіряє, чи виклик методу connect для вже активного з'єднання безпечно достроково завершується.
- StopIQAsync_NoConnection_DoesNotSendRequest
Гарантує, що якщо застосунок намагається зупинити потік даних IQ під час відключення, метод коректно завершується без викидання помилок або спроб передачі команд через неактивний мережевий сокет.
- ChangeFrequencyAsync_ValidInputs_SendsCorrectMessage
Підтверджує основну функціональність методу налаштування частоти. Перевіряє, що передача конкретної частоти в герцах та індексу каналу успішно упаковує корисне навантаження та передає його до потоку TCP.
- TcpClient_UnsolicitedMessage_RaisesUnsolicitedMessageReceivedEvent
Тестує логіку маршрутизації TCP. Вводить імітовану фонову трансляцію з апаратного забезпечення та перевіряє, що подія - UnsolicitedMessageReceived успішно передається до програми, замість виконання завдання з очікуючим наказом.
- UdpClient_MessageReceived_CallsSampleWriterWithSamples
Перевіряє працездатність парсера даних шляхом введення в UDP-потік імітованого корисного навантаження у вигляді байтів IQ перевіряється, чи NetSdrMessageHelper успішно перетворює корисне навантаження та передає отримані зразки повністю в пам'яті до роз'єднаного інтерфейсу ISampleWriter.
- ChangeFrequencyAsync_WhenNotConnected_HandlesNullResponseGracefully
Перевіряє асинхронні механізми безпеки. Якщо команда запускається без активного з'єднання, базовий SendTcpRequest припиняється і повертає null.

Покриття становить 81.38%:

![alt text](.github/assets/image4.png)

---

## Лабораторна робота 4

**Дублікати через SonarCloud**

Поточний рівень дублікатів коду становить 9.8%:

![alt text](.github/assets/image5.png)


Дублікати виявлено у файлах:

- TcpClientWrapper.cs — дублювання (14 %)
Причина: 2 перевантаження для SendMessageAsync (одне приймає byte[], а інше – sting).
Виправлення: щоб перевантаження для string перетворює корисне навантаження, а потім негайно передає його до перевантаження для byte[].

- Дублювання в UdpClientWrapper.cs (28%)
Причина: Методи StopListening() та Exit() містять ідентичний блок try/catch, логіку скасування, закриття сокета та ведення журналу в консолі. Виправлення: Exit() викликає StopListening().

PR: https://github.com/m4xym/NetSDR_Lab/pull/8


Знижено Дублювання коду до 0%:

![alt text](.github/assets/image6.png)

---

## Лабораторна робота 5

**Архітектурні правила (NetArchTest)**

Додано 2 тести для перевірки архітектури

- Ізоляція доменної логіки (Messages_ShouldNot_DependOn_Networking) – Розділення відповідальності: тест гарантує, що простір імен Messages (де відбувається парсинг байтів та бізнес-логіка) є повністю незалежним. Він перевіряє, що парсер нічого не знає про інфраструктуру (Networking). Це захищає ядро програми: ми можемо змінити механізм роботи сокетів, не торкаючись логіки обробки самих повідомлень.

- Інверсія залежностей (ClientApp_Should_DependOn_Interfaces...) – Принцип інверсії залежностей: тест забороняє головному класу NetSdrClient напряму створювати або залежати від конкретних класів (наприклад, TcpClientWrapper). Він змушує клас працювати виключно через абстракції (ITcpClient). Завдяки цьому ми зберігаємо можливість легко підміняти реальні мережеві виклики на моки (Mocks) під час тестування.

Для перевірки тестів додано тимчасовий демонстраційний метод BadArchitectureMethod у класі NetSdrMessageHelper, який навмисно створює жорстку прив'язку між незалежними модулями. Знаходячись у просторі імен Messages (який має відповідати лише за чисту логіку парсингу), він ініціалізує клас TcpClientWrapper з простору імен Networking.

Його наявність у коді гарантовано порушує правило ізоляції доменної логіки. Завдання цього методу – викликати спрацьовування NetArchTest.Rules, "завалити" збірку (зробити PR червоним).

PR: https://github.com/m4xym/NetSDR_Lab/pull/9

Провал тесту Messages_ShouldNot_DependOn_Networking ламає збірку:

![alt text](.github/assets/image7.png)

Виправлення (видалено BadArchitectureMethod):

![alt text](.github/assets/image8.png)

---

## Лабораторна робота 6

**Безпечний рефакторинг під тести**

Поточне покриття EchoServer – 0%.

![alt text](.github/assets/image9.png)

PR: https://github.com/m4xym/NetSDR_Lab/pull/10

Рефакторинг EchoServer:
- Підтримка порту 0: якщо передати серверу значення 0, ОС автоматично призначить вільний тимчасовий порт.
Logger: функція Console.WriteLine замінюється вбудованим Action<string>, що дозволяє тестам фіксувати або приховувати записи в журналі.
- Розмежування функціональних блоків: логіка виведення інформації винесена в клас ProcessStreamAsync, який приймає стандартний потік.

Тести:
- StartAsync_AssignsDynamicPort_AndSetsIsRunningToTrue – Коректність ініціалізації сервера та правильну роботу з динамічними портами ОС: передає порт 0 під час створення сервера, що змушує ОС автоматично знайти та призначити будь-який вільний порт. Потім він перевіряє, що стан сервера IsRunning стає true, фактичний порт оновлюється на число більше за 0, а логер фіксує повідомлення про успішний старт. Це повністю усуває проблему "Address already in use", коли тести падають через зайнятий жорстко заданий порт (наприклад, 5000).
- Stop_SafeShutDownServer – Безпечне завершення роботи мережевого слухача: запускає сервер у фоновій задачі, дає йому час на ініціалізацію, а потім викликає метод Stop(). Він перевіряє, що внутрішній CancellationToken успішно скасовує очікування нових клієнтів, статус IsRunning змінюється на false, а процес зупинки не викидає фатальних винятків і фіксується у логах.
- Server_ReceivesAndEchoesDataCorrectly – здатність сервера приймати та повертати (Echo) байти без втрат: запускає сервер, після чого створює тестовий TcpClient та підключається до 127.0.0.1 на динамічно виділений порт. Тест відправляє текстовий рядок ("Hello, Echo Server!"), перетворений на масив байтів. Далі він вичитує відповідь із потоку та застосовує Assert для перевірки того, що отримана кількість байтів і сам текст збігаються до символу. Додатково перевіряється, чи логер зафіксував факт підключення клієнта та обсяг повернутих даних.

Покриття нового коду становить 82.76%:

![alt text](.github/assets/image10.png)

---

## Лабораторна робота 7

**Оновлення залежностей**

Список залежностей:

![alt text](.github/assets/mage11.png)

У налаштуваннях увімкнено Dependency graph + Dependabot alerts.

- PR на оновлення coverlet.collector (https://github.com/m4xym/NetSDR_Lab/pull/13)

У нових версіях Coverlet часто змінюється спосіб взаємодії з JIT-компілятором. Оновлення в цьому випадку може призвести до «фантомного» падіння покриття, коли показник покриття, що становив 80%, раптово впаде до 0%, оскільки інструментарій не зміг інтегруватися у структуру конкретного збірника.
Версії Coverlet часто прив’язані до конкретних версій MSBuild. Істотний перехід на нову версію може вимагати оновленої версії .NET SDK для збірки або на GitHub Actions runner.

- PR на оновлення Microsoft.NET.Test.Sdk (https://github.com/m4xym/NetSDR_Lab/pull/14)

Test SDK керує процесом виявлення тестів та інтеграцією з виконавцем. Значні зміни в цій частині можуть іноді спричиняти проблеми з виявленням тестів у Visual Studio або в певних адаптерах тестів CI/CD, якщо змінюється внутрішній протокол зв’язку виконавця.

- PR на оновлення NUnit.Analyzers (https://github.com/m4xym/NetSDR_Lab/pull/16)

- PR на оновлення NUnit (https://github.com/m4xym/NetSDR_Lab/pull/15)

---

## Лабораторна робота 8

**Чистий проєкт і gated build**

Статус проєкту:

![alt text](.github/assets/image13.png)

- Coverage - 89.6%
- Duplications - 0%
- 1 Security Hotspots


Виправлено Security Hotspot "Make sure that using this pseudorandom number generator is safe here." (PR https://github.com/m4xym/NetSDR_Lab/pull/21)

Увімкнено правила Require a pull request before merging та Require status checks to pass (Sonar Check)

![alt text](.github/assets/image14.png)

![alt text](.github/assets/image15.png)

Правило не дозволяє злиття до закінчення перевірки:

![alt text](.github/assets/image16.png)
Loading