Skip to content

Commit 0bef7ce

Browse files
committed
Implement v1.1 quality improvements
1 parent fb40daa commit 0bef7ce

21 files changed

Lines changed: 650 additions & 109 deletions

File tree

.github/dependabot.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,23 @@ updates:
77
day: "monday"
88
time: "10:00"
99
open-pull-requests-limit: 5
10+
groups:
11+
gradle-quality-stack:
12+
patterns:
13+
- "com.github.spotbugs*"
14+
- "org.junit*"
15+
- "org.awaitility*"
16+
jackson:
17+
patterns:
18+
- "com.fasterxml.jackson*"
1019
- package-ecosystem: "github-actions"
1120
directory: "/"
1221
schedule:
1322
interval: "weekly"
1423
day: "monday"
1524
time: "10:30"
1625
open-pull-requests-limit: 5
26+
groups:
27+
github-actions:
28+
patterns:
29+
- "*"

.github/workflows/ci.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,31 @@ jobs:
3131
gradle-version: "8.10.2"
3232
- name: Run tests and checks
3333
run: ./gradlew check jacocoAllReport --stacktrace
34+
- name: Publish coverage summary
35+
if: matrix.os == 'ubuntu-latest'
36+
shell: bash
37+
run: |
38+
report="build/reports/jacoco/jacocoAllReport/jacocoAllReport.csv"
39+
awk -F, '
40+
NR > 1 {
41+
branchMissed += $6
42+
branchCovered += $7
43+
lineMissed += $8
44+
lineCovered += $9
45+
}
46+
END {
47+
lineTotal = lineMissed + lineCovered
48+
branchTotal = branchMissed + branchCovered
49+
lineCoverage = lineTotal == 0 ? 100 : (lineCovered * 100 / lineTotal)
50+
branchCoverage = branchTotal == 0 ? 100 : (branchCovered * 100 / branchTotal)
51+
print "### JaCoCo coverage"
52+
print ""
53+
print "| Metric | Coverage |"
54+
print "| --- | ---: |"
55+
printf "| Lines | %.2f%% |\n", lineCoverage
56+
printf "| Branches | %.2f%% |\n", branchCoverage
57+
}
58+
' "$report" >> "$GITHUB_STEP_SUMMARY"
3459
- name: Upload coverage report
3560
if: matrix.os == 'ubuntu-latest'
3661
uses: actions/upload-artifact@v4

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Added `ChatServerConfig` with server limits and socket timeout settings.
6+
- Made server client handling bounded and explicit about busy rejections.
7+
- Split protocol text payloads from display formatting: `data` is raw text, `sender` is the author.
8+
- Fixed GUI connection lifecycle by preserving the base client status update path.
9+
- Added architecture documentation, grouped Dependabot updates, version catalog, and CI coverage summary.
10+
311
## 1.0.0
412

513
- Reworked project into Gradle Java 21 multi-layer architecture.

README.en.md

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![CI](https://github.com/krotname/JavaNetworkChat/actions/workflows/ci.yml/badge.svg)](https://github.com/krotname/JavaNetworkChat/actions/workflows/ci.yml)
44
[![CodeQL](https://github.com/krotname/JavaNetworkChat/actions/workflows/codeql.yml/badge.svg)](https://github.com/krotname/JavaNetworkChat/actions/workflows/codeql.yml)
55
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/krotname/JavaNetworkChat/badge)](https://securityscorecards.dev/viewer/?uri=github.com/krotname/JavaNetworkChat)
6-
[![coverage](https://img.shields.io/badge/coverage-70%2B-green)](https://github.com/krotname/JavaNetworkChat/actions/workflows/ci.yml)
6+
[![coverage summary](https://img.shields.io/badge/coverage-CI%20summary-blue)](https://github.com/krotname/JavaNetworkChat/actions/workflows/ci.yml)
77
[![Java](https://img.shields.io/badge/Java-21-007396)](https://adoptium.net/)
88
[![License](https://img.shields.io/badge/license-GPL--3.0-blue)](LICENSE)
99

@@ -17,6 +17,8 @@ Network Chat is a Java 21 chat application over TCP sockets with:
1717
- a Swing GUI client using MVC style structure.
1818
- a production-like project layout with Gradle, tests, and CI.
1919

20+
![Swing GUI client](docs/images/gui-client.svg)
21+
2022
## Run locally
2123

2224
### Prerequisites
@@ -34,12 +36,27 @@ Network Chat is a Java 21 chat application over TCP sockets with:
3436

3537
Server and clients can also be run directly with Java by building jars from Gradle.
3638

39+
The default server port is `1500`. Programmatic server startup can use `ChatServerConfig` to set the
40+
port, maximum client count, handshake timeout, and post-handshake read timeout.
41+
42+
## Architecture and protocol
43+
44+
The compact architecture contract is documented in [docs/architecture.md](docs/architecture.md).
45+
46+
- `ChatServer` accepts TCP connections and handles clients in a bounded executor.
47+
- `ChatConnection` reads and writes one-line UTF-8 JSON frames.
48+
- `ChatProtocol` serializes `ChatMessage`.
49+
- For `TEXT` messages, `data` contains only raw text and `sender` contains the author.
50+
- Console and Swing clients format display text such as `alice: hello`.
51+
- The bot client reads date/time commands from `data` and uses the author from `sender`.
52+
3753
## Project structure
3854

3955
- `src/main/java` — core application classes.
4056
- `src/test/java` — unit tests.
4157
- `src/integrationTest/java` — protocol and network integration tests.
4258
- `src/uiTest/java` — Swing smoke tests.
59+
- `docs` — architecture notes and visual assets.
4360
- `.github/workflows` — CI, CodeQL and Scorecard workflows.
4461

4562
## Testing
@@ -51,12 +68,14 @@ Server and clients can also be run directly with Java by building jars from Grad
5168
- `./gradlew jacocoTestCoverageVerification`
5269
- `./gradlew jacocoAllReport` (CI artifact source)
5370

54-
Coverage thresholds are enforced in Gradle and CI.
71+
Coverage thresholds are enforced in Gradle and CI. The HTML JaCoCo report is uploaded as a CI
72+
artifact, and line/branch coverage is published to the GitHub Actions Summary for the Linux job.
5573

5674
### Test strategy
5775

58-
- **Unit tests** (`src/test/java`) check protocol and UI model invariants.
59-
- **Integration tests** (`src/integrationTest/java`) exercise full server/client socket flow with multiple peers.
76+
- **Unit tests** (`src/test/java`) check protocol, bot command handling, and UI model invariants.
77+
- **Integration tests** (`src/integrationTest/java`) exercise full server/client socket flow, handshake
78+
failures, resource limits, timeouts, and multiple peers.
6079
- **UI smoke tests** (`src/uiTest/java`) verify Swing state rendering.
6180
- **Future hardening tests**: contract validation and error-handling matrix can be added in the same
6281
structure.
@@ -68,9 +87,9 @@ The repository runs:
6887
- `checkstyle` for style and API cleanliness,
6988
- `spotless` for deterministic formatting,
7089
- `spotbugs` for bug-pattern analysis,
71-
- `jaCoCo` line/branch coverage gate on core network/protocol layers (`70%/55%`),
90+
- `jaCoCo` line/branch coverage gate on core network/protocol layers (`80%/65%`),
7291
- GitHub Actions pipeline on Linux + Windows,
73-
- dependency and workflow update signals via Dependabot,
92+
- grouped dependency and workflow update signals via Dependabot,
7493
- CodeQL and OpenSSF Scorecard security scans.
7594

7695
The quality surface is intentionally structured for a public review: clean `main` surface, automated checks,
@@ -98,3 +117,15 @@ This repository is organized to be review-friendly:
98117
- Security checks via CodeQL and OpenSSF Scorecard.
99118
- Dependency and workflow automation via Dependabot.
100119
- Explicit contributor and security docs.
120+
121+
## Troubleshooting
122+
123+
- `Address already in use`: run the server on another port, for example `./gradlew runServer --args="--port 1600"`.
124+
- GUI does not render in CI: UI smoke tests skip automatically in headless environments.
125+
- Client disconnects immediately: check username uniqueness and nickname length (`3..64`, letters, digits, `_`, `-`).
126+
- Client receives `Server is busy`: the configured `ChatServerConfig.maxClients` limit has been reached.
127+
128+
## Roadmap
129+
130+
- v1.1.x: stabilize protocol/server lifecycle, expand negative tests, and improve documentation.
131+
- Later: rooms, message history, TLS, and persistent accounts as separate product-focused phases.

README.md

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![CI](https://github.com/krotname/JavaNetworkChat/actions/workflows/ci.yml/badge.svg)](https://github.com/krotname/JavaNetworkChat/actions/workflows/ci.yml)
44
[![CodeQL](https://github.com/krotname/JavaNetworkChat/actions/workflows/codeql.yml/badge.svg)](https://github.com/krotname/JavaNetworkChat/actions/workflows/codeql.yml)
55
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/krotname/JavaNetworkChat/badge)](https://securityscorecards.dev/viewer/?uri=github.com/krotname/JavaNetworkChat)
6-
[![coverage](https://img.shields.io/badge/coverage-70%2B-green)](https://github.com/krotname/JavaNetworkChat/actions/workflows/ci.yml)
6+
[![coverage summary](https://img.shields.io/badge/coverage-CI%20summary-blue)](https://github.com/krotname/JavaNetworkChat/actions/workflows/ci.yml)
77
[![Java](https://img.shields.io/badge/Java-21-007396)](https://adoptium.net/)
88
[![License](https://img.shields.io/badge/license-GPL--3.0-blue)](LICENSE)
99

@@ -19,6 +19,8 @@ Network Chat — это Java 21 приложение для сетевого ч
1919
- GUI клиент на Swing с разделением на MVC;
2020
- структуру продакшн-проекта с Gradle, тестами и CI.
2121

22+
![Swing GUI client](docs/images/gui-client.svg)
23+
2224
## Запуск
2325

2426
```bash
@@ -28,6 +30,21 @@ Network Chat — это Java 21 приложение для сетевого ч
2830
./gradlew runGuiClient
2931
```
3032

33+
Сервер по умолчанию слушает порт `1500`. Для программного запуска используйте
34+
`ChatServerConfig`: он задаёт порт, максимальное число клиентов, timeout handshake и timeout чтения
35+
после handshake.
36+
37+
## Архитектура и протокол
38+
39+
Краткий архитектурный контракт описан в [docs/architecture.md](docs/architecture.md).
40+
41+
- `ChatServer` принимает TCP-соединения и обрабатывает клиентов в bounded executor.
42+
- `ChatConnection` читает и пишет однострочные UTF-8 JSON frames.
43+
- `ChatProtocol` сериализует `ChatMessage`.
44+
- Для `TEXT` сообщений `data` содержит только исходный текст, а `sender` содержит автора.
45+
- Console и Swing клиенты сами форматируют отображение вида `alice: hello`.
46+
- Bot client отвечает на команды времени/даты по `data`, используя автора из `sender`.
47+
3148
## Тесты и качество
3249

3350
- `./gradlew test`
@@ -37,27 +54,43 @@ Network Chat — это Java 21 приложение для сетевого ч
3754
- `./gradlew jacocoAllReport`
3855
- `./gradlew jacocoTestCoverageVerification`
3956

57+
В CI HTML-отчёт JaCoCo публикуется как artifact, а line/branch coverage добавляется в GitHub
58+
Actions Summary для Linux job.
59+
4060
## Стратегия тестирования
4161

42-
- **Unit-тесты** (`src/test/java`) — протокол и модель GUI.
43-
- **Интеграционные тесты** (`src/integrationTest/java`) — подключение нескольких клиентов к серверу и обмен сообщениями.
62+
- **Unit-тесты** (`src/test/java`) — протокол, bot-команды, модель GUI.
63+
- **Интеграционные тесты** (`src/integrationTest/java`) — подключение клиентов, handshake, лимиты сервера, timeout и обмен сообщениями.
4464
- **UI smoke тесты** (`src/uiTest/java`) — проверка отрисовки состояния окна чата.
45-
- **План роста** — контракты протокола и матрицы негативных сценариев (подключение дубликатов, некорректные пакеты).
65+
- **План роста** — больше негативных сценариев протокола и проверок отказоустойчивости медленных клиентов.
66+
67+
Для оценки покрытия используется JaCoCo: в CI порог для ядра (`network` + `protocol`) — `80%/65%` (`line`/`branch`).
68+
69+
## Troubleshooting
4670

47-
Для оценки покрытия используется JaCoCo: в CI порог для ядра (`network` + `protocol`) — `70%/55%` (`line`/`branch`).
71+
- `Address already in use`: запустите сервер на другом порту, например `./gradlew runServer --args="--port 1600"`.
72+
- GUI не показывает окно в CI: UI smoke тесты автоматически пропускаются в headless окружении.
73+
- Клиент сразу отключился: проверьте уникальность имени и длину ника (`3..64`, буквы, цифры, `_`, `-`).
74+
- Клиент получил `Server is busy`: достигнут `maxClients` из `ChatServerConfig`.
4875

4976
## Структура репозитория
5077

5178
- `src/main/java` — код приложения.
5279
- `src/test/java` — unit-тесты.
5380
- `src/integrationTest/java` — интеграционные тесты.
5481
- `src/uiTest/java` — smoke тесты UI.
82+
- `docs` — архитектурные заметки и визуальные материалы.
5583
- `.github/workflows` — CI и проверки безопасности.
5684

5785
## Дополнительные сигналы качества
5886

5987
- CI на Linux и Windows.
6088
- Авто-проверки: Checkstyle, Spotless, SpotBugs, JaCoCo.
6189
- Security проверки: CodeQL и OpenSSF Scorecard.
62-
- Dependabot для обновлений зависимостей и Actions.
90+
- Dependabot с группировкой обновлений зависимостей и Actions.
6391
- Явно оформленные файлы `CONTRIBUTING.md` и `SECURITY.md`.
92+
93+
## Roadmap
94+
95+
- v1.1.x: стабилизация protocol/server lifecycle, расширение негативных тестов, улучшение документации.
96+
- Позже: комнаты, история сообщений, TLS и персистентные аккаунты отдельными product-focused этапами.

build.gradle.kts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ plugins {
22
java
33
application
44
jacoco
5-
id("com.diffplug.spotless") version "6.25.0"
5+
alias(libs.plugins.spotless)
66
id("checkstyle")
7-
id("com.github.spotbugs") version "6.0.12"
7+
alias(libs.plugins.spotbugs)
88
}
99

1010
group = "dev.krotname"
11-
version = "1.0.0"
11+
version = "1.1.0-SNAPSHOT"
1212

1313
java {
1414
toolchain {
@@ -21,17 +21,17 @@ repositories {
2121
}
2222

2323
dependencies {
24-
implementation("com.fasterxml.jackson.core:jackson-databind:2.17.2")
25-
compileOnly("com.github.spotbugs:spotbugs-annotations:4.8.6")
24+
implementation(libs.jackson.databind)
25+
compileOnly(libs.spotbugs.annotations)
2626

27-
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
28-
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.2")
29-
testImplementation("org.awaitility:awaitility:4.2.1")
30-
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
27+
testImplementation(libs.junit.jupiter)
28+
testImplementation(libs.junit.jupiter.params)
29+
testImplementation(libs.awaitility)
30+
testRuntimeOnly(libs.junit.platform.launcher)
3131
}
3232

3333
checkstyle {
34-
toolVersion = "10.12.5"
34+
toolVersion = libs.versions.checkstyle.get()
3535
configFile = file("config/checkstyle/checkstyle.xml")
3636
}
3737

@@ -119,6 +119,7 @@ tasks.register<JacocoReport>("jacocoAllReport") {
119119
)
120120
reports {
121121
xml.required.set(true)
122+
csv.required.set(true)
122123
html.required.set(true)
123124
}
124125
}
@@ -128,7 +129,7 @@ tasks.withType<JacocoCoverageVerification>().configureEach {
128129
}
129130

130131
jacoco {
131-
toolVersion = "0.8.12"
132+
toolVersion = libs.versions.jacoco.get()
132133
}
133134

134135
tasks.named<JacocoCoverageVerification>("jacocoTestCoverageVerification") {
@@ -157,12 +158,12 @@ tasks.named<JacocoCoverageVerification>("jacocoTestCoverageVerification") {
157158
limit {
158159
counter = "LINE"
159160
value = "COVEREDRATIO"
160-
minimum = "0.70".toBigDecimal()
161+
minimum = "0.80".toBigDecimal()
161162
}
162163
limit {
163164
counter = "BRANCH"
164165
value = "COVEREDRATIO"
165-
minimum = "0.55".toBigDecimal()
166+
minimum = "0.65".toBigDecimal()
166167
}
167168
}
168169
}

docs/architecture.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Network Chat Architecture
2+
3+
Network Chat is a small Java 21 TCP chat application with a deliberately simple runtime shape:
4+
5+
```text
6+
clients <-> ChatConnection <-> ChatProtocol <-> ChatServer
7+
```
8+
9+
## Runtime Flow
10+
11+
1. `ChatServer` opens a `ServerSocket` on the configured port.
12+
2. Each accepted socket is handled by a bounded client executor.
13+
3. The server sends `NAME_REQUEST`, waits for `USER_NAME`, validates uniqueness, then responds with
14+
`NAME_ACCEPTED`.
15+
4. Existing users are sent to the new client as `USER_ADDED` events.
16+
5. `TEXT` messages are broadcast to other clients with raw text in `data` and the author in
17+
`sender`.
18+
6. Closing or failed connections are removed and announced with `USER_REMOVED`.
19+
20+
## Message Frames
21+
22+
Frames are one-line UTF-8 JSON objects serialized by `ChatProtocol`.
23+
24+
- `type` is required for every frame.
25+
- `data` is optional for control frames, but required and non-blank for `TEXT`.
26+
- `sender` carries the author for `TEXT`; clients own display formatting.
27+
- `timestamp` and `messageId` are generated when a frame is created.
28+
- `data` is limited by `ChatMessage.MAX_DATA_LENGTH`.
29+
30+
## Server Limits
31+
32+
`ChatServerConfig` centralizes runtime limits:
33+
34+
- `port` - TCP port, default `1500`.
35+
- `maxClients` - maximum concurrent client handler threads, default `100`.
36+
- `handshakeTimeout` - maximum time to complete username registration, default `10s`.
37+
- `readTimeout` - idle socket read timeout after handshake, default `5m`.
38+
39+
The legacy `new ChatServer(int port)` constructor delegates to `ChatServerConfig.ofPort(port)`.
40+
41+
## Client Model
42+
43+
`ChatClient` owns the socket lifecycle and exposes hooks for console, bot, and Swing clients.
44+
Connection status is updated through a final template method before client-specific UI or console
45+
side effects run, so subclasses cannot skip the shared latch/status update.

docs/images/gui-client.svg

Lines changed: 18 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)