Commit Graph
1919 Commits
Author SHA1 Message Date
Vickey afaa899c19 test(auth): cover security-critical service impls with mockito
Add Mockito-based unit tests for the four ServiceImpl classes that the
TokenServiceImpl pipeline transitively trusts. Other ServiceImpls in
dc3-common-auth follow the same MyBatis-Plus CRUD shape and will be
covered as Testcontainers PG slice tests in a later stage where the
real schema can validate the lambda query wrappers end-to-end.

- TenantServiceImplTest (16): save / remove / update / selectById /
  selectByCode / selectByPage. Covers DuplicateException on save,
  NotFoundException on remove and update, AddException / DeleteException
  / UpdateException when the manager returns false, the same-row
  duplicate check during update, and Pages defaulting / preservation.
- UserLoginServiceImplTest (12): the standard CRUD trio plus the four
  selectByLoginName branches (blank + throw / blank + silent /
  not-found + throw / happy path) and the three checkLoginNameValid
  outcomes (unknown / disabled / enabled).
- UserPasswordServiceImplTest (9): the CRUD trio plus the password
  hashing assertion via DecodeUtil.md5 (save and update both rehash
  before persistence). Reset-password is asserted to set
  AlgorithmConstant.DEFAULT_PASSWORD before delegating to update.
- TenantBindServiceImplTest (8): CRUD trio plus the
  selectByTenantIdAndUserId branches and the null-id short circuit on
  listUserIdsByTenantId. The happy path of listUserIdsByTenantId
  requires mybatis-plus lambda metadata not available without a real
  ORM context and is deferred to the slice test stage.

Verified locally: 45 new cases green; dc3-common-auth now ships 69
unit tests across biz + service tiers.
2026-05-13 16:01:22 +08:00
Vickey fb99b84aa0 test(auth): cover biz layer with focus on token edge paths
Add the first batch of dc3-common-auth coverage targeting the security
sensitive biz/impl tier:

- TokenServiceImplTest covers the full credential pipeline:
  generateSalt rejects unknown tenants; generateToken rejects unknown
  tenant, unknown login, unbound user, missing password row, blank salt
  and mismatched md5; the happy path produces a JWT that parses with
  the same salt + tenant. checkValid covers the unknown-tenant throw,
  blank-token short-circuit, unknown-login + unbound-user invalid
  branches, the happy path that returns valid + expireTime, and the
  catch-all that swallows parser exceptions and returns invalid. 15
  cases in total — every UnAuthorizedException site has at least one
  dedicated test.
- DictionaryForAuthServiceImplTest covers the empty-tenant case and
  the label/value mapping path used by the admin UI.
- ResourceRegistrySyncServiceImplTest is intentionally narrow: it
  fails fast on null command, blank serviceName, blank or unsupported
  method, blank path; verifies removeMenuResource and syncMenuResource
  are null-safe and never touch the resource manager. Behavioural
  coverage of the full reconcile flow (insert / update / delete /
  grouping nodes) requires a real PostgreSQL schema and lands as a
  Testcontainers slice test in a later stage.

Verified locally: 24 cases green via mvn -pl dc3-common-auth test.
2026-05-13 15:51:22 +08:00
pnoker 10ff9da9ba test(common): cover indexed domain enums via shared contract
Add a single TestFactory-driven contract test under dc3-common-constant
that exercises every enum following the standard
"Byte index + getIndex() + ofIndex(Byte)" convention. For each constant
in each enum the contract asserts:

- getIndex() is non-null and unique within the enum;
- ofIndex(constant.getIndex()) round-trips back to the same constant;
- ofIndex of an unused byte value returns null (the contract used by
  the metadata cache to detect unknown rows).

31 enums are exercised in one place; adding a new enum that follows
the convention only requires adding its class literal to the
INDEXED_ENUMS list. TimeRangeKeyEnum is intentionally excluded because
it keys off a string code; its contract is exercised in
TimeRangeUtilTest.

MapStruct builder behaviour tests are intentionally deferred to the
business stages (S3 manager, S4 data, S5 driver, etc.) where the
builder lives next to its BO/VO/DO trio, so the tests can use the
real conversion fixtures without dragging cross-module dependencies
into dc3-common-constant.

Verified locally: 275 dynamic test cases across the 31 enums,
all green via mvn -pl dc3-common-constant test.
2026-05-13 15:28:00 +08:00
pnoker 425dbd7689 test(driver): cover binary codec helpers used by protocol drivers
Add unit tests for dc3-common-driver/CodecUtil, the byte-level helper
shared by every protocol driver:

- Base64 encode/decode round-trip across ASCII, UTF-8 and binary
  payloads.
- BCD <-> decimal-string round-trip including the odd-length leading
  zero trim path.
- bytesToHex emits two characters per byte and preserves leading zero.
- bytesToInt / bytesToIntLE compare big-endian and little-endian
  decoding plus the short-array zero-padding fallback.
- bytesToAscii uses ISO-8859-1 so non-printing bytes survive
  round-trip.
- byteReverse, mergerBytes, xorBytes and sumBytes assert the array
  manipulation invariants used by Modbus / S7 framing.

Note: dc3-common-exception coverage (CustomExceptionContractTest,
ExceptionMessageFormatterTest, ExceptionUtilTest) was committed in
parallel by Copilot in 85b9bd5f0; my locally written copies were
byte-identical so this commit only ships the driver codec piece
that is genuinely new.

Verified locally: 18 cases green via mvn -pl dc3-common-driver test.
2026-05-13 15:19:06 +08:00
pnoker 1e415cd44b refactor: standardize API routes and uploads 2026-05-13 15:06:48 +08:00
pnoker d82bea91ac test: add common exception coverage 2026-05-13 15:06:43 +08:00
pnoker 2480594aa0 test(public): cover optional wrappers and response entities
Round out the dc3-common-public coverage with the small wrapper types
that the rest of the platform relies on for null-safe field updates and
unified API envelopes:

- StringOptional / IntegerOptional / LongOptional / JsonOptional /
  CollectionOptional / EnableOptional tests assert that ifPresent and
  ifPresentOrElse fire (or do not fire) for present, null, empty,
  non-positive, invalid-JSON and unknown-enum-index inputs respectively.
  These guards are what stops MapStruct builders from clobbering
  existing rows with null/zero defaults during partial updates.
- R<T> tests cover all eight static factories (ok / fail with no args,
  message, ResponseEnum, enum + message, data, data + message) and the
  resulting envelope state. The data-overload cases use Integer payloads
  to disambiguate from the String-message overloads -- a subtle Java
  overload resolution corner that future contributors should not have
  to rediscover.
- Pages / TreeNode / Keys / RequestHeader cover their constructors,
  setters and the utility-class guards on the enclosing types.

Verified locally with `make test`: 52 new test cases green; total in
dc3-common-public is now 263 from this work-in-progress (an unrelated
contract test in the user's tree currently throws a regex error and is
not part of this commit).
2026-05-13 14:37:49 +08:00
pnoker 8768971ee3 test(public): cover time, regex, page, tree and lambda utilities
Continue the dc3-common-public coverage with the remaining stateless
helpers used across the platform:

- TimeUtilTest / LocalDateTimeUtilTest / ZoneDateTimeUtilTest cover
  format <-> parse round-trips, expireTime arithmetic and the null
  fallback path used when callers feed unparseable input.
- TimeRangeUtilTest covers the rolling-window resolver: TODAY / 24h /
  7d / 30d enum branches, the legacy hours/days fallback and the
  null-when-unbounded escape hatch, plus the wire-format code overload.
- RegexUtilTest exercises every matcher (numeric, name, phone, email,
  password, IPv4 host, driver port range) with parameterised positive
  and negative inputs.
- PageUtilTest validates Pages -> MyBatis-Plus Page coercion: nulls,
  current=0, size cap at MAX_PAGE_SIZE, default create_time order
  injection, idempotent create_time, copyPage records mapping plus the
  null-source short-circuit.
- TreeUtilTest covers buildByLoop / buildByRecursive / findChildren on
  empty input, single-root chains, multi-root and no-matching-root.
- MapStructUtilTest, FieldUtilTest, EnvironmentUtilTest, CodeUtilTest
  and HostUtilTest cover the smaller helpers used by builders, mapper
  lambdas and node-id generation.

Verified locally: 134 new test cases (212 total in dc3-common-public),
all green via `make test`.
2026-05-13 14:02:07 +08:00
pnoker 1f30422a07 test(public): cover arithmetic, codec, decode, json and key utilities
Add the first batch of unit tests under dc3-common-public covering the
core "stateless function" surface used everywhere else in the platform:

- ArithmeticUtilTest: precise add/subtract/multiply/divide/round across
  BigDecimal/float/double overloads, plus scale-bound rejections and
  division by zero.
- DecodeUtilTest: UTF-8 round-trips, MD5 stability and salting,
  Base64 byte/string round-trips and hex en/decoding.
- HmacAuthSignerTest: enabled/disabled state derivation from the secret,
  hex digest stability, mismatched-payload + mismatched-secret behavior,
  null-payload guards and constant-time verification on length mismatch.
- JsonUtilTest: parseObject/parseArray from String/byte[]/InputStream/
  TypeReference, isJson validation, toJsonString/Bytes round-trip and
  unknown-property tolerance.
- KeyUtilTest: AES and RSA encrypt/decrypt round-trips, JWT signing
  followed by salt/subject/tenant rejection paths.

The Makefile test/test-it/test-e2e/coverage targets get an explicit
-Dmaven.test.skip=false override because .mvn/maven.config sets the
flag globally so `mvn package` does not run tests; without the override
the new targets would silently produce empty reports.

dc3-common-public/pom.xml declares spring-boot-starter-test test-scope.

Verified locally: 77 new test cases run via `make test`, all green.
2026-05-13 14:01:26 +08:00
pnoker ade8579369 fix(test-infra): propagate test bom into dc3-common dependency management
Maven dependencyManagement does not flow across the iot-dc3 root reactor
into dc3-common because dc3-common inherits from the externally
published dc3-parent. As a result, dc3-common-test could not resolve
JUnit 5 / Testcontainers / Instancio dependencies and dc3-e2e could not
resolve dc3-common-test itself.

Mirror the relevant slice of test-toolchain version management into
dc3-common/pom.xml (junit-bom + testcontainers-bom imports plus pinned
versions for AssertJ, Awaitility, Instancio, REST-assured and WireMock)
and add the missing dc3-common-test version entry to the iot-dc3 root
dependencyManagement so the e2e module can import it.

Verified locally with mvn -B clean compile -pl dc3-common/dc3-common-test -am,
which now resolves all 9 source files and produces
dc3-common-test-2026.5.5.jar.
2026-05-13 13:17:55 +08:00
Vickey 10e0836026 docs(test): add testing guide and update validation checklist
Introduce dc3/doc/TESTING.md as the canonical reference for the iot-dc3
test pyramid, naming conventions, time/randomness isolation rules,
Testcontainers conventions pinned to the production timescaledb-ha:pg18
image, fixture data strategy, contract base classes shipped by
dc3-common-test, the make commands developers run locally and the
ci.yml/test.yml/e2e.yml workflow contract.

Update AGENTS.md so:

- The Validation Checklist references make test, make test-it,
  make coverage and proto contract tests; coverage regressions over 1%
  block PRs.
- The Documentation Rules section now lists TESTING.md alongside the
  other domain-specific docs to keep the guide current as the harness
  evolves.

This closes the S0 stage of the test build-out: every subsequent stage
(S1..S8) will deliver business test cases under the layout defined here.
2026-05-13 13:10:50 +08:00
Vickey efd26c645b ci: add unit, integration and e2e workflows with makefile targets
Wire the test toolchain into developer-facing entry points and CI:

- Makefile gains test, test-it, test-e2e and coverage targets; the help
  banner advertises them alongside the existing build commands so
  contributors do not need to memorise the underlying mvn invocations.
- A new Test workflow runs three sequenced jobs: unit (mvn test, skipping
  the integration phase), integration (mvn verify, skipping unit phase,
  running with TESTCONTAINERS_REUSE_ENABLE=true), and a final coverage
  job that downloads both jacoco .exec artifacts and rebuilds the
  aggregate report from dc3-coverage.
- A new E2E workflow runs make test-e2e on develop/release/main pushes
  and on manual dispatch, with a 90 minute timeout that accommodates
  cold compose start-up plus the full critical path battery.
- The existing CI workflow keeps its fast-fail compile job unchanged so
  PR feedback latency stays low; tests are now owned exclusively by
  the new Test workflow.
2026-05-13 13:08:28 +08:00
Vickey c47e5f0a37 test(infra): add coverage and end-to-end aggregator modules
Introduce two reactor modules that exist purely to host repository-wide
test concerns:

- dc3-coverage (packaging=pom) runs jacoco:report-aggregate against all
  contributing modules and applies a tree-wide jacoco:check rule. The
  aggregator excludes generated sources, deployable Application classes,
  POJO entity packages and the third-party modbus4j sero utilities so
  the percentage stays anchored on real business logic. Coverage gates
  start at 0% and tighten in later stages as more tests land.
- dc3-e2e (packaging=jar) reserves a place for the docker-compose driven
  end-to-end suite delivered in stage S8. Unit and integration phases
  are skipped by default and only the e2e profile turns them on.

Both modules are wired into the root reactor.
2026-05-13 13:02:26 +08:00
Vickey a3e95968bc test(infra): wire test bom and plugins in root pom
Centralise test toolchain wiring at the iot-dc3 root pom so child modules
do not need to repeat versions or plugin definitions:

- Import the JUnit 5 and Testcontainers BOMs and pin AssertJ, Awaitility,
  Instancio, REST-assured and WireMock versions.
- Add Surefire 3.5.2 and Failsafe 3.5.2 plugin management with the
  expected include patterns (*Test.java for unit, *IT.java for
  integration) plus argLine wiring for the Jacoco agents.
- Add Jacoco 0.8.12 plugin management with both unit and integration
  agent + report executions; integration coverage lands in jacoco-it.exec
  while unit coverage stays in jacoco.exec.
- Surface skip.unit.tests and skip.integration.tests properties so CI and
  Makefile targets can flip phases without rewriting plugin configuration.

The new plugins are enabled at this layer; subsequent commits add the
aggregator coverage module that reads both .exec files and the workflows
that exercise them.
2026-05-13 11:14:21 +08:00
Vickey 36ffe2bb6f test(infra): introduce dc3-common-test module with shared fixtures
Bootstrap dc3-common-test, a new infrastructure-only Maven module under
dc3-common that ships:

- Reusable Testcontainers wrappers for the production-aligned
  timescale/timescaledb-ha:pg18 image, RabbitMQ with publisher confirms
  and Eclipse Mosquitto MQTT broker.
- JUnit 5 support beans: a fixed Clock configuration, an in-process gRPC
  extension, an Awaitility-backed Rabbit harness and JSON assertion
  helpers.
- Reusable contract base classes for domain enum index round-trips and
  for asserting that secret-bearing fields never leak through Lombok
  toString() output.
- A test profile (application-test.yml) and logback config aligned with
  the production RabbitMQ confirm/return semantics.

Module-specific fixtures that depend on business BO/VO/DO types are
deliberately deferred to their owning modules' src/test trees to avoid
introducing reverse dependencies into dc3-common-test.

This commit only adds the new module; no other module consumes it yet.
The test BOM and plugin wiring that exposes it as a test-scope artifact
to the rest of the tree lands in a follow-up commit.
2026-05-13 11:10:25 +08:00
Vickey c19720090f chore(test): remove playwright leftover and harden gitignore
Drop the stale `test-results/.last-run.json` Playwright artifact at the
backend repo root and extend `.gitignore` to cover surefire, failsafe and
jacoco report directories plus testcontainers state, in preparation for
the upcoming test infrastructure bootstrap.
2026-05-13 11:00:14 +08:00
pnoker aa0da35727 refactor: simplify PointController, extract ChatClientFactory and remove deprecated service methods 2026-05-13 09:08:11 +08:00
pnoker 37294b1771 fix(backend): support group and label settings 2026-05-12 20:58:54 +08:00
pnoker d99e6cb2c1 style: reorder imports and fix doc table alignment 2026-05-12 08:32:14 +08:00
pnoker 6fcc11da11 refactor(agentic): use enum types in requests and fix default model resolution
- Change ModelConfigRequest/ModelProviderRequest defaultFlag and
  enableFlag from Byte to DefaultFlagEnum/EnableFlagEnum, aligning
  with Jackson's default enum name serialization.
- Remove redundant @AfterMapping enum conversion in builders since
  Jackson now handles enum deserialization natively.
- Add @Primary ChatClient.Builder bean to resolve Spring AI
  ChatModel ambiguity when multiple providers are configured.
- Replace hardcoded DEFAULT_MODEL ("dc3-agentic") with DB-driven
  resolution via ChatClientFactory.resolveModel(), falling back to
  the defaultFlag=DEFAULT model config when no model is specified.
2026-05-12 08:31:56 +08:00
pnoker 8f33f53944 fix(builder): suppress MapStruct unmapped target property warnings
Add @Mapping ignores for tenantId/userId on VO→BO builders and
groupId/labelId on query builders — these fields are resolved by
the service layer, not by MapStruct.
2026-05-12 08:31:32 +08:00
pnoker f859750c8f feat(manager): filter entities by group and label 2026-05-11 20:58:46 +08:00
pnoker 97c7094a7d feat(manager): add group and label binding APIs 2026-05-11 20:58:29 +08:00
pnoker ebf8bbefe0 refactor(domain): align group and label taxonomy enums 2026-05-11 20:58:10 +08:00
pnoker 8f0f171c34 security(auth): exclude credentials from toString 2026-05-11 19:14:47 +08:00
pnoker 0d8ac8d088 refactor(domain): use enums for business flags 2026-05-11 19:14:41 +08:00
pnoker 88a114f8ac docs(agent): document domain modeling conventions 2026-05-11 19:14:33 +08:00
pnoker 2d60ebe134 refactor(agentic): standardize domain mapping 2026-05-11 18:58:43 +08:00
pnoker 989443e99f docs(agentic): document provider configuration 2026-05-11 18:58:19 +08:00
pnoker 285ed9273f feat(agentic): configure fallback provider and profile activation 2026-05-11 18:57:53 +08:00
pnoker 6d97de316d docs: update AGENTS.md with project architecture and workflow instructions 2026-05-11 15:34:41 +08:00
pnoker d65fc715ff build(deploy): add agentic memory and tool-calling env variables to docker-compose
Expose AGENTIC_MEMORY_ENABLED, AGENTIC_TOOL_CALLING_ENABLED,
AGENTIC_MEMORY_MAX_MESSAGES, and AGENTIC_ATTACHMENT_STORAGE_PATH
in development and production compose files, with defaults in dev.env.

Also mark OpenAI base-url config as deprecated in application-agentic.yml.
2026-05-11 00:44:44 +08:00
pnoker 2927840667 build(agentic): add spring-ai-starter-model-anthropic dependency
Enable Anthropic model provider support alongside the existing OpenAI
starter, so ChatClientFactory can create Claude-backed clients.
2026-05-11 00:44:31 +08:00
pnoker 53f6272e89 refactor(agentic): bind ModelConfig to provider via providerId foreign key
Replace inline `provider` and `baseUrl` string fields with a `providerId`
reference to ModelProvider. Add provider existence validation on save/update.
Thread user identity (creator/operator) into ModelConfig save and update
operations via UserHeader.

Also switch ModelController add/update endpoints from synchronous to
reactive async with UserHeader resolution.
2026-05-11 00:44:24 +08:00
pnoker 0f3a08d905 refactor(agentic): replace ChatClient singleton with per-provider factory
Each model provider (OpenAI, Anthropic, etc.) needs its own ChatClient
instance with provider-specific credentials. Extract ChatClient creation
into ChatClientFactory and resolve the client dynamically at request time.

Also reduce ChatClientConfig scope to only ChatMemory/JDBC setup.
2026-05-11 00:44:09 +08:00
pnoker 66a364df31 feat(agentic): add ModelProvider module with CRUD operations
Introduce ModelProvider as a standalone entity so model configurations
reference a provider by foreign key instead of inline provider/baseUrl
strings. Includes entity, mapper, manager, service, and controller.
2026-05-11 00:43:56 +08:00
Vickey 9d7e238eb1 refactor(config): update default AI model to deepseek-v4-flash and agentic env variables v2026.5.10 2026-05-10 21:43:58 +08:00
Vickey d721b01c51 feat(agentic): add message, attachment, action, model config and skill submodules 2026-05-10 21:43:58 +08:00
Vickey 480054d9a8 fix(manager): guard profile bind removal and initialize empty device list 2026-05-10 21:43:58 +08:00
Vickey c5f1d8bd96 fix(driver): tolerate incomplete attribute config and relax name pattern 2026-05-10 21:43:58 +08:00
Vickey 46b8c54af4 feat(auth): auto-manage tenant binding on user create and delete 2026-05-10 21:43:58 +08:00
Vickey f08d311018 fix(auth): use @NotNull instead of @NotBlank for Long parent ID fields 2026-05-10 21:43:58 +08:00
Vickey 7e04ffd13c refactor(web): remove context-path WebFilter from WebFilterConfig 2026-05-10 21:43:58 +08:00
Vickey ca45788d50 style(java): sort imports and remove unused imports across modules 2026-05-10 21:43:57 +08:00
Vickey cdb05e7aff fix(log): revert LogsAspect to @Configuration — module lacks autoconfigure dependency
dc3-common-log does not depend on spring-boot-autoconfigure, so
@AutoConfiguration cannot be resolved. Keep @Configuration for this
module.
2026-05-10 11:41:13 +08:00
pnoker 6f0b7d0496 fix(web): read reactive context-path from Environment instead of ServerProperties
ServerProperties.Reactive does not expose getContextPath() in Boot 4.x.
Use Environment.getProperty("server.reactive.context-path") instead.
2026-05-10 11:37:10 +08:00
pnoker f5045c7392 fix(config): restore spring.factories for EnvironmentPostProcessor loading
Spring Boot 4.0.6 still loads EnvironmentPostProcessor implementations
via SpringFactoriesLoader from META-INF/spring.factories, not from the
new .imports file. The .imports mechanism only applies to
AutoConfiguration classes.

The previous commit incorrectly deleted all spring.factories files,
which broke profile activation for every service (auth, data, manager,
gateway, etc.). Restore them with only the EnvironmentPostProcessor
entries (EnableAutoConfiguration entries remain removed since those
use AutoConfiguration.imports).
2026-05-10 11:33:04 +08:00
pnoker 252c55b83d refactor(driver): rename DriverCustomServiceImpl to protocol-specific class names
Rename the generic DriverCustomServiceImpl in each driver module to a
protocol-specific name (e.g., ModbusTcpDriverCustomServiceImpl) so
that static analysis tools can scan every driver module without
filtering duplicate fully-qualified class names. Update
DRIVER-AUTHORING.md to reflect the new convention.
2026-05-10 11:25:55 +08:00
pnoker 3ffcd9bd5c style(auth): move ResourceRepairResult record to end of ResourceRegistrySyncServiceImpl
Remove blank lines between field declarations for consistency.
2026-05-10 11:25:36 +08:00
Vickey 260d2b83ae style(java): align Javadoc @param indentation in resource-registrar 2026-05-10 11:25:25 +08:00