All checks were successful
Verification / Is-Buildable (push) Successful in 3m8s
:Release Notes: - :Detailed Notes: - :Testing Performed: - was not verified, to be fair :D :QA Notes: - generated by glm-5.2 :Issues Addressed: TG-3
184 lines
6.8 KiB
Markdown
184 lines
6.8 KiB
Markdown
# Build & Testing
|
||
|
||
## Build system
|
||
|
||
The project uses **Meson** with **Ninja** and requires a **C++20** compiler (GCC or Clang). The root `meson.build` declares the project and dependencies; `src/meson.build` and `tests/meson.build` define build targets.
|
||
|
||
### Dependencies
|
||
|
||
All dependencies are resolved via Meson wrap files in `subprojects/` or system packages:
|
||
|
||
| Dependency | Wrap file | Purpose |
|
||
|---|---|---|
|
||
| nlohmann_json | `nlohmann_json.wrap` | JSON parsing |
|
||
| asio | `asio.wrap` | TCP networking (header-only) |
|
||
| glog | `glog.wrap` (CMake subproject) | Logging |
|
||
| yaml-cpp | `yaml-cpp.wrap` | Config file parsing |
|
||
| aklomp-base64 | `aklomp-base64.wrap` | Base64 encode/decode |
|
||
| GoogleTest | `gtest.wrap` | Unit testing (gtest + gmock) |
|
||
|
||
The `rpc/` directory is a git submodule pointing to [json-rpc-cxx](https://github.com/jsonrpcx/json-rpc-cxx), providing `jsonrpccxx/` headers used by the client. It is included via `include_directories` in the root `meson.build`.
|
||
|
||
### Build targets
|
||
|
||
Defined in `src/meson.build`:
|
||
|
||
**Shared libraries:**
|
||
| Library | Sources | Notes |
|
||
|---|---|---|
|
||
| `libcloud_point_rpc` | `rpc_coder.cpp`, `rpc_server.cpp`, `server_api.cpp`, `service.cpp` | Core library, installed with `install_rpath: '$ORIGIN'` |
|
||
| `libcloud_point_rpc_cli` | `cli.cpp` | CLI client logic |
|
||
| `test_cloud_point` | `test_api.cpp` | Test API library |
|
||
|
||
**Executables:**
|
||
| Executable | Source | Description |
|
||
|---|---|---|
|
||
| `cloud_point_rpc_server` | `server_main.cpp` | Standalone mock server |
|
||
| `cloud_point_rpc_cli` | `main.cpp` | Interactive CLI client |
|
||
| `minimal_client` | `minimal_client.cpp` | Minimal client sending a hardcoded `ping` |
|
||
|
||
### Linux build
|
||
|
||
```bash
|
||
git submodule init && git submodule update
|
||
meson setup build
|
||
meson compile -C build
|
||
```
|
||
|
||
Run the server:
|
||
```bash
|
||
./build/src/cloud_point_rpc_server config.yaml
|
||
```
|
||
|
||
Run the CLI client:
|
||
```bash
|
||
./build/src/cloud_point_rpc_cli config.yaml
|
||
```
|
||
|
||
### Windows build
|
||
|
||
Windows requires static linking and a Python venv for Meson:
|
||
|
||
```powershell
|
||
git submodule init
|
||
git submodule update
|
||
python3 -m venv .\venv
|
||
.\venv\Scripts\Activate.ps1
|
||
pip install meson cmake
|
||
meson setup -Ddefault_library=static build
|
||
meson compile -C build
|
||
# To get DLLs on PATH:
|
||
meson devenv -C build
|
||
```
|
||
|
||
The root `meson.build` adds a `devenv` on Windows that appends subproject DLL directories to `PATH` when `default_library=shared`. When building static, the build defines `BASE64_STATIC_DEFINE` and `YAML_CPP_STATIC_DEFINE`.
|
||
|
||
### Clean build
|
||
|
||
```bash
|
||
meson compile --clean -C build
|
||
```
|
||
|
||
## Configuration
|
||
|
||
The server reads a YAML config file. Sample: `config.yml`:
|
||
|
||
```yaml
|
||
server:
|
||
ip: "127.0.0.1"
|
||
port: 9095
|
||
```
|
||
|
||
Full config schema (parsed by `ConfigLoader` in `include/cloud_point_rpc/config.hpp`):
|
||
|
||
| Section | Field | Type | Default | Description |
|
||
|---|---|---|---|---|
|
||
| `server.ip` | string | `127.0.0.1` | Server bind address |
|
||
| `server.port` | int | `8080` | Server listen port |
|
||
| `test_data.intrinsic_params` | list of double | empty (fallback to identity 3×3) | Camera intrinsic parameters |
|
||
| `test_data.extrinsic_params` | list of double | empty (fallback to identity 4×4) | Camera extrinsic parameters |
|
||
| `test_data.cloud_point` | list of lists of double | empty (fallback to 3 sample points) | Point cloud data |
|
||
|
||
The `test_data` section is only used by the standalone mock server (`server_main.cpp`). The C API path (`crpc_init`) loads config for server address but does not use `test_data` — Unity provides its own handlers.
|
||
|
||
## Docker
|
||
|
||
The `Dockerfile` uses Ubuntu 24.04 and builds the CLI client. It installs build dependencies, copies the project, runs `meson setup build && meson compile -C build`, and starts the CLI by default.
|
||
|
||
```bash
|
||
docker build -t cloud-point-rpc .
|
||
docker run --network=host -it cloud-point-rpc
|
||
```
|
||
|
||
Mount a custom config:
|
||
```bash
|
||
docker run --network=host -it -v $(pwd)/my_config.yaml:/app/config.yaml cloud-point-rpc
|
||
```
|
||
|
||
> The server is not configured to run inside Docker — only the CLI client. The `--network=host` flag simplifies connectivity to a server running on the host.
|
||
|
||
## CI
|
||
|
||
`.gitea/workflows/test.yaml` defines a Gitea Actions workflow named "Verification" that runs on push to `master`:
|
||
|
||
1. Install build tools (cmake, make, ninja, gcc)
|
||
2. Install Meson via pip in a venv
|
||
3. Checkout with submodules
|
||
4. `meson setup build && meson compile -C build -j2`
|
||
5. `meson test -C build`
|
||
|
||
## Testing
|
||
|
||
All tests are in `tests/` and compiled into a single `unit_tests` executable (defined in `tests/meson.build`) linked against `cloud_point_rpc_dep`, `cloud_point_rpc_cli_dep`, `cloud_point_rpc_test_dep`, and GoogleTest/GMock.
|
||
|
||
### Run tests
|
||
|
||
```bash
|
||
meson test -C build # all tests
|
||
meson test -C build -v # verbose
|
||
meson test -C build unit_tests # explicit
|
||
```
|
||
|
||
### Test suites
|
||
|
||
| File | Area | Description |
|
||
|---|---|---|
|
||
| `test_rpc.cpp` | RPC server | Basic request/response, method dispatch |
|
||
| `test_rpc_edge_cases.cpp` | RPC server | Edge cases: invalid JSON, missing fields, non-object requests |
|
||
| `test_tcp.cpp` | TCP server | TCP connection and message round-trip |
|
||
| `test_tcp_edge_cases.cpp` | TCP server | TCP edge cases |
|
||
| `test_integration.cpp` | Integration | Full server+client stack with mock data, real TCP |
|
||
| `test_cli.cpp` | CLI | CLI client menu and output |
|
||
| `test_c_api.cpp` | C API | `crpc_test_*` functions, callback registration, auto-call |
|
||
| `test_c_api_edge_cases.cpp` | C API | Multiple methods, removal, scheduling |
|
||
| `test_base64.cpp` | Base64 | Encode/decode round-trip |
|
||
| `test_base64_edge_cases.cpp` | Base64 | Edge cases (empty input, binary with nulls) |
|
||
| `test_serialize.cpp` | Serialization | `serialize`/`deserialize` for numeric types, `inplace_size_embedding` |
|
||
| `test_service.cpp` | Service | Default fallbacks, configured data, empty data |
|
||
|
||
### Test conventions
|
||
|
||
- All test fixtures initialize Google Logging in `SetUp()` with `FLAGS_logtostderr = true`.
|
||
- Integration tests (`test_integration.cpp`) create a temporary `config.yaml`, start a real `TcpServer` in a thread, and connect via `TCPConnector`/`RpcClient`.
|
||
- C API tests use `crpc_test_init()` / `crpc_test_deinit()` and verify callback invocation via `std::promise`/`std::future`.
|
||
- The latest commit (`9de6f5a`) added `google::InitGoogleLogging` calls in test files to ensure logging is initialized before glog macros are used.
|
||
|
||
### Linting
|
||
|
||
The project uses clang-format with LLVM base style and 4-space indent (`.clang-format`):
|
||
|
||
```bash
|
||
ninja -C build clang-format
|
||
# or
|
||
find src include tests -name "*.cpp" -o -name "*.hpp" | xargs clang-format -i
|
||
```
|
||
|
||
## Source references
|
||
|
||
- `meson.build` — Root build config, dependency declarations
|
||
- `src/meson.build` — Library and executable targets
|
||
- `tests/meson.build` — Test executable definition
|
||
- `config.yml` — Sample config
|
||
- `Dockerfile` — Container build
|
||
- `.gitea/workflows/test.yaml` — CI pipeline
|
||
- `.clang-format` — Code formatting config |