From b19c94d7906a3520c2ff27fecc333616f022cdb6 Mon Sep 17 00:00:00 2001 From: Szymon Sasin Date: Wed, 21 Jun 2023 14:45:12 +0300 Subject: [PATCH 1/2] Refactor CoapResponse with builder pattern resp --- coap-cli/build.gradle.kts | 1 + .../com/mbed/coap/cli/DeviceEmulator.java | 11 +- .../java/com/mbed/coap/cli/CoapCliTest.java | 11 +- .../java/microbenchmark/ServerBenchmark.java | 8 +- .../coap/exception/CoapCodeException.java | 9 +- .../exception/CoapRequestEntityTooLarge.java | 23 +-- .../mbed/coap/packet/CoapOptionsBuilder.java | 2 +- .../com/mbed/coap/packet/CoapResponse.java | 173 +++++++++++------- .../mbed/coap/packet/SeparateResponse.java | 4 +- .../coap/server/CriticalOptionVerifier.java | 6 +- .../com/mbed/coap/server/RescueFilter.java | 2 +- .../com/mbed/coap/server/RouterService.java | 3 +- .../coap/server/block/BlockWiseCallback.java | 4 +- .../server/block/BlockWiseIncomingFilter.java | 11 +- .../block/BlockWiseNotificationFilter.java | 2 +- .../server/filter/EtagGeneratorFilter.java | 16 +- .../filter/MaxAllowedPayloadFilter.java | 11 +- .../coap/server/observe/ObserversManager.java | 10 +- .../com/mbed/coap/client/CoapClientTest.java | 2 +- .../mbed/coap/packet/CoapResponseTest.java | 113 +++++++++++- .../coap/packet/SeparateResponseTest.java | 2 +- .../server/NotificationValidatorTest.java | 15 +- .../coap/server/ObserveRequestFilterTest.java | 2 +- .../mbed/coap/server/RoutingServiceTest.java | 1 + .../server/block/BlockWiseCallbackTest.java | 9 +- .../block/BlockWiseIncomingFilterTest.java | 1 + .../BlockWiseNotificationFilterTest.java | 2 +- .../block/BlockWiseOutgoingFilterTest.java | 7 +- .../coap/server/filter/EchoFilterTest.java | 7 +- .../filter/EtagValidatorFilterTest.java | 6 +- .../filter/MaxAllowedPayloadFilterTest.java | 5 +- .../filter/TokenGeneratorFilterTest.java | 1 + .../server/messaging/ExchangeFilterTest.java | 3 +- .../server/observe/ObserversManagerTest.java | 14 +- .../ClientServerWithBlocksTest.java | 4 +- .../test/java/protocolTests/ClientTest.java | 1 + .../java/protocolTests/DuplicateTest.java | 2 +- .../NonConfirmableTransactionsTest.java | 1 + .../java/com/mbed/coap/utils/Assertions.java | 26 +++ .../mbed/coap/utils/ObservableResource.java | 10 +- .../protocolTests/IntegrationTestBase.java | 27 +-- .../utils/StubNotificationsReceiver.java | 4 +- .../mbedtls/MbedtlsCoapTransportTest.java | 1 + .../transport/mbedtls/MbedtlsNettyTest.java | 2 +- coap-metrics/build.gradle.kts | 1 + .../MicrometerMetricsFilterTest.java | 2 +- .../org/opencoap/coap/netty/NettyTest.java | 2 +- .../packet/CoapTcpPacketConverterTest.java | 2 +- .../messaging/TcpExchangeFilterTest.java | 1 + 49 files changed, 386 insertions(+), 197 deletions(-) create mode 100644 coap-core/src/testFixtures/java/com/mbed/coap/utils/Assertions.java diff --git a/coap-cli/build.gradle.kts b/coap-cli/build.gradle.kts index a7904961..5725cc4f 100644 --- a/coap-cli/build.gradle.kts +++ b/coap-cli/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0") testImplementation("org.awaitility:awaitility:4.2.0") + testImplementation(testFixtures(project(":coap-core"))) } tasks { diff --git a/coap-cli/src/main/java/com/mbed/coap/cli/DeviceEmulator.java b/coap-cli/src/main/java/com/mbed/coap/cli/DeviceEmulator.java index bf56ce2f..3bdce85b 100644 --- a/coap-cli/src/main/java/com/mbed/coap/cli/DeviceEmulator.java +++ b/coap-cli/src/main/java/com/mbed/coap/cli/DeviceEmulator.java @@ -16,7 +16,6 @@ */ package com.mbed.coap.cli; -import static java.util.concurrent.CompletableFuture.completedFuture; import com.mbed.coap.client.RegistrationManager; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; @@ -77,7 +76,7 @@ public Integer call() throws Exception { } protected Service createRouting() { - Service timeResource = __ -> completedFuture(CoapResponse.ok(Instant.now().toString())); + Service timeResource = __ -> CoapResponse.ok(Instant.now().toString()).toFuture(); scheduledExecutor.scheduleAtFixedRate(() -> obsManager.sendObservation("/time", timeResource), @@ -85,12 +84,12 @@ protected Service createRouting() { ); return RouterService.builder() - .get("/3/0/1", __ -> completedFuture(CoapResponse.ok("Acme"))) - .get("/3/0/2", __ -> completedFuture(CoapResponse.ok("Emulator"))) - .get("/3/0/3", __ -> completedFuture(CoapResponse.ok("0.0.1"))) + .get("/3/0/1", __ -> CoapResponse.ok("Acme").toFuture()) + .get("/3/0/2", __ -> CoapResponse.ok("Emulator").toFuture()) + .get("/3/0/3", __ -> CoapResponse.ok("0.0.1").toFuture()) .get("/delayed-10s", __ -> { CompletableFuture promise = new CompletableFuture<>(); - scheduledExecutor.schedule(() -> promise.complete(CoapResponse.ok("OK")), 10, TimeUnit.SECONDS); + scheduledExecutor.schedule(() -> promise.complete(CoapResponse.ok("OK").build()), 10, TimeUnit.SECONDS); return promise; }) .get("/time", obsManager.then(timeResource)) diff --git a/coap-cli/src/test/java/com/mbed/coap/cli/CoapCliTest.java b/coap-cli/src/test/java/com/mbed/coap/cli/CoapCliTest.java index 35122183..0ab88f8a 100644 --- a/coap-cli/src/test/java/com/mbed/coap/cli/CoapCliTest.java +++ b/coap-cli/src/test/java/com/mbed/coap/cli/CoapCliTest.java @@ -16,16 +16,17 @@ package com.mbed.coap.cli; import static com.mbed.coap.packet.BlockSize.S_16; +import static com.mbed.coap.packet.CoapRequest.get; +import static com.mbed.coap.packet.CoapResponse.coapResponse; +import static com.mbed.coap.packet.CoapOptionsBuilder.options; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.transport.udp.DatagramSocketTransport.udp; import static java.lang.String.format; -import static java.util.concurrent.CompletableFuture.completedFuture; import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import com.mbed.coap.packet.CoapRequest; -import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Code; import com.mbed.coap.packet.MediaTypes; import com.mbed.coap.packet.Opaque; @@ -54,10 +55,10 @@ void beforeAll() throws IOException { .route(RouterService.builder() .post("/rd", req -> { String epName = req.options().getUriQueryMap().get("ep"); - return completedFuture(CoapResponse.of(Code.C201_CREATED, Opaque.EMPTY, o -> o.locationPath("/rd/" + epName))); + return coapResponse(Code.C201_CREATED).locationPath("/rd/" + epName).toFuture(); }) - .get("/test", __ -> completedFuture(ok("Dziala!"))) - .post("/test", req -> completedFuture(ok("Received " + req.getPayload().size()))) + .get("/test", __ -> ok("Dziala!").toFuture()) + .post("/test", req -> ok("Received " + req.getPayload().size()).toFuture()) ) .build() diff --git a/coap-core/src/jmh/java/microbenchmark/ServerBenchmark.java b/coap-core/src/jmh/java/microbenchmark/ServerBenchmark.java index 023cb5b0..ce08fb0e 100644 --- a/coap-core/src/jmh/java/microbenchmark/ServerBenchmark.java +++ b/coap-core/src/jmh/java/microbenchmark/ServerBenchmark.java @@ -15,7 +15,6 @@ */ package microbenchmark; -import static java.util.concurrent.CompletableFuture.completedFuture; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import com.mbed.coap.exception.CoapException; @@ -66,10 +65,9 @@ public void setup() throws CoapException, IOException { server = CoapServer.builder() .transport(mockTransport) .route(RouterService.builder() - .get("/path1/sub2/sub3", __ -> completedFuture( - CoapResponse.ok("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890") - .maxAge(requestCounter++) - )) + .get("/path1/sub2/sub3", __ -> + CoapResponse.ok("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890").maxAge((int) requestCounter++).toFuture() + ) ) .build(); server.start(); diff --git a/coap-core/src/main/java/com/mbed/coap/exception/CoapCodeException.java b/coap-core/src/main/java/com/mbed/coap/exception/CoapCodeException.java index 7b22689c..a5899314 100644 --- a/coap-core/src/main/java/com/mbed/coap/exception/CoapCodeException.java +++ b/coap-core/src/main/java/com/mbed/coap/exception/CoapCodeException.java @@ -1,5 +1,5 @@ -/** - * Copyright (C) 2022 java-coap contributors (https://github.com/open-coap/java-coap) +/* + * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) * Copyright (C) 2011-2018 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,6 +16,7 @@ */ package com.mbed.coap.exception; +import static com.mbed.coap.packet.CoapResponse.coapResponse; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Code; @@ -46,7 +47,7 @@ public Code getCode() { return code; } - public CoapResponse toResponse() { - return CoapResponse.of(code, getMessage()); + public CoapResponse.Builder toResponse() { + return coapResponse(code).payload(getMessage()); } } diff --git a/coap-core/src/main/java/com/mbed/coap/exception/CoapRequestEntityTooLarge.java b/coap-core/src/main/java/com/mbed/coap/exception/CoapRequestEntityTooLarge.java index 5b0e63fe..e93e1ba5 100644 --- a/coap-core/src/main/java/com/mbed/coap/exception/CoapRequestEntityTooLarge.java +++ b/coap-core/src/main/java/com/mbed/coap/exception/CoapRequestEntityTooLarge.java @@ -1,5 +1,5 @@ -/** - * Copyright (C) 2022 java-coap contributors (https://github.com/open-coap/java-coap) +/* + * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) * Copyright (C) 2011-2018 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,14 +38,15 @@ public CoapRequestEntityTooLarge(BlockOption blockOptionHint, String message) { } @Override - public CoapResponse toResponse() { - CoapResponse resp = super.toResponse(); - if (maxSize > 0) { - resp.options().setSize1(maxSize); - } - if (blockOptionHint != null) { - resp.options().setBlock1Req(blockOptionHint); - } - return resp; + public CoapResponse.Builder toResponse() { + return super.toResponse() + .options(o -> { + if (maxSize > 0) { + o.size1(maxSize); + } + if (blockOptionHint != null) { + o.block1Req(blockOptionHint); + } + }); } } diff --git a/coap-core/src/main/java/com/mbed/coap/packet/CoapOptionsBuilder.java b/coap-core/src/main/java/com/mbed/coap/packet/CoapOptionsBuilder.java index aaf254e8..4b124781 100644 --- a/coap-core/src/main/java/com/mbed/coap/packet/CoapOptionsBuilder.java +++ b/coap-core/src/main/java/com/mbed/coap/packet/CoapOptionsBuilder.java @@ -30,7 +30,7 @@ public static CoapOptionsBuilder from(HeaderOptions options) { return new CoapOptionsBuilder(options.duplicate()); } - CoapOptionsBuilder(HeaderOptions options) { + private CoapOptionsBuilder(HeaderOptions options) { this.options = options; } diff --git a/coap-core/src/main/java/com/mbed/coap/packet/CoapResponse.java b/coap-core/src/main/java/com/mbed/coap/packet/CoapResponse.java index e3ebe3ca..864305c5 100644 --- a/coap-core/src/main/java/com/mbed/coap/packet/CoapResponse.java +++ b/coap-core/src/main/java/com/mbed/coap/packet/CoapResponse.java @@ -1,6 +1,5 @@ /* * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) - * Copyright (C) 2011-2021 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +17,7 @@ import com.mbed.coap.transport.TransportContext; import java.net.InetSocketAddress; +import java.time.Duration; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -39,10 +39,6 @@ public static CoapResponse of(Code code) { return new CoapResponse(code, Opaque.EMPTY, new HeaderOptions()); } - public static CoapResponse coapResponse(Code code) { - return new CoapResponse(code, Opaque.EMPTY, new HeaderOptions()); - } - public static CoapResponse of(Code code, Opaque payload) { return new CoapResponse(code, payload, new HeaderOptions()); } @@ -51,46 +47,38 @@ public static CoapResponse of(Code code, Opaque payload, HeaderOptions options) return new CoapResponse(code, payload, options); } - public static CoapResponse of(Code code, Opaque payload, Consumer optionsFunc) { - CoapOptionsBuilder options = CoapOptionsBuilder.options(); - optionsFunc.accept(options); - return new CoapResponse(code, payload, options.build()); - } - - public static CoapResponse of(Code code, Opaque payload, short contentFormat) { - return CoapResponse.of(code, payload, opts -> opts.contentFormat(contentFormat)); - } - public static CoapResponse of(Code code, String description) { return of(code, Opaque.of(description)); } - public static CoapResponse ok(Opaque payload) { - return of(Code.C205_CONTENT, payload); + // --- BUILDER CONSTRUCTORS --- + + public static CoapResponse.Builder coapResponse(Code code) { + return new CoapResponse.Builder(code); } - public static CoapResponse ok(String payload) { - return ok(Opaque.of(payload)); + public static CoapResponse.Builder ok() { + return new CoapResponse.Builder(Code.C205_CONTENT); } - public static CoapResponse ok(Opaque payload, short contentFormat) { - return CoapResponse.of(Code.C205_CONTENT, payload, opts -> opts.contentFormat(contentFormat)); + public static CoapResponse.Builder ok(Opaque payload) { + return new CoapResponse.Builder(Code.C205_CONTENT).payload(payload); } - public static CoapResponse ok(String payload, short contentFormat) { - return CoapResponse.of(Code.C205_CONTENT, Opaque.of(payload), opts -> opts.contentFormat(contentFormat)); + public static CoapResponse.Builder ok(String payload) { + return new CoapResponse.Builder(Code.C205_CONTENT).payload(payload); } - public static CoapResponse notFound() { - return of(Code.C404_NOT_FOUND, Opaque.EMPTY); + public static CoapResponse.Builder ok(String payload, short contentFormat) { + return new CoapResponse.Builder(Code.C205_CONTENT).payload(payload).contentFormat(contentFormat); } - public static CoapResponse badRequest() { - return of(Code.C400_BAD_REQUEST, Opaque.EMPTY); + public static CoapResponse.Builder notFound() { + return new CoapResponse.Builder(Code.C404_NOT_FOUND); } - public static CoapResponse badRequest(String errorDescription) { - return of(Code.C400_BAD_REQUEST, Opaque.of(errorDescription)); + public static CoapResponse.Builder badRequest() { + return new CoapResponse.Builder(Code.C400_BAD_REQUEST); } // --------------------- @@ -119,10 +107,6 @@ public SeparateResponse toSeparate(Opaque token, InetSocketAddress peerAddress) return toSeparate(token, peerAddress, TransportContext.EMPTY); } - public CompletableFuture toFuture() { - return CompletableFuture.completedFuture(this); - } - @Override public boolean equals(Object o) { if (this == o) { @@ -155,54 +139,105 @@ public String toString() { } } - // --- MODIFIERS --- + // --- IMMUTABLE MODIFIERS --- - public CoapResponse payload(Opaque newPayload) { + public CoapResponse withPayload(Opaque newPayload) { return new CoapResponse(code, newPayload, options); } - public CoapResponse payload(String newPayload) { - return payload(Opaque.of(newPayload)); - } - - public CoapResponse payload(String newPayload, short contentFormat) { - return payload(Opaque.of(newPayload), contentFormat); - } - - public CoapResponse payload(Opaque newPayload, short contentFormat) { - options.setContentFormat(contentFormat); - return payload(newPayload); - } - - public CoapResponse options(Consumer optionsFunc) { + public CoapResponse withOptions(Consumer optionsFunc) { CoapOptionsBuilder optionsBuilder = CoapOptionsBuilder.from(options); optionsFunc.accept(optionsBuilder); return new CoapResponse(code, payload, optionsBuilder.build()); } - public CoapResponse etag(Opaque etag) { - options.setEtag(etag); - return this; - } + public static class Builder { + private final Code code; + private final CoapOptionsBuilder options = CoapOptionsBuilder.options(); + private Opaque payload = Opaque.EMPTY; - public CoapResponse maxAge(long maxAge) { - options.setMaxAge(maxAge); - return this; - } + private Builder(Code code) { + this.code = code; + } - public CoapResponse block1Req(int num, BlockSize size, boolean more) { - options.setBlock1Req(new BlockOption(num, size, more)); - return this; - } + public CoapResponse build() { + return new CoapResponse(code, payload, options.build()); + } - public CoapResponse block2Res(int num, BlockSize size, boolean more) { - options.setBlock2Res(new BlockOption(num, size, more)); - return this; - } + public SeparateResponse toSeparate(Opaque token, InetSocketAddress peerAddress, TransportContext transContext) { + return build().toSeparate(token, peerAddress, transContext); + } - public CoapResponse observe(int observe) { - options.setObserve(observe); - return this; - } + public SeparateResponse toSeparate(Opaque token, InetSocketAddress peerAddress) { + return build().toSeparate(token, peerAddress); + } + + public CompletableFuture toFuture() { + return CompletableFuture.completedFuture(build()); + } + public Builder payload(Opaque payload) { + this.payload = payload; + return this; + } + + public Builder payload(String payload) { + return payload(Opaque.of(payload)); + } + + public Builder payload(String payload, short contentFormat) { + options.contentFormat(contentFormat); + return payload(Opaque.of(payload)); + } + + public Builder options(Consumer builder) { + builder.accept(options); + return this; + } + + public Builder locationPath(String locationPath) { + options.locationPath(locationPath); + return this; + } + + public Builder etag(Opaque etag) { + options.etag(etag); + return this; + } + + public Builder block1Req(int blockNr, BlockSize blockSize, boolean more) { + options.block1Req(blockNr, blockSize, more); + return this; + } + + public Builder block2Res(int blockNr, BlockSize blockSize, boolean more) { + options.block2Res(blockNr, blockSize, more); + return this; + } + + public Builder maxAge(int maxAge) { + options.maxAge(maxAge); + return this; + } + + public Builder maxAge(Duration maxAge) { + options.maxAge(maxAge); + return this; + } + + public Builder observe(int observe) { + options.observe(observe); + return this; + } + + public Builder contentFormat(short contentFormat) { + options.contentFormat(contentFormat); + return this; + } + + public Builder size2Res(int size) { + options.size2Res(size); + return this; + } + } } diff --git a/coap-core/src/main/java/com/mbed/coap/packet/SeparateResponse.java b/coap-core/src/main/java/com/mbed/coap/packet/SeparateResponse.java index 05d9cfa7..d541b1c0 100644 --- a/coap-core/src/main/java/com/mbed/coap/packet/SeparateResponse.java +++ b/coap-core/src/main/java/com/mbed/coap/packet/SeparateResponse.java @@ -90,8 +90,8 @@ public int hashCode() { return Objects.hash(response, token, peerAddress, transContext); } - public SeparateResponse payload(Opaque newPayload) { - return new SeparateResponse(response.payload(newPayload), token, peerAddress, transContext); + public SeparateResponse withPayload(Opaque newPayload) { + return new SeparateResponse(response.withPayload(newPayload), token, peerAddress, transContext); } public SeparateResponse duplicate() { diff --git a/coap-core/src/main/java/com/mbed/coap/server/CriticalOptionVerifier.java b/coap-core/src/main/java/com/mbed/coap/server/CriticalOptionVerifier.java index e39aa030..e83d6f99 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/CriticalOptionVerifier.java +++ b/coap-core/src/main/java/com/mbed/coap/server/CriticalOptionVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 java-coap contributors (https://github.com/open-coap/java-coap) + * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) * Copyright (C) 2011-2021 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ */ package com.mbed.coap.server; -import static java.util.concurrent.CompletableFuture.*; +import static com.mbed.coap.packet.CoapResponse.coapResponse; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Code; @@ -29,7 +29,7 @@ class CriticalOptionVerifier implements Filter.SimpleFilter apply(CoapRequest request, Service service) { if (request.options().containsUnrecognisedCriticalOption()) { - return completedFuture(CoapResponse.of(Code.C402_BAD_OPTION)); + return coapResponse(Code.C402_BAD_OPTION).toFuture(); } return service.apply(request); } diff --git a/coap-core/src/main/java/com/mbed/coap/server/RescueFilter.java b/coap-core/src/main/java/com/mbed/coap/server/RescueFilter.java index e1475901..9a37b92a 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/RescueFilter.java +++ b/coap-core/src/main/java/com/mbed/coap/server/RescueFilter.java @@ -43,7 +43,7 @@ private CoapResponse rescue(Throwable ex) { return rescue(ex.getCause()); } if (ex instanceof CoapCodeException) { - return ((CoapCodeException) ex).toResponse(); + return ((CoapCodeException) ex).toResponse().build(); } LOGGER.error("Unexpected exception: {}", ex.getMessage(), ex); diff --git a/coap-core/src/main/java/com/mbed/coap/server/RouterService.java b/coap-core/src/main/java/com/mbed/coap/server/RouterService.java index 0c097e15..1e3d6f97 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/RouterService.java +++ b/coap-core/src/main/java/com/mbed/coap/server/RouterService.java @@ -17,7 +17,6 @@ import static java.util.Collections.unmodifiableList; import static java.util.Collections.unmodifiableMap; -import static java.util.concurrent.CompletableFuture.completedFuture; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Method; @@ -37,7 +36,7 @@ public class RouterService implements Service { private final List>> prefixedHandlers; public final Service defaultHandler; - public final static Service NOT_FOUND_SERVICE = request -> completedFuture(CoapResponse.notFound()); + public final static Service NOT_FOUND_SERVICE = request -> CoapResponse.notFound().toFuture(); public static RouteBuilder builder() { return new RouteBuilder(); diff --git a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseCallback.java b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseCallback.java index 49e5b616..06eba611 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseCallback.java +++ b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseCallback.java @@ -141,8 +141,8 @@ private CompletableFuture receiveBlock2(CoapResponse blResponse) { if (response == null) { response = blResponse; } else { - this.response = CoapResponse.of(blResponse.getCode(), response.getPayload().concat(blResponse.getPayload()), response.options()); - this.response.options().setBlock2Res(blResponse.options().getBlock2Res()); + this.response = CoapResponse.of(blResponse.getCode(), response.getPayload().concat(blResponse.getPayload()), response.options()) + .withOptions(o -> o.block2Res(blResponse.options().getBlock2Res())); } if (hasResourceChanged(blResponse)) { diff --git a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseIncomingFilter.java b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseIncomingFilter.java index 966f013d..8f06f912 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseIncomingFilter.java +++ b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseIncomingFilter.java @@ -16,8 +16,8 @@ */ package com.mbed.coap.server.block; +import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.utils.FutureHelpers.failedFuture; -import static java.util.concurrent.CompletableFuture.completedFuture; import com.mbed.coap.exception.CoapCodeException; import com.mbed.coap.packet.BlockOption; import com.mbed.coap.packet.BlockSize; @@ -99,9 +99,10 @@ public CompletableFuture apply(CoapRequest request, Service o.block1Req(finalReqBlock)) + .toFuture(); } } @@ -157,7 +158,7 @@ private CoapResponse updateBlockResponse(final BlockOption block2Response, final } Opaque blockPayload = resp.getPayload().slice(blFrom, newLength); resp.options().setBlock2Res(block2Res); - return resp.payload(blockPayload); + return resp.withPayload(blockPayload); } } diff --git a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseNotificationFilter.java b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseNotificationFilter.java index 25a8cee5..e190a07c 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseNotificationFilter.java +++ b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseNotificationFilter.java @@ -39,7 +39,7 @@ public CompletableFuture apply(SeparateResponse blockObs, Service etagGenerator) { public CompletableFuture apply(CoapRequest request, Service service) { return service .apply(request) - .thenApply(resp -> { - if (resp.options().getEtagArray() == null) { - return resp.etag(etagGenerator.apply(resp.getPayload())); - } - return resp; - }); + .thenApply(this::updateEtag); + } + + private CoapResponse updateEtag(CoapResponse resp) { + return resp.withOptions(o -> + o.ifNull(HeaderOptions::getEtagArray, __ -> + o.etag(etagGenerator.apply(resp.getPayload())) + ) + ); } } diff --git a/coap-core/src/main/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilter.java b/coap-core/src/main/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilter.java index 1deb70be..220bad0b 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilter.java +++ b/coap-core/src/main/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 java-coap contributors (https://github.com/open-coap/java-coap) + * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */ package com.mbed.coap.server.filter; -import static java.util.concurrent.CompletableFuture.*; +import static com.mbed.coap.packet.CoapResponse.coapResponse; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Code; @@ -36,9 +36,10 @@ public MaxAllowedPayloadFilter(int max, String msg) { public CompletableFuture apply(CoapRequest request, Service service) { if (request.getPayload().size() > max) { - CoapResponse response = CoapResponse.of(Code.C413_REQUEST_ENTITY_TOO_LARGE, msg); - response.options().setSize1(max); - return completedFuture(response); + return coapResponse(Code.C413_REQUEST_ENTITY_TOO_LARGE) + .options(o -> o.size1(max)) + .payload(msg) + .toFuture(); } else { return service.apply(request); } diff --git a/coap-core/src/main/java/com/mbed/coap/server/observe/ObserversManager.java b/coap-core/src/main/java/com/mbed/coap/server/observe/ObserversManager.java index 99f9fe01..99cbacde 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/observe/ObserversManager.java +++ b/coap-core/src/main/java/com/mbed/coap/server/observe/ObserversManager.java @@ -61,6 +61,10 @@ public CompletableFuture apply(CoapRequest request, Service subscribe(request, resp)); } + public CoapResponse subscribe(CoapRequest req, CoapResponse.Builder resp) { + return subscribe(req, resp.build()); + } + public CoapResponse subscribe(CoapRequest req, CoapResponse resp) { if (req.getMethod() != Method.GET && req.getMethod() != Method.FETCH) { return resp; @@ -73,14 +77,14 @@ public CoapResponse subscribe(CoapRequest req, CoapResponse resp) { remove(req.options().getUriPath(), req.getPeerAddress()); } - return resp.options(CoapOptionsBuilder::unsetObserve); + return resp.withOptions(CoapOptionsBuilder::unsetObserve); } private CoapResponse updateObserve(CoapResponse resp) { if (resp.options().getObserve() != null) { return resp; } - return resp.options(o -> o.observe(observeSeq.get())); + return resp.withOptions(o -> o.observe(observeSeq.get())); } public void sendObservation(String uriPath, Service service) { @@ -128,7 +132,7 @@ private void sendObservation(String uriPath, SeparateResponse separateResponse) } private static SeparateResponse toSeparateResponse(CoapResponse obsResponse, int currentObserveSequence, CoapRequest subscribeRequest) { - return obsResponse.options(o -> o.observe(currentObserveSequence)) + return obsResponse.withOptions(o -> o.observe(currentObserveSequence)) .toSeparate(subscribeRequest.getToken(), subscribeRequest.getPeerAddress()); } diff --git a/coap-core/src/test/java/com/mbed/coap/client/CoapClientTest.java b/coap-core/src/test/java/com/mbed/coap/client/CoapClientTest.java index 5210c6c7..d39b1727 100644 --- a/coap-core/src/test/java/com/mbed/coap/client/CoapClientTest.java +++ b/coap-core/src/test/java/com/mbed/coap/client/CoapClientTest.java @@ -90,7 +90,7 @@ public void syncRequest() throws CoapException { @Test public void observationTest() throws Exception { given(clientService.apply(get("/test").token(token1001).observe().from(LOCAL_5683))) - .willReturn(CoapResponse.ok("1", CT_TEXT_PLAIN).options(o -> o.observe(1)).toFuture()); + .willReturn(CoapResponse.ok().payload("1").contentFormat(CT_TEXT_PLAIN).observe(1).toFuture()); // when CompletableFuture resp = client.send(observe("/test").token(token1001)); diff --git a/coap-core/src/test/java/com/mbed/coap/packet/CoapResponseTest.java b/coap-core/src/test/java/com/mbed/coap/packet/CoapResponseTest.java index 7d4563f3..f09a2af6 100644 --- a/coap-core/src/test/java/com/mbed/coap/packet/CoapResponseTest.java +++ b/coap-core/src/test/java/com/mbed/coap/packet/CoapResponseTest.java @@ -16,21 +16,59 @@ */ package com.mbed.coap.packet; +import static com.mbed.coap.packet.CoapResponse.coapResponse; +import static com.mbed.coap.packet.Code.C201_CREATED; +import static com.mbed.coap.packet.Code.C204_CHANGED; +import static com.mbed.coap.packet.Code.C205_CONTENT; +import static com.mbed.coap.packet.Code.C400_BAD_REQUEST; +import static com.mbed.coap.packet.Code.C404_NOT_FOUND; import static com.mbed.coap.packet.MediaTypes.CT_APPLICATION_JSON; import static com.mbed.coap.packet.MediaTypes.CT_TEXT_PLAIN; +import static com.mbed.coap.packet.Opaque.decodeHex; +import static com.mbed.coap.utils.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static protocolTests.utils.CoapPacketBuilder.LOCAL_5683; +import com.mbed.coap.transport.TransportContext; +import java.time.Duration; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; import java.util.function.Supplier; import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Func; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; + class CoapResponseTest { @Test - void build_bad_request() { - assertEquals(CoapResponse.of(Code.C400_BAD_REQUEST, Opaque.EMPTY), CoapResponse.badRequest()); - assertEquals(CoapResponse.of(Code.C400_BAD_REQUEST, Opaque.of("really bad")), CoapResponse.badRequest("really bad")); + void staticFactory() { + assertEquals(CoapResponse.ok(), CoapResponse.of(C205_CONTENT, Opaque.EMPTY)); + assertEquals(CoapResponse.ok(Opaque.of("test")), CoapResponse.of(C205_CONTENT, "test")); + assertEquals(CoapResponse.ok("test"), CoapResponse.of(C205_CONTENT, Opaque.of("test"))); + assertEquals(CoapResponse.ok("test"), CoapResponse.of(C205_CONTENT, Opaque.of("test"))); + assertEquals(CoapResponse.badRequest(), CoapResponse.of(C400_BAD_REQUEST, Opaque.EMPTY)); + assertEquals(CoapResponse.notFound(), CoapResponse.of(C404_NOT_FOUND, Opaque.EMPTY)); + } + + @Test + public void shouldModifyPayload() { + CoapResponse response = CoapResponse.of(C205_CONTENT, Opaque.of("moi")); + CoapResponse expected = CoapResponse.of(C205_CONTENT, Opaque.of("czesc")); + + assertEquals(expected, response.withPayload(Opaque.of("czesc"))); + assertEquals("moi", response.getPayloadString()); + } + + @Test + public void shouldModifyOptions() { + CoapResponse response = CoapResponse.of(C205_CONTENT, Opaque.of("test"), newOptions(o -> o.setMaxAge(100L))); + CoapResponse expected = CoapResponse.of(C205_CONTENT, Opaque.of("test"), newOptions(o -> o.setMaxAge(200L))); + + assertEquals(expected, response.withOptions(o -> o.maxAge(200))); + assertEquals(100, response.options().getMaxAge()); } @Test @@ -38,16 +76,75 @@ public void equalsAndHashTest() { EqualsVerifier.forClass(CoapResponse.class) .withGenericPrefabValues(Supplier.class, (Func.Func1, Supplier>) o -> () -> o) .withGenericPrefabValues(CompletableFuture.class, (Func.Func1) coapResponse -> new CompletableFuture<>()) - .withPrefabValues(CoapResponse.class, CoapResponse.badRequest(), CoapResponse.ok("")) + .withPrefabValues(CoapResponse.class, CoapResponse.badRequest().build(), CoapResponse.ok().build()) .usingGetClass() .verify(); } @Test void testToString() { - assertEquals("CoapResponse[205, pl(4):64757061]", CoapResponse.ok("dupa").toString()); - assertEquals("CoapResponse[400, ETag:6565]", CoapResponse.badRequest().etag(Opaque.of("ee")).toString()); - assertEquals("CoapResponse[205, ContTp:0, pl(3):616161]", CoapResponse.ok("aaa", CT_TEXT_PLAIN).toString()); - assertEquals("CoapResponse[400, ContTp:50, pl(13):7b226572726f72223a3132337d]", CoapResponse.of(Code.C400_BAD_REQUEST, Opaque.of("{\"error\":123}"), CT_APPLICATION_JSON).toString()); + assertEquals("CoapResponse[205, pl(4):64757061]", CoapResponse.ok("dupa").build().toString()); + assertEquals("CoapResponse[400, ETag:6565]", CoapResponse.badRequest().etag(Opaque.of("ee")).build().toString()); + assertEquals("CoapResponse[205, ContTp:0, pl(3):616161]", CoapResponse.ok("aaa", CT_TEXT_PLAIN).build().toString()); + assertEquals("CoapResponse[400, ContTp:50, pl(13):7b226572726f72223a3132337d]", coapResponse(C400_BAD_REQUEST).payload("{\"error\":123}").contentFormat(CT_APPLICATION_JSON).build().toString()); + } + + private static HeaderOptions newOptions(Consumer optionsFunc) { + HeaderOptions options = new HeaderOptions(); + optionsFunc.accept(options); + return options; + } + + @Nested + class BuilderTest { + + @Test + public void shouldBuildComplex() { + CoapResponse response = coapResponse(C201_CREATED) + .payload(Opaque.of("{'test:1}")) + .contentFormat(CT_APPLICATION_JSON) + .observe(123) + .etag(decodeHex("0102")) + .size2Res(9) + .locationPath("/test") + .maxAge(Duration.ofMinutes(1)) + .options(o -> o + .proxyUri("/proxy/test") + .ifMatch(decodeHex("99")) + .size1(432) + ) + .build(); + + CoapResponse expected = CoapResponse.of(C201_CREATED, Opaque.of("{'test:1}"), newOptions(o -> { + o.setContentFormat(CT_APPLICATION_JSON); + o.setObserve(123); + o.setEtag(decodeHex("0102")); + o.setSize2Res(9); + o.setLocationPath("/test"); + o.setMaxAge(60L); + o.setProxyUri("/proxy/test"); + o.setIfMatch(new Opaque[]{decodeHex("99")}); + o.setSize1(432); + })); + + assertEquals(expected, response); + } + + + @Test + public void shouldReturnCompletedFuture() throws ExecutionException, InterruptedException { + CompletableFuture future = coapResponse(C205_CONTENT).toFuture(); + + assertTrue(future.isDone()); + assertEquals(future.get(), CoapResponse.of(C205_CONTENT)); + } + + @Test + public void shouldReturnSeparateResponse() { + SeparateResponse separateResponse = coapResponse(C204_CHANGED).toSeparate(decodeHex("0102"), LOCAL_5683); + SeparateResponse expected = new SeparateResponse(CoapResponse.of(C204_CHANGED), decodeHex("0102"), LOCAL_5683, TransportContext.EMPTY); + + assertEquals(expected, separateResponse); + } } } diff --git a/coap-core/src/test/java/com/mbed/coap/packet/SeparateResponseTest.java b/coap-core/src/test/java/com/mbed/coap/packet/SeparateResponseTest.java index 6799ffa1..ce561019 100644 --- a/coap-core/src/test/java/com/mbed/coap/packet/SeparateResponseTest.java +++ b/coap-core/src/test/java/com/mbed/coap/packet/SeparateResponseTest.java @@ -30,7 +30,7 @@ public void equalsAndHashTest() { EqualsVerifier.forClass(SeparateResponse.class) .withGenericPrefabValues(Supplier.class, (Func.Func1, Supplier>) o -> () -> o) .withGenericPrefabValues(CompletableFuture.class, (Func.Func1) coapResponse -> new CompletableFuture<>()) - .withPrefabValues(CoapResponse.class, CoapResponse.badRequest(), CoapResponse.ok("")) + .withPrefabValues(CoapResponse.class, CoapResponse.badRequest().build(), CoapResponse.ok().build()) .withPrefabValues(TransportContext.class, TransportContext.EMPTY, TransportContext.of(TransportContext.NON_CONFIRMABLE, true)) .usingGetClass() .verify(); diff --git a/coap-core/src/test/java/com/mbed/coap/server/NotificationValidatorTest.java b/coap-core/src/test/java/com/mbed/coap/server/NotificationValidatorTest.java index 0362bc57..d16c4b2d 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/NotificationValidatorTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/NotificationValidatorTest.java @@ -16,12 +16,13 @@ */ package com.mbed.coap.server; -import static com.mbed.coap.packet.CoapResponse.*; -import static com.mbed.coap.packet.Opaque.*; -import static java.util.concurrent.CompletableFuture.*; -import static org.assertj.core.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.*; -import static protocolTests.utils.CoapPacketBuilder.*; +import static com.mbed.coap.packet.CoapResponse.ok; +import static com.mbed.coap.packet.Opaque.EMPTY; +import static com.mbed.coap.packet.Opaque.ofBytes; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static protocolTests.utils.CoapPacketBuilder.LOCAL_1_5683; import com.mbed.coap.packet.SeparateResponse; import com.mbed.coap.utils.Service; import java.util.concurrent.CompletableFuture; @@ -55,4 +56,4 @@ public void failToSendNotificationWithout_missingHeaders() { ).isInstanceOf(IllegalArgumentException.class); } -} \ No newline at end of file +} diff --git a/coap-core/src/test/java/com/mbed/coap/server/ObserveRequestFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/ObserveRequestFilterTest.java index 43224e68..ea74672f 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/ObserveRequestFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/ObserveRequestFilterTest.java @@ -20,7 +20,7 @@ import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Opaque.EMPTY; import static com.mbed.coap.packet.Opaque.ofBytes; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static com.mbed.coap.utils.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; diff --git a/coap-core/src/test/java/com/mbed/coap/server/RoutingServiceTest.java b/coap-core/src/test/java/com/mbed/coap/server/RoutingServiceTest.java index 49493960..47162450 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/RoutingServiceTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/RoutingServiceTest.java @@ -24,6 +24,7 @@ import static com.mbed.coap.packet.CoapRequest.put; import static com.mbed.coap.packet.MediaTypes.CT_APPLICATION_JSON; import static com.mbed.coap.packet.MediaTypes.CT_TEXT_PLAIN; +import static com.mbed.coap.utils.Assertions.assertEquals; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mbed.coap.packet.CoapRequest; diff --git a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseCallbackTest.java b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseCallbackTest.java index e77dc208..78f25241 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseCallbackTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseCallbackTest.java @@ -29,6 +29,7 @@ import static com.mbed.coap.packet.Code.C204_CHANGED; import static com.mbed.coap.packet.Code.C231_CONTINUE; import static com.mbed.coap.packet.Code.C413_REQUEST_ENTITY_TOO_LARGE; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Bytes.opaqueOfSize; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -361,8 +362,12 @@ private void receiveFirst(CoapResponse resp) { response = bwc.receive(resp); } - private void receive(CoapResponse resp) { - promise.complete(resp); + private void receiveFirst(CoapResponse.Builder resp) { + receiveFirst(resp.build()); + } + + private void receive(CoapResponse.Builder resp) { + promise.complete(resp.build()); } private void givenPutRequest(int payloadSize) throws CoapException { diff --git a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseIncomingFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseIncomingFilterTest.java index ea1e41da..6b19364e 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseIncomingFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseIncomingFilterTest.java @@ -27,6 +27,7 @@ import static com.mbed.coap.packet.Code.C205_CONTENT; import static com.mbed.coap.packet.Code.C231_CONTINUE; import static com.mbed.coap.packet.Opaque.decodeHex; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Bytes.opaqueOfSize; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseNotificationFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseNotificationFilterTest.java index a82d42fb..48b8eb80 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseNotificationFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseNotificationFilterTest.java @@ -65,7 +65,7 @@ void shouldSendFirstBlockForLargePayload() { // then assertTrue(resp.join()); - SeparateResponse expected = ok("aaaaaaaaaaaaaaab").options(o -> o.size2Res(27)).block2Res(0, S_16, true).toSeparate(token, LOCAL_1_5683); + SeparateResponse expected = ok("aaaaaaaaaaaaaaab").size2Res(27).block2Res(0, S_16, true).toSeparate(token, LOCAL_1_5683); verify(service).apply(expected); } } \ No newline at end of file diff --git a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseOutgoingFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseOutgoingFilterTest.java index b15a6d14..6ac59124 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseOutgoingFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseOutgoingFilterTest.java @@ -23,6 +23,7 @@ import static com.mbed.coap.packet.CoapRequest.put; import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.packet.CoapResponse.ok; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Bytes.opaqueOfSize; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -47,7 +48,7 @@ class BlockWiseOutgoingFilterTest { private Capabilities capability = Capabilities.BASE; - private CompletableFuture promise; + private CompletableFuture promise; private CoapRequest lastReq; private BlockWiseOutgoingFilter filter = new BlockWiseOutgoingFilter(__ -> capability, 100_000); private Service service = filter.then(this::newPromise); @@ -55,7 +56,7 @@ class BlockWiseOutgoingFilterTest { private CompletableFuture newPromise(CoapRequest req) { promise = new CompletableFuture<>(); lastReq = req; - return promise; + return promise.thenApply(CoapResponse.Builder::build); } @Test @@ -288,7 +289,7 @@ public void should_continue_block_transfer_after_block_size_change() throws Exec assertEquals(Code.C204_CHANGED, respFut.get().getCode()); } - private void assertMakeRequestAndReceive(CoapRequest req, CoapResponse resp) { + private void assertMakeRequestAndReceive(CoapRequest req, CoapResponse.Builder resp) { assertMakeRequest(req); //response diff --git a/coap-core/src/test/java/com/mbed/coap/server/filter/EchoFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/filter/EchoFilterTest.java index 4dd87fdf..cd7d59cf 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/filter/EchoFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/filter/EchoFilterTest.java @@ -19,10 +19,13 @@ import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Code.C401_UNAUTHORIZED; +import static com.mbed.coap.utils.Assertions.assertEquals; +import static com.mbed.coap.utils.CoapRequestBuilderFilter.REQUEST_BUILDER_FILTER; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Opaque; +import com.mbed.coap.utils.Filter; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -31,7 +34,7 @@ public class EchoFilterTest { - private final EchoFilter filter = new EchoFilter(); + private final Filter filter = REQUEST_BUILDER_FILTER.andThen(new EchoFilter()); @Test void shouldRetryWithEcho() throws ExecutionException, InterruptedException { @@ -61,7 +64,7 @@ private CompletableFuture handle1(CoapRequest request) { if (Objects.equals(Opaque.of("echo1"), request.options().getEcho())) { return ok("OK").toFuture(); } else { - return CoapResponse.of(C401_UNAUTHORIZED) + return coapResponse(C401_UNAUTHORIZED) .options(it -> it.echo(Opaque.of("echo1"))) .toFuture(); } diff --git a/coap-core/src/test/java/com/mbed/coap/server/filter/EtagValidatorFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/filter/EtagValidatorFilterTest.java index cd251f05..42870e68 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/filter/EtagValidatorFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/filter/EtagValidatorFilterTest.java @@ -20,7 +20,7 @@ import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Opaque.ofBytes; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static com.mbed.coap.utils.Assertions.assertEquals; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Code; @@ -33,7 +33,7 @@ class EtagValidatorFilterTest { private final Filter.SimpleFilter filter = new EtagValidatorFilter(); - private final CoapResponse resource = ok("OK").etag(ofBytes(100)).maxAge(100); + private final CoapResponse.Builder resource = ok("OK").etag(ofBytes(100)).maxAge(100); private final Service service = filter.then(__ -> resource.toFuture()); @Test @@ -65,4 +65,4 @@ void shouldPassResponseWhenMethodOtherThanGET() { assertEquals(resource, resp.join()); } -} \ No newline at end of file +} diff --git a/coap-core/src/test/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilterTest.java index 8f23618b..00d25cd8 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilterTest.java @@ -16,15 +16,16 @@ package com.mbed.coap.server.filter; import static com.mbed.coap.packet.CoapRequest.post; +import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.packet.CoapResponse.of; import static com.mbed.coap.packet.Code.C201_CREATED; import static com.mbed.coap.packet.Code.C413_REQUEST_ENTITY_TOO_LARGE; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Bytes.opaqueOfSize; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; -import com.mbed.coap.packet.Opaque; import com.mbed.coap.utils.Service; import org.junit.jupiter.api.Test; @@ -45,7 +46,7 @@ void shouldPassWhenPayloadUnderLimit() { @Test void shouldFailWhenPayloadAboveLimit() { - CoapResponse expected = CoapResponse.of(C413_REQUEST_ENTITY_TOO_LARGE, Opaque.of("too much"), o -> o.size1(50)); + CoapResponse.Builder expected = coapResponse(C413_REQUEST_ENTITY_TOO_LARGE).options(o -> o.size1(50)).payload("too much"); assertEquals(expected, service.apply(post("/t").payload(opaqueOfSize(51))).join()); assertEquals(expected, service.apply(post("/t").payload(opaqueOfSize(10021))).join()); diff --git a/coap-core/src/test/java/com/mbed/coap/server/filter/TokenGeneratorFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/filter/TokenGeneratorFilterTest.java index 7298791e..f9b6db66 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/filter/TokenGeneratorFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/filter/TokenGeneratorFilterTest.java @@ -17,6 +17,7 @@ import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.packet.CoapResponse.ok; +import static com.mbed.coap.utils.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import com.mbed.coap.packet.CoapRequest; diff --git a/coap-core/src/test/java/com/mbed/coap/server/messaging/ExchangeFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/messaging/ExchangeFilterTest.java index bacce605..e126442d 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/messaging/ExchangeFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/messaging/ExchangeFilterTest.java @@ -17,6 +17,7 @@ import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.transport.TransportContext.NON_CONFIRMABLE; +import static com.mbed.coap.utils.Assertions.assertEquals; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -63,7 +64,7 @@ void piggybackedExchange() { assertEquals(1, exchangeFilter.transactions()); // when - CoapResponse cpResp = CoapResponse.ok("ok"); + CoapResponse cpResp = CoapResponse.ok("ok").build(); promise.complete(cpResp); // then diff --git a/coap-core/src/test/java/com/mbed/coap/server/observe/ObserversManagerTest.java b/coap-core/src/test/java/com/mbed/coap/server/observe/ObserversManagerTest.java index 1bb6990b..c34d8714 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/observe/ObserversManagerTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/observe/ObserversManagerTest.java @@ -17,6 +17,7 @@ import static com.mbed.coap.packet.CoapRequest.fetch; import static com.mbed.coap.packet.CoapRequest.get; +import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.packet.CoapResponse.notFound; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.MediaTypes.CT_APPLICATION_JSON; @@ -35,6 +36,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; +import com.mbed.coap.packet.Code; import com.mbed.coap.packet.SeparateResponse; import com.mbed.coap.utils.IpPortAddress; import com.mbed.coap.utils.Service; @@ -101,7 +103,7 @@ public void sendObservation() throws ExecutionException, InterruptedException { obsMgr.sendObservation("/test", __ -> ok("OK 1").toFuture()); // then - CoapResponse expected = ok("OK 1").observe(1); + CoapResponse.Builder expected = coapResponse(Code.C205_CONTENT).observe(1).payload("OK 1"); verify(outboundObservation).apply(eq(expected.toSeparate(variableUInt(13), PEER_1))); verify(outboundObservation).apply(eq(expected.toSeparate(variableUInt(1312), PEER_2))); } @@ -116,8 +118,8 @@ public void sendObservation_different_for_each_subscriber_accept() { obsMgr.sendObservation("/test", okResource); // then - verify(outboundObservation).apply(eq(ok("OK", CT_TEXT_PLAIN).observe(1).toSeparate(variableUInt(13), PEER_1))); - verify(outboundObservation).apply(eq(ok("OK", CT_APPLICATION_XML).observe(1).toSeparate(variableUInt(1312), PEER_2))); + verify(outboundObservation).apply(eq(ok().payload("OK", CT_TEXT_PLAIN).observe(1).toSeparate(variableUInt(13), PEER_1))); + verify(outboundObservation).apply(eq(ok().payload("OK").contentFormat(CT_APPLICATION_XML).observe(1).toSeparate(variableUInt(1312), PEER_2))); } @Test @@ -150,8 +152,8 @@ public void updateSubscription_and_sendObservation() throws ExecutionException, // then assertEquals(1, obsMgr.size()); - obsMgr.sendObservation("/test", __ -> completedFuture(ok("OK"))); - CoapResponse expected = ok("OK").observe(1); + obsMgr.sendObservation("/test", __ -> ok("OK").toFuture()); + CoapResponse.Builder expected = coapResponse(Code.C205_CONTENT).observe(1).payload("OK"); verify(outboundObservation).apply(eq(expected.toSeparate(variableUInt(222), PEER_1))); } @@ -164,7 +166,7 @@ public void sendCancelObservation() throws ExecutionException, InterruptedExcept obsMgr.sendObservation("/test", __ -> notFound().toFuture()); // then - CoapResponse expected = notFound().observe(1); + CoapResponse.Builder expected = coapResponse(Code.C404_NOT_FOUND).observe(1); verify(outboundObservation).apply(eq(expected.toSeparate(variableUInt(13), PEER_1))); } diff --git a/coap-core/src/test/java/protocolTests/ClientServerWithBlocksTest.java b/coap-core/src/test/java/protocolTests/ClientServerWithBlocksTest.java index f9752c07..6ee332f5 100644 --- a/coap-core/src/test/java/protocolTests/ClientServerWithBlocksTest.java +++ b/coap-core/src/test/java/protocolTests/ClientServerWithBlocksTest.java @@ -272,9 +272,7 @@ private class DynamicBigResource implements Service { @Override public CompletableFuture apply(CoapRequest req) { - final CoapResponse resp = CoapResponse.of(Code.C205_CONTENT, dynamicResource, opts -> - opts.etag(Opaque.variableUInt(dynamicResource.hashCode())) - ); + final CoapResponse.Builder resp = CoapResponse.ok().etag(Opaque.variableUInt(dynamicResource.hashCode())).payload(dynamicResource); if (!changed) { dynamicResource = dynamicResource.concat(of("-CH")); diff --git a/coap-core/src/test/java/protocolTests/ClientTest.java b/coap-core/src/test/java/protocolTests/ClientTest.java index 5f3c48e8..cd1919a8 100644 --- a/coap-core/src/test/java/protocolTests/ClientTest.java +++ b/coap-core/src/test/java/protocolTests/ClientTest.java @@ -18,6 +18,7 @@ import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Opaque.decodeHex; +import static com.mbed.coap.utils.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mbed.coap.client.CoapClient; import com.mbed.coap.exception.CoapException; diff --git a/coap-core/src/test/java/protocolTests/DuplicateTest.java b/coap-core/src/test/java/protocolTests/DuplicateTest.java index 80f22706..1eff66b8 100644 --- a/coap-core/src/test/java/protocolTests/DuplicateTest.java +++ b/coap-core/src/test/java/protocolTests/DuplicateTest.java @@ -129,7 +129,7 @@ public void testDuplicateRequest_withSlowResponse() throws Exception { // when //let response be sent - delayResource.complete(CoapResponse.ok("dupa3")); + delayResource.complete(CoapResponse.ok("dupa3").build()); // then client.verifyReceived(coap(11).ack(Code.C205_CONTENT).payload("dupa3")); diff --git a/coap-core/src/test/java/protocolTests/NonConfirmableTransactionsTest.java b/coap-core/src/test/java/protocolTests/NonConfirmableTransactionsTest.java index 27c71a3d..6e733060 100644 --- a/coap-core/src/test/java/protocolTests/NonConfirmableTransactionsTest.java +++ b/coap-core/src/test/java/protocolTests/NonConfirmableTransactionsTest.java @@ -20,6 +20,7 @@ import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.transport.TransportContext.NON_CONFIRMABLE; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Validations.require; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/coap-core/src/testFixtures/java/com/mbed/coap/utils/Assertions.java b/coap-core/src/testFixtures/java/com/mbed/coap/utils/Assertions.java new file mode 100644 index 00000000..b53b9d66 --- /dev/null +++ b/coap-core/src/testFixtures/java/com/mbed/coap/utils/Assertions.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mbed.coap.utils; + +import com.mbed.coap.packet.CoapResponse; + +public class Assertions { + + public static void assertEquals(CoapResponse.Builder expected, CoapResponse actual) { + org.junit.jupiter.api.Assertions.assertEquals(expected.build(), actual); + } + +} diff --git a/coap-core/src/testFixtures/java/com/mbed/coap/utils/ObservableResource.java b/coap-core/src/testFixtures/java/com/mbed/coap/utils/ObservableResource.java index 181248e7..5f7ea32e 100644 --- a/coap-core/src/testFixtures/java/com/mbed/coap/utils/ObservableResource.java +++ b/coap-core/src/testFixtures/java/com/mbed/coap/utils/ObservableResource.java @@ -15,6 +15,7 @@ */ package com.mbed.coap.utils; +import static com.mbed.coap.packet.CoapResponse.coapResponse; import static java.util.Objects.requireNonNull; import static java.util.concurrent.CompletableFuture.completedFuture; import com.mbed.coap.packet.CoapRequest; @@ -30,11 +31,10 @@ public class ObservableResource implements Service { private CoapResponse current; private final String uriPath; - public ObservableResource(String uriPath, CoapResponse current, ObserversManager observersManager) { - this.current = current; + public ObservableResource(String uriPath, CoapResponse.Builder current, ObserversManager observersManager) { + this.current = current.observe(0).build(); this.observersManager = observersManager; this.uriPath = uriPath; - current.options().setObserve(0); } @Override @@ -43,12 +43,12 @@ public CompletableFuture apply(CoapRequest req) { } public void putPayload(Opaque payload) { - put(current.payload(payload)); + put(current.withPayload(payload)); } public void terminate(Code code) { requireNonNull(code); - put(CoapResponse.of(code, Opaque.EMPTY, opts -> opts.observe(current.options().getObserve()))); + put(coapResponse(code).observe(current.options().getObserve()).build()); } public void put(CoapResponse obs) { diff --git a/coap-core/src/testFixtures/java/protocolTests/IntegrationTestBase.java b/coap-core/src/testFixtures/java/protocolTests/IntegrationTestBase.java index bf363989..135bade8 100644 --- a/coap-core/src/testFixtures/java/protocolTests/IntegrationTestBase.java +++ b/coap-core/src/testFixtures/java/protocolTests/IntegrationTestBase.java @@ -27,6 +27,7 @@ import static com.mbed.coap.packet.Opaque.EMPTY; import static com.mbed.coap.packet.Opaque.of; import static com.mbed.coap.server.observe.NotificationsReceiver.retrieveRemainingBlocks; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.FutureHelpers.failedFuture; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -71,9 +72,9 @@ abstract class IntegrationTestBase { private final Opaque largePayload = Bytes.opaqueOfRandom(3000); protected final StubNotificationsReceiver receiver = new StubNotificationsReceiver(); - private CompletableFuture slowResourcePromise; + private CompletableFuture slowResourcePromise; private ObserversManager observersManager; - private CoapResponse obsResource = CoapResponse.ok(""); + private CoapResponse.Builder obsResource = CoapResponse.ok(); @BeforeEach public void setUp() throws IOException { @@ -106,7 +107,7 @@ public void setUp() throws IOException { }) .get("/obs", req -> observersManager.apply(req, __ -> obsResource.toFuture())) .fetch("/obs", req -> observersManager.apply(req, __ -> obsResource.toFuture())) - .get("/slow", __ -> slowResourcePromise) + .get("/slow", __ -> slowResourcePromise.thenApply(CoapResponse.Builder::build)) .get(CoapConstants.WELL_KNOWN_CORE, req -> ok(",", MediaTypes.CT_APPLICATION_LINK__FORMAT).toFuture() ).build(); @@ -219,14 +220,14 @@ public void sendPing() throws Exception { void readLargePayload() { CoapResponse resp = client.send(get("/large").token(101)).join(); - assertEquals(CoapResponse.ok(largePayload), resp.options(CoapOptionsBuilder::unsetBlock2Res)); + assertEquals(CoapResponse.ok(largePayload), resp.withOptions(CoapOptionsBuilder::unsetBlock2Res)); } @Test void readLargePayloadFetch() { CoapResponse resp = client.send(fetch("/large").token(103)).join(); - assertEquals(CoapResponse.ok(largePayload), resp.options(CoapOptionsBuilder::unsetBlock2Res)); + assertEquals(CoapResponse.ok(largePayload), resp.withOptions(CoapOptionsBuilder::unsetBlock2Res)); } @Test @@ -234,7 +235,7 @@ void writeLargePayload() { await().untilAsserted(() -> { CoapResponse resp = client.send(post("/large").token(102).payload(largePayload)).join(); - assertEquals(CoapResponse.ok("Got 3000B"), resp.options(CoapOptionsBuilder::unsetBlock1Req)); + assertEquals(CoapResponse.ok("Got 3000B"), resp.withOptions(CoapOptionsBuilder::unsetBlock1Req)); }); } @@ -243,7 +244,7 @@ void writeLargePatch() { await().untilAsserted(() -> { CoapResponse resp = client.send(patch("/large").token(105).payload(largePayload)).join(); - assertEquals(CoapResponse.ok("Got 3000B"), resp.options(CoapOptionsBuilder::unsetBlock1Req)); + assertEquals(CoapResponse.ok("Got 3000B"), resp.withOptions(CoapOptionsBuilder::unsetBlock1Req)); }); } @@ -252,7 +253,7 @@ void writeLargeIPatch() { await().untilAsserted(() -> { CoapResponse resp = client.send(iPatch("/large").token(106).payload(largePayload)).join(); - assertEquals(CoapResponse.ok("Got 3000B"), resp.options(CoapOptionsBuilder::unsetBlock1Req)); + assertEquals(CoapResponse.ok("Got 3000B"), resp.withOptions(CoapOptionsBuilder::unsetBlock1Req)); }); } @@ -261,7 +262,7 @@ void writeLargeIPatch() { void observeResource() throws Exception { // given CoapResponse observe = client.sendSync(observe("/obs")); - assertEquals(CoapResponse.ok("").observe(0), observe); + assertEquals(CoapResponse.ok().observe(0), observe); // when observersManager.sendObservation("/obs", __ -> ok("obs1").toFuture()); @@ -275,8 +276,8 @@ void observeResource() throws Exception { @Test void observeResource_with_FETCH() throws Exception { // given - CoapResponse observe = client.sendSync(fetch("/obs").observe(0)); - assertEquals(CoapResponse.ok("").observe(0), observe); + CoapResponse observe = client.sendSync(fetch("/obs").observe()); + assertEquals(CoapResponse.ok().observe(0), observe); // when observersManager.sendObservation("/obs", __ -> ok("obs1").toFuture()); @@ -356,7 +357,7 @@ public CompletableFuture apply(CoapRequest request) { } } - public CoapResponse get(CoapRequest request) { + public CoapResponse.Builder get(CoapRequest request) { if (request.options().getAccept() != null) { boolean isFound = false; if (request.options().getAccept() == contentType) { @@ -369,7 +370,7 @@ public CoapResponse get(CoapRequest request) { } } - return CoapResponse.ok(payload, contentType); + return CoapResponse.ok().payload(payload).contentFormat(contentType); } public CoapResponse put(CoapRequest request) { diff --git a/coap-core/src/testFixtures/java/protocolTests/utils/StubNotificationsReceiver.java b/coap-core/src/testFixtures/java/protocolTests/utils/StubNotificationsReceiver.java index a982806b..7f683378 100644 --- a/coap-core/src/testFixtures/java/protocolTests/utils/StubNotificationsReceiver.java +++ b/coap-core/src/testFixtures/java/protocolTests/utils/StubNotificationsReceiver.java @@ -15,7 +15,7 @@ */ package protocolTests.utils; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static com.mbed.coap.utils.Assertions.assertEquals; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.SeparateResponse; import com.mbed.coap.server.observe.NotificationsReceiver; @@ -37,7 +37,7 @@ public SeparateResponse take() throws InterruptedException { return queue.poll(5, TimeUnit.SECONDS); } - public void verifyReceived(CoapResponse obs) throws InterruptedException { + public void verifyReceived(CoapResponse.Builder obs) throws InterruptedException { CoapResponse received = queue.poll(1, TimeUnit.SECONDS).asResponse(); assertEquals(obs, received); } diff --git a/coap-mbedtls/src/test/java/org/opencoap/transport/mbedtls/MbedtlsCoapTransportTest.java b/coap-mbedtls/src/test/java/org/opencoap/transport/mbedtls/MbedtlsCoapTransportTest.java index 6a1d51b1..e036f35a 100644 --- a/coap-mbedtls/src/test/java/org/opencoap/transport/mbedtls/MbedtlsCoapTransportTest.java +++ b/coap-mbedtls/src/test/java/org/opencoap/transport/mbedtls/MbedtlsCoapTransportTest.java @@ -20,6 +20,7 @@ import static com.mbed.coap.packet.CoapResponse.coapResponse; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Opaque.of; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Networks.localhost; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/coap-mbedtls/src/test/java/org/opencoap/transport/mbedtls/MbedtlsNettyTest.java b/coap-mbedtls/src/test/java/org/opencoap/transport/mbedtls/MbedtlsNettyTest.java index 66494b4a..7931e28a 100644 --- a/coap-mbedtls/src/test/java/org/opencoap/transport/mbedtls/MbedtlsNettyTest.java +++ b/coap-mbedtls/src/test/java/org/opencoap/transport/mbedtls/MbedtlsNettyTest.java @@ -19,10 +19,10 @@ import static com.mbed.coap.packet.CoapResponse.badRequest; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Opaque.of; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Networks.localhost; import static java.util.Collections.singletonMap; import static java.util.concurrent.CompletableFuture.completedFuture; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.opencoap.coap.netty.CoapCodec.EMPTY_RESOLVER; import static org.opencoap.transport.mbedtls.DtlsTransportContext.DTLS_AUTHENTICATION; diff --git a/coap-metrics/build.gradle.kts b/coap-metrics/build.gradle.kts index 7f82c212..0e571084 100644 --- a/coap-metrics/build.gradle.kts +++ b/coap-metrics/build.gradle.kts @@ -10,4 +10,5 @@ dependencies { implementation("io.micrometer:micrometer-core:1.11.4") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0") + testImplementation(testFixtures(project(":coap-core"))) } diff --git a/coap-metrics/src/test/java/org/opencoap/coap/metrics/micrometer/MicrometerMetricsFilterTest.java b/coap-metrics/src/test/java/org/opencoap/coap/metrics/micrometer/MicrometerMetricsFilterTest.java index 8a3f103c..a19e846b 100644 --- a/coap-metrics/src/test/java/org/opencoap/coap/metrics/micrometer/MicrometerMetricsFilterTest.java +++ b/coap-metrics/src/test/java/org/opencoap/coap/metrics/micrometer/MicrometerMetricsFilterTest.java @@ -17,8 +17,8 @@ import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.packet.CoapResponse.ok; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.FutureHelpers.failedFuture; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/coap-netty/src/test/java/org/opencoap/coap/netty/NettyTest.java b/coap-netty/src/test/java/org/opencoap/coap/netty/NettyTest.java index b815c220..56473ffc 100644 --- a/coap-netty/src/test/java/org/opencoap/coap/netty/NettyTest.java +++ b/coap-netty/src/test/java/org/opencoap/coap/netty/NettyTest.java @@ -18,8 +18,8 @@ import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.packet.CoapRequest.post; import static com.mbed.coap.packet.CoapResponse.ok; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Networks.localhost; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opencoap.coap.netty.CoapCodec.EMPTY_RESOLVER; import com.mbed.coap.client.CoapClient; diff --git a/coap-tcp/src/test/java/com/mbed/coap/packet/CoapTcpPacketConverterTest.java b/coap-tcp/src/test/java/com/mbed/coap/packet/CoapTcpPacketConverterTest.java index 70ec3aeb..0fcf9615 100644 --- a/coap-tcp/src/test/java/com/mbed/coap/packet/CoapTcpPacketConverterTest.java +++ b/coap-tcp/src/test/java/com/mbed/coap/packet/CoapTcpPacketConverterTest.java @@ -86,4 +86,4 @@ void convertSeperateResponseToCoap() { assertEquals(expected, coapPacket); } -} \ No newline at end of file +} diff --git a/coap-tcp/src/test/java/com/mbed/coap/server/messaging/TcpExchangeFilterTest.java b/coap-tcp/src/test/java/com/mbed/coap/server/messaging/TcpExchangeFilterTest.java index 93fe64f3..8d76fb7b 100644 --- a/coap-tcp/src/test/java/com/mbed/coap/server/messaging/TcpExchangeFilterTest.java +++ b/coap-tcp/src/test/java/com/mbed/coap/server/messaging/TcpExchangeFilterTest.java @@ -20,6 +20,7 @@ import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Opaque.variableUInt; import static com.mbed.coap.transport.TransportContext.EMPTY; +import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.FutureHelpers.failedFuture; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.assertj.core.api.Assertions.assertThatThrownBy; From 39184ea667b7f6510e60e657d155b757ee77b90f Mon Sep 17 00:00:00 2001 From: Szymon Sasin Date: Tue, 20 Jun 2023 14:18:17 +0300 Subject: [PATCH 2/2] Refactor CoapRequest with builder pattern --- .../java/com/mbed/coap/cli/SendCommand.java | 10 +- .../java/com/mbed/coap/cli/CoapCliTest.java | 10 +- .../java/com/mbed/coap/client/CoapClient.java | 10 +- .../com/mbed/coap/packet/CoapRequest.java | 301 +++++++++--------- .../coap/server/ObserveRequestFilter.java | 2 +- .../coap/server/block/BlockWiseCallback.java | 8 +- .../server/block/BlockWiseIncomingFilter.java | 2 +- .../coap/server/block/BlockWiseTransfer.java | 4 +- .../mbed/coap/server/filter/EchoFilter.java | 6 +- .../server/filter/TokenGeneratorFilter.java | 2 +- .../com/mbed/coap/packet/CoapRequestTest.java | 161 ++++++---- .../mbed/coap/packet/CoapResponseTest.java | 13 +- .../server/CriticalOptionVerifierTest.java | 2 +- .../coap/server/ObservationHandlerTest.java | 2 +- .../coap/server/ObserveRequestFilterTest.java | 7 +- .../mbed/coap/server/RescueFilterTest.java | 11 +- .../mbed/coap/server/RouterServiceTest.java | 34 +- .../mbed/coap/server/RoutingServiceTest.java | 5 +- .../server/block/BlockWiseCallbackTest.java | 2 +- .../filter/EtagGeneratorFilterTest.java | 5 +- .../filter/EtagValidatorFilterTest.java | 6 +- .../filter/MaxAllowedPayloadFilterTest.java | 3 +- .../filter/TokenGeneratorFilterTest.java | 4 +- .../observe/NotificationsReceiverTest.java | 4 +- .../server/observe/ObserversManagerTest.java | 2 +- .../ClientServerWithBlocksTest.java | 3 +- .../java/com/mbed/coap/utils/Assertions.java | 5 + .../coap/utils/CoapRequestBuilderFilter.java | 27 ++ .../protocolTests/IntegrationTestBase.java | 8 +- .../MicrometerMetricsFilterTest.java | 8 +- 30 files changed, 390 insertions(+), 277 deletions(-) create mode 100644 coap-core/src/testFixtures/java/com/mbed/coap/utils/CoapRequestBuilderFilter.java diff --git a/coap-cli/src/main/java/com/mbed/coap/cli/SendCommand.java b/coap-cli/src/main/java/com/mbed/coap/cli/SendCommand.java index b03a3fdf..dbc04604 100644 --- a/coap-cli/src/main/java/com/mbed/coap/cli/SendCommand.java +++ b/coap-cli/src/main/java/com/mbed/coap/cli/SendCommand.java @@ -17,6 +17,7 @@ package com.mbed.coap.cli; import static com.mbed.coap.cli.TransportOptions.addressFromUri; +import static com.mbed.coap.packet.CoapRequest.request; import com.mbed.coap.CoapConstants; import com.mbed.coap.client.CoapClient; import com.mbed.coap.packet.BlockSize; @@ -82,15 +83,16 @@ public Integer call() throws Exception { Thread.sleep(200); String uriPath = uri.getPath().isEmpty() ? CoapConstants.WELL_KNOWN_CORE : uri.getPath(); - request = CoapRequest.of(null, method, uriPath) + request = request(method, uriPath) .query(uri.getQuery() == null ? "" : uri.getQuery()) .blockSize(blockSize) .payload(hexPayload ? Opaque.decodeHex(payload) : Opaque.of(payload)) + .contentFormat(contentFormat) + .accept(accept) .options(o -> o - .contentFormat(contentFormat) .proxyUri(proxyUri) - .accept(accept) - ); + ) + .build(); CoapResponse resp = cli.sendSync(request); if (resp.getPayload().nonEmpty()) { diff --git a/coap-cli/src/test/java/com/mbed/coap/cli/CoapCliTest.java b/coap-cli/src/test/java/com/mbed/coap/cli/CoapCliTest.java index 0ab88f8a..106c1a8d 100644 --- a/coap-cli/src/test/java/com/mbed/coap/cli/CoapCliTest.java +++ b/coap-cli/src/test/java/com/mbed/coap/cli/CoapCliTest.java @@ -18,9 +18,9 @@ import static com.mbed.coap.packet.BlockSize.S_16; import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.packet.CoapResponse.coapResponse; -import static com.mbed.coap.packet.CoapOptionsBuilder.options; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.transport.udp.DatagramSocketTransport.udp; +import static com.mbed.coap.utils.Assertions.assertEquals; import static java.lang.String.format; import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -93,7 +93,7 @@ void simplestRequest() { // then assertEquals(0, exitCode); assertEquals("\nDziala!\n", sw.toString().replace("\r", "")); - assertEquals(CoapRequest.get("/test"), sendCommand.request); + assertEquals(get("/test"), sendCommand.request); } @Test @@ -109,10 +109,10 @@ void requestWithAllCoapParameters() { assertEquals(0, exitCode); assertEquals("\nReceived 29\n", sw.toString().replace("\r", "")); - CoapRequest expected = CoapRequest.post("/test") + CoapRequest.Builder expected = CoapRequest.post("/test") .options(it -> it .query("par1", "val1") - .block1Req(1, S_16, false) + .block1Req(0, S_16, true) .proxyUri("http://another-uri") .requestTag(sendCommand.request.options().getRequestTag()) // it's random ) @@ -129,7 +129,7 @@ public void requestWithHexPayload() { assertEquals(0, exitCode); assertEquals("\nReceived 27\n", sw.toString().replace("\r", "")); - CoapRequest expected = CoapRequest.post("/test") + CoapRequest.Builder expected = CoapRequest.post("/test") .payload(Opaque.decodeHex("a16e626573745f6775697461726973746a476172795f4d6f6f7265"), MediaTypes.CT_APPLICATION_CBOR) .accept(MediaTypes.CT_APPLICATION_JSON); assertEquals(expected, sendCommand.request); diff --git a/coap-core/src/main/java/com/mbed/coap/client/CoapClient.java b/coap-core/src/main/java/com/mbed/coap/client/CoapClient.java index de8766c2..b5990492 100644 --- a/coap-core/src/main/java/com/mbed/coap/client/CoapClient.java +++ b/coap-core/src/main/java/com/mbed/coap/client/CoapClient.java @@ -60,13 +60,21 @@ public static CoapClient create(InetSocketAddress target, CoapServer server, Fun } public CompletableFuture send(CoapRequest request) { - return clientService.apply(request.address(destination)); + return clientService.apply(request.withAddress(destination)); + } + + public CompletableFuture send(CoapRequest.Builder request) { + return send(request.build()); } public CoapResponse sendSync(CoapRequest request) throws CoapException { return await(send(request)); } + public CoapResponse sendSync(CoapRequest.Builder request) throws CoapException { + return sendSync(request.build()); + } + private static CoapResponse await(CompletableFuture future) throws CoapException { try { return future.get(5, TimeUnit.MINUTES); diff --git a/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java b/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java index feabcbef..4e81d3a0 100644 --- a/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java +++ b/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java @@ -20,6 +20,7 @@ import com.mbed.coap.transport.TransportContext; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.time.Duration; import java.util.Objects; import java.util.function.Consumer; @@ -52,58 +53,46 @@ private CoapRequest(InetSocketAddress peerAddress, TransportContext transContext // --- STATIC BUILDERS --- + public static Builder request(Method method, String uriPath) { + return new Builder(method, uriPath); + } - public static CoapRequest of(InetSocketAddress peerAddress, Method method, String uriPath) { - HeaderOptions options = new HeaderOptions(); - options.setUriPath(uriPath); - - return new CoapRequest(method, Opaque.EMPTY, options, Opaque.EMPTY, peerAddress, TransportContext.EMPTY); + public static Builder get(String uriPath) { + return request(Method.GET, uriPath); } - public static CoapRequest get(String uriPath) { - return CoapRequest.of(null, Method.GET, uriPath); + public static Builder put(String uriPath) { + return request(Method.PUT, uriPath); } - public static CoapRequest post(String uriPath) { - return CoapRequest.of(null, Method.POST, uriPath); + public static Builder post(String uriPath) { + return request(Method.POST, uriPath); } - public static CoapRequest put(String uriPath) { - return CoapRequest.of(null, Method.PUT, uriPath); + public static Builder delete(String uriPath) { + return request(Method.DELETE, uriPath); } - public static CoapRequest delete(String uriPath) { - return CoapRequest.of(null, Method.DELETE, uriPath); + public static Builder fetch(String uriPath) { + return request(Method.FETCH, uriPath); } - public static CoapRequest fetch(String uriPath) { - return CoapRequest.of(null, Method.FETCH, uriPath); + public static Builder patch(String uriPath) { + return request(Method.PATCH, uriPath); } - public static CoapRequest patch(String uriPath) { - return CoapRequest.of(null, Method.PATCH, uriPath); + public static Builder iPatch(String uriPath) { + return request(Method.iPATCH, uriPath); } - public static CoapRequest iPatch(String uriPath) { - return CoapRequest.of(null, Method.iPATCH, uriPath); + public static Builder observe(String uriPath) { + return get(uriPath).observe(); } public static CoapRequest ping(InetSocketAddress peerAddress, TransportContext transContext) { return new CoapRequest(peerAddress, transContext); } - public static CoapRequest observe(String uriPath) { - return observe(null, uriPath); - } - - public static CoapRequest observe(InetSocketAddress peerAddress, String uriPath) { - CoapRequest obsRequest = new CoapRequest(Method.GET, Opaque.EMPTY, new HeaderOptions(), Opaque.EMPTY, peerAddress, TransportContext.EMPTY); - obsRequest.options().setObserve(0); - obsRequest.options().setUriPath(uriPath); - - return obsRequest; - } - // -------------------- @@ -180,161 +169,181 @@ public String toString() { // --- MODIFIERS --- - public CoapRequest token(Opaque newToken) { + public CoapRequest withToken(Opaque newToken) { return new CoapRequest(method, newToken, options, payload, peerAddress, transContext); } - public CoapRequest token(long token) { - return token(Opaque.variableUInt(token)); + public CoapRequest withOptions(Consumer optionsFunc) { + CoapOptionsBuilder optionsBuilder = CoapOptionsBuilder.from(options); + optionsFunc.accept(optionsBuilder); + return new CoapRequest(method, token, optionsBuilder.build(), payload, peerAddress, transContext); } - - public CoapRequest payload(Opaque newPayload) { + public CoapRequest withPayload(Opaque newPayload) { return new CoapRequest(method, token, options, newPayload, peerAddress, transContext); } - public CoapRequest payload(String newPayload) { - return payload(Opaque.of(newPayload)); + public CoapRequest withAddress(InetSocketAddress newPeerAddress) { + return new CoapRequest(method, token, options, payload, newPeerAddress, transContext); } - public CoapRequest payload(String newPayload, short contentFormat) { - options.setContentFormat(contentFormat); - return payload(newPayload); - } + public static class Builder { + private final Method method; + private Opaque token = Opaque.EMPTY; + private final CoapOptionsBuilder options; + private Opaque payload = Opaque.EMPTY; + private InetSocketAddress peerAddress; + private TransportContext transContext = TransportContext.EMPTY; - public CoapRequest payload(Opaque newPayload, short contentFormat) { - options.setContentFormat(contentFormat); - return payload(newPayload); - } + private Builder(Method method, String uriPath) { + this.method = method; + this.options = CoapOptionsBuilder.options(); + this.options.uriPath(uriPath); + } - public CoapRequest address(InetSocketAddress newPeerAddress) { - return new CoapRequest(method, token, options, payload, newPeerAddress, transContext); - } + public CoapRequest build() { + return new CoapRequest(method, token, options.build(), payload, peerAddress, transContext); + } - public CoapRequest from(InetSocketAddress peerAddress) { - return this.address(peerAddress); - } + public CoapRequest to(InetSocketAddress address) { + return this.address(address).build(); + } - public CoapRequest to(InetSocketAddress peerAddress) { - return address(peerAddress); - } + public CoapRequest toLocal(int localPort) { + return wrapExceptions(() -> + this.address(new InetSocketAddress(InetAddress.getLocalHost(), localPort)).build() + ); + } - public CoapRequest fromLocal(int localPort) { - return wrapExceptions(() -> - address(new InetSocketAddress(InetAddress.getLocalHost(), localPort)) - ); - } + public CoapRequest from(InetSocketAddress address) { + return this.address(address).build(); + } - public CoapRequest toLocal(int localPort) { - return fromLocal(localPort); - } + public CoapRequest fromLocal(int localPort) { + return wrapExceptions(() -> + this.address(new InetSocketAddress(InetAddress.getLocalHost(), localPort)).build() + ); + } - public CoapRequest context(TransportContext newTransportContext) { - return new CoapRequest(method, token, options, payload, peerAddress, newTransportContext); - } + public Builder payload(Opaque payload, short contentFormat) { + this.payload = payload; + return contentFormat(contentFormat); + } - public CoapRequest context(TransportContext.Key key, T value) { - return new CoapRequest(method, token, options, payload, peerAddress, TransportContext.of(key, value)); - } + public Builder payload(String payload, short contentFormat) { + return payload(Opaque.of(payload), contentFormat); + } - // --- OPTIONS MODIFIERS --- + public Builder payload(String newPayload) { + return payload(Opaque.of(newPayload)); + } - public CoapRequest options(Consumer optionsConsumer) { - CoapOptionsBuilder optionsBuilder = new CoapOptionsBuilder(options); - optionsConsumer.accept(optionsBuilder); - return this; - } + public Builder payload(Opaque payload) { + this.payload = payload; + return this; + } - public CoapRequest observe(int observe) { - options.setObserve(observe); - return this; - } + public Builder token(Opaque token) { + this.token = token; + return this; + } - public CoapRequest observe() { - options.setObserve(0); - return this; - } + public Builder token(long token) { + return token(Opaque.variableUInt(token)); + } - public CoapRequest deregisterObserve() { - options.setObserve(1); - return this; - } + public Builder context(TransportContext newTransportContext) { + this.transContext = newTransportContext; + return this; + } - public CoapRequest etag(Opaque etag) { - options.setEtag(etag); - return this; - } + public Builder context(TransportContext.Key key, T value) { + transContext = transContext.with(key, value); + return this; + } - public CoapRequest block1Req(int num, BlockSize size, boolean more) { - options.setBlock1Req(new BlockOption(num, size, more)); - return this; - } + public Builder address(InetSocketAddress address) { + this.peerAddress = address; + return this; + } - public CoapRequest block2Res(int num, BlockSize size, boolean more) { - options.setBlock2Res(new BlockOption(num, size, more)); - return this; - } + public Builder options(Consumer optionsFunc) { + optionsFunc.accept(options); + return this; + } - public CoapRequest size1(int size) { - options.setSize1(size); - return this; - } + public Builder observe() { + options.observe(0); + return this; + } - public CoapRequest maxAge(long maxAge) { - this.options.setMaxAge(maxAge); - return this; - } + public Builder deregisterObserve() { + options.observe(1); + return this; + } - public CoapRequest host(String host) { - this.options.setUriHost(host); - return this; - } - public CoapRequest query(String name, String val) { - if (name.isEmpty() || name.contains("=") || name.contains("&") || name.contains("?") - || val.isEmpty() || val.contains("=") || val.contains("&") || val.contains("?")) { - throw new IllegalArgumentException("Non valid characters provided in query"); + public Builder accept(Short contentFormat) { + options.accept(contentFormat); + return this; } - final StringBuilder query = new StringBuilder(); - if (options.getUriQuery() != null) { - query.append(options.getUriQuery()); - query.append('&'); + + public Builder blockSize(BlockSize size) { + if (size == null) { + return this; + } + if (method == Method.GET) { + options.block2Res(0, size, false); + } + if (method == Method.PUT || method == Method.POST || method == Method.FETCH || method == Method.PATCH || method == Method.iPATCH) { + options.block1Req(0, size, true); + } + return this; + } + + public Builder block1Req(int blockNr, BlockSize size, boolean more) { + options.block1Req(blockNr, size, more); + return this; } - query.append(name).append('=').append(val); - options.setUriQuery(query.toString()); - return this; - } - public CoapRequest blockSize(BlockSize size) { - if (size == null) { + public Builder block2Res(int blockNr, BlockSize blockSize, boolean more) { + options.block2Res(blockNr, blockSize, more); return this; } - if (method == Method.GET) { - options.setBlock2Res(new BlockOption(0, size, false)); + + public Builder size1(int size) { + options.size1(size); + return this; } - if (method == Method.PUT || method == Method.POST || method == Method.FETCH || method == Method.PATCH || method == Method.iPATCH) { - options.setBlock1Req(new BlockOption(0, size, true)); + + public Builder etag(Opaque... etag) { + options.etag(etag); + return this; } - return this; - } - public CoapRequest query(String uriQuery) { - options.setUriQuery(uriQuery); - return this; - } + public Builder query(String query) { + options.query(query); + return this; + } - public CoapRequest proxy(String proxyUri) { - options.setProxyUri(proxyUri); - return this; - } + public Builder maxAge(Duration maxAge) { + options.maxAge(maxAge); + return this; + } - public CoapRequest ifMatch(Opaque etag) { - options.setIfMatch(new Opaque[]{etag}); - return this; - } + public Builder host(String host) { + options.host(host); + return this; + } - public CoapRequest accept(short contentFormat) { - options.setAccept(contentFormat); - return this; + public Builder query(String name, String value) { + options.query(name, value); + return this; + } + + public Builder contentFormat(Short contentFormat) { + options.contentFormat(contentFormat); + return this; + } } } diff --git a/coap-core/src/main/java/com/mbed/coap/server/ObserveRequestFilter.java b/coap-core/src/main/java/com/mbed/coap/server/ObserveRequestFilter.java index 45dd34e4..a9c8b041 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/ObserveRequestFilter.java +++ b/coap-core/src/main/java/com/mbed/coap/server/ObserveRequestFilter.java @@ -41,7 +41,7 @@ public CompletableFuture apply(CoapRequest req, Service sendService, Capabilities csm, CoapRequest.Builder request, int maxIncomingBlockTransferSize) throws CoapException { + this(sendService, csm, request.build(), maxIncomingBlockTransferSize); + } + CompletableFuture receive(CoapResponse response) { LOGGER.trace("BlockWiseCallback.call(): {}", response); @@ -125,7 +129,7 @@ private CompletableFuture handleIfBlock1(CoapResponse response) { // see https://tools.ietf.org/html/draft-ietf-core-block-18#section-4 , Implementation notes request.options().setSize1(null); Opaque blockPayload = BlockWiseTransfer.createBlockPart(responseBlock, requestPayload, maxBlockPayload); - request = request.payload(blockPayload); + request = request.withPayload(blockPayload); LOGGER.trace("BlockWiseCallback.call() next block b1: {}", request); return makeRequest(); } @@ -210,7 +214,7 @@ private CompletableFuture restartBlockRequest(BlockSize newSize) { request.options().setBlock1Req(block1Req); Opaque blockPayload = BlockWiseTransfer.createBlockPart(block1Req, requestPayload, block1Req.getSize()); - request = request.payload(blockPayload); + request = request.withPayload(blockPayload); return makeRequest(); } diff --git a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseIncomingFilter.java b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseIncomingFilter.java index 8f06f912..1bd1b427 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseIncomingFilter.java +++ b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseIncomingFilter.java @@ -85,7 +85,7 @@ public CompletableFuture apply(CoapRequest request, Service adjustPayloadSize(coapRequest, resp)); diff --git a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseTransfer.java b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseTransfer.java index 40985ff4..182d031e 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseTransfer.java +++ b/coap-core/src/main/java/com/mbed/coap/server/block/BlockWiseTransfer.java @@ -43,7 +43,7 @@ static CoapRequest createFirstBlock(CoapRequest request, Capabilities csm) { int maxBlockPayload = csm.getMaxOutboundPayloadSize(); return request - .options(o -> o + .withOptions(o -> o .block1Req(blockOption) .unsetBlock2Res() .size1(payloadSize) @@ -52,7 +52,7 @@ static CoapRequest createFirstBlock(CoapRequest request, Capabilities csm) { o.requestTag(csm.nextRequestTag()) ) ) - .payload( + .withPayload( createBlockPart(blockOption, request.getPayload(), maxBlockPayload) ); } diff --git a/coap-core/src/main/java/com/mbed/coap/server/filter/EchoFilter.java b/coap-core/src/main/java/com/mbed/coap/server/filter/EchoFilter.java index 4021e108..4bdb201f 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/filter/EchoFilter.java +++ b/coap-core/src/main/java/com/mbed/coap/server/filter/EchoFilter.java @@ -15,6 +15,7 @@ */ package com.mbed.coap.server.filter; +import static java.util.concurrent.CompletableFuture.completedFuture; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Code; @@ -31,10 +32,11 @@ public CompletableFuture apply(CoapRequest request, Service { if (resp.getCode() == Code.C401_UNAUTHORIZED && resp.options().getEcho() != null) { // server required freshness verification, retry with echo - CoapRequest requestWithEcho = request.options(it -> it.echo(resp.options().getEcho())); + + CoapRequest requestWithEcho = request.withOptions(it -> it.echo(resp.options().getEcho())); return service.apply(requestWithEcho); } else { - return resp.toFuture(); + return completedFuture(resp); } }); } diff --git a/coap-core/src/main/java/com/mbed/coap/server/filter/TokenGeneratorFilter.java b/coap-core/src/main/java/com/mbed/coap/server/filter/TokenGeneratorFilter.java index 72050dd9..afd55d83 100644 --- a/coap-core/src/main/java/com/mbed/coap/server/filter/TokenGeneratorFilter.java +++ b/coap-core/src/main/java/com/mbed/coap/server/filter/TokenGeneratorFilter.java @@ -48,7 +48,7 @@ public TokenGeneratorFilter(Supplier tokenGenerator) { @Override public CompletableFuture apply(CoapRequest request, Service service) { if (!request.isPing() && request.getToken().isEmpty()) { - return service.apply(request.token(tokenGenerator.get())); + return service.apply(request.withToken(tokenGenerator.get())); } return service.apply(request); diff --git a/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java b/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java index 3a1ca089..90e18069 100644 --- a/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java +++ b/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java @@ -16,88 +16,75 @@ */ package com.mbed.coap.packet; +import static com.mbed.coap.packet.BlockSize.S_32; +import static com.mbed.coap.packet.BlockSize.S_512; +import static com.mbed.coap.packet.BlockSize.S_64; +import static com.mbed.coap.packet.CoapRequest.fetch; +import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.packet.CoapRequest.ping; +import static com.mbed.coap.packet.CoapResponseTest.newOptions; +import static com.mbed.coap.packet.MediaTypes.CT_APPLICATION_JSON; +import static com.mbed.coap.packet.Opaque.EMPTY; +import static com.mbed.coap.packet.Opaque.decodeHex; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static protocolTests.utils.CoapPacketBuilder.LOCAL_1_5683; +import static protocolTests.utils.CoapPacketBuilder.LOCAL_5683; import com.mbed.coap.transport.TransportContext; -import java.net.InetSocketAddress; +import java.time.Duration; import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; class CoapRequestTest { - private InetSocketAddress destination = new InetSocketAddress("localhost", 5683); @Test - public void buildWithAllPossibleFields() { - CoapRequest buildRequest = CoapRequest.get("/0/1/2") - .address(destination) - .accept((short) 1) - .blockSize(BlockSize.S_16) - .etag(Opaque.ofBytes(10, 8, 6)) - .host("some.com") - .ifMatch(Opaque.ofBytes(9, 7, 5)) - .maxAge(789456L) - .payload("perse", MediaTypes.CT_TEXT_PLAIN) - .query("p=1") - .query("b", "2") - .token(45463L); - - CoapRequest expected = new CoapRequest(Method.GET, Opaque.ofBytes(0xB1, 0x97), new HeaderOptions(), Opaque.of("perse"), destination, TransportContext.EMPTY); - expected.options().setUriPath("/0/1/2"); - expected.options().setAccept((short) 1); - expected.options().setEtag(Opaque.ofBytes(10, 8, 6)); - expected.options().setUriHost("some.com"); - expected.options().setIfMatch(new Opaque[]{Opaque.ofBytes(9, 7, 5)}); - expected.options().setMaxAge(789456L); - expected.options().setUriQuery("p=1&b=2"); - expected.options().setContentFormat(MediaTypes.CT_TEXT_PLAIN); - expected.options().setBlock2Res(new BlockOption(0, BlockSize.S_16, false)); - - assertEquals(expected, buildRequest); - } - - - @Test - public void malformedUriQuery() { - CoapRequest req = CoapRequest.put("/0/1/2"); - failQueryWithNonValidChars(req, "", "2"); - failQueryWithNonValidChars(req, "&", "2"); - failQueryWithNonValidChars(req, "=", "54"); - failQueryWithNonValidChars(req, "f", ""); - failQueryWithNonValidChars(req, "f", "&"); - failQueryWithNonValidChars(req, "f", "="); - } + void shouldCreatePing() { + CoapRequest ping = ping(LOCAL_5683, TransportContext.EMPTY); - private static void failQueryWithNonValidChars(CoapRequest req, String name, String val) { - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> req.query(name, val)); + assertTrue(ping.isPing()); + assertThrows(NullPointerException.class, () -> ping.withPayload(Opaque.of("a")).isPing()); + assertThrows(NullPointerException.class, () -> ping.withToken(decodeHex("12")).isPing()); - assertEquals("Non valid characters provided in query", e.getMessage()); + assertFalse(new CoapRequest(Method.GET, EMPTY, new HeaderOptions(), EMPTY, LOCAL_5683, TransportContext.EMPTY).isPing()); } @Test - void shouldCreatePing() { - CoapRequest ping = ping(destination, TransportContext.EMPTY); + public void shouldModifyCoapRequest() { + CoapRequest request = new CoapRequest(Method.POST, decodeHex("0102"), newOptions(o -> o.setUriPath("/test")), Opaque.of("test-1"), LOCAL_5683, TransportContext.EMPTY); + CoapRequest expected = new CoapRequest(Method.POST, decodeHex("ffff"), newOptions(o -> o.setUriPath("/test2")), Opaque.of("test-2"), LOCAL_1_5683, TransportContext.EMPTY); - assertTrue(ping.isPing()); - assertThrows(NullPointerException.class, () -> ping.payload("a").isPing()); - assertThrows(NullPointerException.class, () -> ping.token(1).isPing()); + // when + CoapRequest request2 = request + .withToken(decodeHex("ffff")) + .withOptions(o -> o.uriPath("/test2")) + .withPayload(Opaque.of("test-2")) + .withAddress(LOCAL_1_5683); + + // then + assertEquals(request2, expected); - assertFalse(new CoapRequest(Method.GET, Opaque.EMPTY, new HeaderOptions(), Opaque.EMPTY, destination, TransportContext.EMPTY).isPing()); + // and original object is not changed + assertEquals(decodeHex("0102"), request.getToken()); + assertEquals(Opaque.of("test-1"), request.getPayload()); + assertEquals(LOCAL_5683, request.getPeerAddress()); } @Test void testToString() { - assertEquals("CoapRequest[PUT URI:/test,Token:03ff, pl(4):64757061]", CoapRequest.put("/test").token(1023).payload("dupa").toString()); - assertEquals("CoapRequest[POST URI:/test, pl(4):64757061]", CoapRequest.post("/test").payload("dupa").toString()); - assertEquals("CoapRequest[DELETE URI:/test,Token:03ff]", CoapRequest.delete("/test").token(1023).toString()); - assertEquals("CoapRequest[GET URI:/test]", CoapRequest.get("/test").toString()); - assertEquals("CoapRequest[FETCH URI:/test, pl(4):64757061]", CoapRequest.fetch("/test").payload("dupa").toString()); - assertEquals("CoapRequest[PATCH URI:/test, pl(4):64757061]", CoapRequest.patch("/test").payload("dupa").toString()); - assertEquals("CoapRequest[iPATCH URI:/test, pl(4):64757061]", CoapRequest.iPatch("/test").payload("dupa").toString()); - assertEquals("CoapRequest[PING]", CoapRequest.ping(destination, TransportContext.EMPTY).toString()); + assertEquals("CoapRequest[PUT URI:/test,Token:03ff, pl(4):64757061]", CoapRequest.put("/test").token(1023).payload("dupa").build().toString()); + assertEquals("CoapRequest[POST URI:/test, pl(4):64757061]", CoapRequest.post("/test").payload("dupa").build().toString()); + assertEquals("CoapRequest[DELETE URI:/test,Token:03ff]", CoapRequest.delete("/test").token(1023).build().toString()); + assertEquals("CoapRequest[GET URI:/test]", get("/test").build().toString()); + assertEquals("CoapRequest[FETCH URI:/test, pl(4):64757061]", fetch("/test").payload("dupa").build().toString()); + assertEquals("CoapRequest[PATCH URI:/test, pl(4):64757061]", CoapRequest.patch("/test").payload("dupa").build().toString()); + assertEquals("CoapRequest[iPATCH URI:/test, pl(4):64757061]", CoapRequest.iPatch("/test").payload("dupa").build().toString()); + assertEquals("CoapRequest[GET URI:/test obs:0]", CoapRequest.observe("/test").build().toString()); + assertEquals("CoapRequest[PING]", CoapRequest.ping(LOCAL_5683, TransportContext.EMPTY).toString()); } @Test @@ -107,4 +94,62 @@ public void equalsAndHashTest() { .withPrefabValues(TransportContext.class, TransportContext.EMPTY, TransportContext.of(TransportContext.NON_CONFIRMABLE, true)) .verify(); } + + @Nested + class BuilderTest { + + @Test + public void buildWithAllPossibleFields() { + CoapRequest buildRequest = get("/0/1/2").options(o -> o + .ifMatch(Opaque.ofBytes(9, 7, 5)) + ) + .token(45463L) + .accept(CT_APPLICATION_JSON) + .maxAge(Duration.ofHours(1)) + .block1Req(0, S_32, true) + .block2Res(0, S_64, true) + .etag(decodeHex("010203")) + .host("some.com") + .query("p=1") + .query("b", "2") + .size1(342) + .observe() + .payload("perse", MediaTypes.CT_TEXT_PLAIN) + .from(LOCAL_5683); + + CoapRequest expected = new CoapRequest(Method.GET, Opaque.ofBytes(0xB1, 0x97), new HeaderOptions(), Opaque.of("perse"), LOCAL_5683, TransportContext.EMPTY); + expected.options().setUriPath("/0/1/2"); + expected.options().setAccept(CT_APPLICATION_JSON); + expected.options().setObserve(0); + expected.options().setEtag(decodeHex("010203")); + expected.options().setUriHost("some.com"); + expected.options().setIfMatch(new Opaque[]{Opaque.ofBytes(9, 7, 5)}); + expected.options().setMaxAge(3600L); + expected.options().setUriQuery("p=1&b=2"); + expected.options().setContentFormat(MediaTypes.CT_TEXT_PLAIN); + expected.options().setBlock1Req(new BlockOption(0, S_32, true)); + expected.options().setBlock2Res(new BlockOption(0, S_64, true)); + expected.options().setSize1(342); + + assertEquals(expected, buildRequest); + } + + @Test + public void shouldSetBlockOptionBasedOnMethod() { + CoapRequest req = fetch("/test").blockSize(S_512).build(); + CoapRequest req2 = get("/test").blockSize(S_512).build(); + + assertEquals(new BlockOption(0, S_512, true), req.options().getBlock1Req()); + assertNull(req.options().getBlock2Res()); + + assertEquals(new BlockOption(0, S_512, false), req2.options().getBlock2Res()); + assertNull(req2.options().getBlock1Req()); + } + + @Test + public void shouldSetObserveOption() { + assertEquals(0, get("/test").observe().build().options().getObserve()); + assertEquals(1, get("/test").deregisterObserve().build().options().getObserve()); + } + } } diff --git a/coap-core/src/test/java/com/mbed/coap/packet/CoapResponseTest.java b/coap-core/src/test/java/com/mbed/coap/packet/CoapResponseTest.java index f09a2af6..cdf88228 100644 --- a/coap-core/src/test/java/com/mbed/coap/packet/CoapResponseTest.java +++ b/coap-core/src/test/java/com/mbed/coap/packet/CoapResponseTest.java @@ -89,12 +89,6 @@ void testToString() { assertEquals("CoapResponse[400, ContTp:50, pl(13):7b226572726f72223a3132337d]", coapResponse(C400_BAD_REQUEST).payload("{\"error\":123}").contentFormat(CT_APPLICATION_JSON).build().toString()); } - private static HeaderOptions newOptions(Consumer optionsFunc) { - HeaderOptions options = new HeaderOptions(); - optionsFunc.accept(options); - return options; - } - @Nested class BuilderTest { @@ -147,4 +141,11 @@ public void shouldReturnSeparateResponse() { assertEquals(expected, separateResponse); } } + + static HeaderOptions newOptions(Consumer optionsFunc) { + HeaderOptions options = new HeaderOptions(); + optionsFunc.accept(options); + return options; + } + } diff --git a/coap-core/src/test/java/com/mbed/coap/server/CriticalOptionVerifierTest.java b/coap-core/src/test/java/com/mbed/coap/server/CriticalOptionVerifierTest.java index 62e9340d..f9a7f9f0 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/CriticalOptionVerifierTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/CriticalOptionVerifierTest.java @@ -31,7 +31,7 @@ class CriticalOptionVerifierTest { @Test void shouldReturnBadOptionWhenUnrecognizedCriticalOption() { - CoapRequest req = get("/test").options(o -> o.custom(1001, Opaque.of("foo"))); + CoapRequest req = get("/test").options(o -> o.custom(1001, Opaque.of("foo"))).build(); CompletableFuture resp = filter.apply(req, null); diff --git a/coap-core/src/test/java/com/mbed/coap/server/ObservationHandlerTest.java b/coap-core/src/test/java/com/mbed/coap/server/ObservationHandlerTest.java index eae97c7b..5e08fe42 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/ObservationHandlerTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/ObservationHandlerTest.java @@ -46,7 +46,7 @@ void setUp() { reset(service); notifReceiver.clear(); - obsMap.add(get("/obs").token(of("100"))); + obsMap.add(get("/obs").token(of("100")).build()); } @Test diff --git a/coap-core/src/test/java/com/mbed/coap/server/ObserveRequestFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/ObserveRequestFilterTest.java index ea74672f..aa565c00 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/ObserveRequestFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/ObserveRequestFilterTest.java @@ -21,6 +21,7 @@ import static com.mbed.coap.packet.Opaque.EMPTY; import static com.mbed.coap.packet.Opaque.ofBytes; import static com.mbed.coap.utils.Assertions.assertEquals; +import static com.mbed.coap.utils.CoapRequestBuilderFilter.REQUEST_BUILDER_FILTER; import static org.junit.jupiter.api.Assertions.assertTrue; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; @@ -34,7 +35,7 @@ class ObserveRequestFilterTest { private HashMapObservationsStore obsMap = new HashMapObservationsStore(); private ObserveRequestFilter filter = new ObserveRequestFilter(obsMap::add); - private Service service = filter.then(req -> ok(req.getToken()).toFuture()); + private Service service = REQUEST_BUILDER_FILTER.andThen(filter).then(req -> ok(req.getToken()).toFuture()); @Test void shouldAddTokenForObservationRequest() { @@ -59,7 +60,7 @@ void shouldNotChangeTokenForNonObservationRequest() { @Test void shouldAddObservationRelationForSuccessfulObservationResponse() { - service = filter.then(req -> ok("ok").observe(12).toFuture()); + service = REQUEST_BUILDER_FILTER.andThen(filter).then(req -> ok("ok").observe(12).toFuture()); CompletableFuture resp = service.apply(observe("/obs")); @@ -69,7 +70,7 @@ void shouldAddObservationRelationForSuccessfulObservationResponse() { @Test void shouldNotAddObservationRelationForFailedObservationResponse() { - service = filter.then(req -> ok("ok").toFuture()); + service = REQUEST_BUILDER_FILTER.andThen(filter).then(req -> ok("ok").toFuture()); CompletableFuture resp = service.apply(observe("/obs")); diff --git a/coap-core/src/test/java/com/mbed/coap/server/RescueFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/RescueFilterTest.java index 3e55fa68..4af1a181 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/RescueFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/RescueFilterTest.java @@ -15,18 +15,21 @@ */ package com.mbed.coap.server; -import static com.mbed.coap.packet.CoapRequest.*; -import static com.mbed.coap.utils.FutureHelpers.*; -import static org.junit.jupiter.api.Assertions.*; +import static com.mbed.coap.packet.CoapRequest.get; +import static com.mbed.coap.utils.CoapRequestBuilderFilter.REQUEST_BUILDER_FILTER; +import static com.mbed.coap.utils.FutureHelpers.failedFuture; +import static org.junit.jupiter.api.Assertions.assertEquals; import com.mbed.coap.exception.CoapCodeException; +import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Code; +import com.mbed.coap.utils.Filter; import java.util.concurrent.CompletableFuture; import org.junit.jupiter.api.Test; class RescueFilterTest { - private final RescueFilter filter = new RescueFilter(); + private final Filter filter = REQUEST_BUILDER_FILTER.andThen(new RescueFilter()); @Test void shouldConvertCoapCodeExceptionToResponse() { diff --git a/coap-core/src/test/java/com/mbed/coap/server/RouterServiceTest.java b/coap-core/src/test/java/com/mbed/coap/server/RouterServiceTest.java index 19403040..c44838e7 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/RouterServiceTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/RouterServiceTest.java @@ -15,7 +15,9 @@ */ package com.mbed.coap.server; +import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.packet.CoapResponse.ok; +import static com.mbed.coap.utils.CoapRequestBuilderFilter.REQUEST_BUILDER_FILTER; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; @@ -30,43 +32,43 @@ class RouterServiceTest { @Test public void shouldBuildSimpleService() throws ExecutionException, InterruptedException { - Service svc = RouterService.builder() + Service svc = REQUEST_BUILDER_FILTER.then(RouterService.builder() .get("/test1", simpleHandler) .post("/test1", simpleHandler) .get("/test2/*", simpleHandler) .get("/test3", simpleHandler) - .build(); + .build()); assertEquals("GET /test1", svc.apply(CoapRequest.get("/test1")).get().getPayloadString()); assertEquals("POST /test1", svc.apply(CoapRequest.post("/test1")).get().getPayloadString()); - assertEquals("GET /test2/prefixed-route", svc.apply(CoapRequest.get("/test2/prefixed-route")).get().getPayloadString()); - assertEquals(Code.C404_NOT_FOUND, svc.apply(CoapRequest.get("/test3/not-prefixed-route")).get().getCode()); + assertEquals("GET /test2/prefixed-route", svc.apply(get("/test2/prefixed-route")).get().getPayloadString()); + assertEquals(Code.C404_NOT_FOUND, svc.apply(get("/test3/not-prefixed-route")).get().getCode()); } @Test public void shouldFilterRoutes() throws ExecutionException, InterruptedException { - Service svc = RouterService.builder() + Service svc = REQUEST_BUILDER_FILTER.then(RouterService.builder() .get("/test3", simpleHandler) .filter((CoapRequest req, Service nextSvc) -> ok("42").toFuture()) .get("/test1", simpleHandler) .post("/test1", simpleHandler) .get("/test2/*", simpleHandler) - .build(); + .build()); - assertEquals("42", svc.apply(CoapRequest.get("/test1")).get().getPayloadString()); + assertEquals("42", svc.apply(get("/test1")).get().getPayloadString()); assertEquals("42", svc.apply(CoapRequest.post("/test1")).get().getPayloadString()); - assertEquals("42", svc.apply(CoapRequest.get("/test2/prefixed-route")).get().getPayloadString()); - assertEquals("GET /test3", svc.apply(CoapRequest.get("/test3")).get().getPayloadString()); - assertEquals(Code.C404_NOT_FOUND, svc.apply(CoapRequest.get("/test4")).get().getCode()); + assertEquals("42", svc.apply(get("/test2/prefixed-route")).get().getPayloadString()); + assertEquals("GET /test3", svc.apply(get("/test3")).get().getPayloadString()); + assertEquals(Code.C404_NOT_FOUND, svc.apply(get("/test4")).get().getCode()); } @Test public void shouldChangeDefaultHandler() throws ExecutionException, InterruptedException { - Service svc = RouterService.builder() + Service svc = REQUEST_BUILDER_FILTER.then(RouterService.builder() .defaultHandler((CoapRequest r) -> ok("OK").toFuture()) - .build(); + .build()); - assertEquals(Code.C205_CONTENT, svc.apply(CoapRequest.get("/test3")).get().getCode()); + assertEquals(Code.C205_CONTENT, svc.apply(get("/test3")).get().getCode()); } @Test @@ -77,10 +79,10 @@ public void shouldMergeRoutes() throws ExecutionException, InterruptedException .get("/test2", simpleHandler) .mergeRoutes(builder1); - Service svc = builder2.build(); + Service svc = REQUEST_BUILDER_FILTER.then(builder2.build()); - assertEquals(Code.C205_CONTENT, svc.apply(CoapRequest.get("/test1")).get().getCode()); - assertEquals(Code.C205_CONTENT, svc.apply(CoapRequest.get("/test2")).get().getCode()); + assertEquals(Code.C205_CONTENT, svc.apply(get("/test1")).get().getCode()); + assertEquals(Code.C205_CONTENT, svc.apply(get("/test2")).get().getCode()); } } diff --git a/coap-core/src/test/java/com/mbed/coap/server/RoutingServiceTest.java b/coap-core/src/test/java/com/mbed/coap/server/RoutingServiceTest.java index 47162450..bab07ae7 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/RoutingServiceTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/RoutingServiceTest.java @@ -25,6 +25,7 @@ import static com.mbed.coap.packet.MediaTypes.CT_APPLICATION_JSON; import static com.mbed.coap.packet.MediaTypes.CT_TEXT_PLAIN; import static com.mbed.coap.utils.Assertions.assertEquals; +import static com.mbed.coap.utils.CoapRequestBuilderFilter.REQUEST_BUILDER_FILTER; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mbed.coap.packet.CoapRequest; @@ -39,7 +40,7 @@ public class RoutingServiceTest { - private Service routeService = RouterService.builder() + private Service routeService = REQUEST_BUILDER_FILTER.then(RouterService.builder() .get("/test/1", req -> CoapResponse.ok("Test1", CT_TEXT_PLAIN).toFuture() ) @@ -67,7 +68,7 @@ public class RoutingServiceTest { .any("/test3/*", req -> CoapResponse.ok("Reply to " + req.getMethod()).toFuture() ) - .build(); + .build()); @Test public void shouldRouteWithExactUriPath() throws ExecutionException, InterruptedException { diff --git a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseCallbackTest.java b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseCallbackTest.java index 78f25241..1ae933d3 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseCallbackTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/block/BlockWiseCallbackTest.java @@ -347,7 +347,7 @@ public void should_fail_when_too_large_payload() throws CoapException { ); } - private void assertSent(CoapRequest expected) { + private void assertSent(CoapRequest.Builder expected) { assertFalse(response.isDone()); assertNotNull(lastReq); lastReq = null; diff --git a/coap-core/src/test/java/com/mbed/coap/server/filter/EtagGeneratorFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/filter/EtagGeneratorFilterTest.java index 86bbab27..f99c6c7a 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/filter/EtagGeneratorFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/filter/EtagGeneratorFilterTest.java @@ -15,6 +15,7 @@ */ package com.mbed.coap.server.filter; +import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Opaque.ofBytes; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -31,13 +32,13 @@ class EtagGeneratorFilterTest { void shouldAddEtagToResponse() { Service service = filter.then(req -> ok("ok").toFuture()); - assertEquals(ofBytes(1, 2), service.apply(CoapRequest.get("/test")).join().options().getEtag()); + assertEquals(ofBytes(1, 2), service.apply(get("/test").build()).join().options().getEtag()); } @Test void shouldNotChangeEtagToResponseWhenExists() { Service service = filter.then(req -> ok("ok").etag(ofBytes(99)).toFuture()); - assertEquals(ofBytes(99), service.apply(CoapRequest.get("/test")).join().options().getEtag()); + assertEquals(ofBytes(99), service.apply(get("/test").build()).join().options().getEtag()); } } diff --git a/coap-core/src/test/java/com/mbed/coap/server/filter/EtagValidatorFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/filter/EtagValidatorFilterTest.java index 42870e68..6c7f68ad 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/filter/EtagValidatorFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/filter/EtagValidatorFilterTest.java @@ -21,10 +21,10 @@ import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.packet.Opaque.ofBytes; import static com.mbed.coap.utils.Assertions.assertEquals; +import static com.mbed.coap.utils.CoapRequestBuilderFilter.REQUEST_BUILDER_FILTER; import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; import com.mbed.coap.packet.Code; -import com.mbed.coap.packet.Opaque; import com.mbed.coap.utils.Filter; import com.mbed.coap.utils.Service; import java.util.concurrent.CompletableFuture; @@ -34,7 +34,7 @@ class EtagValidatorFilterTest { private final Filter.SimpleFilter filter = new EtagValidatorFilter(); private final CoapResponse.Builder resource = ok("OK").etag(ofBytes(100)).maxAge(100); - private final Service service = filter.then(__ -> resource.toFuture()); + private final Service service = REQUEST_BUILDER_FILTER.andThen(filter).then(__ -> resource.toFuture()); @Test void shouldPassResponseWhenMissingEtagInRequest() { @@ -53,7 +53,7 @@ void shouldReplyValidWhenRequestWithSameEtag() { @Test void shouldReplyValidWhenRequestWithSameOneOfEtags() { CompletableFuture resp = service.apply( - get("/9").options(o -> o.etag(new Opaque[]{ofBytes(200), ofBytes(100)})) + get("/9").etag(ofBytes(200), ofBytes(100)) ); assertEquals(coapResponse(Code.C203_VALID).etag(ofBytes(100)).maxAge(100), resp.join()); diff --git a/coap-core/src/test/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilterTest.java index 00d25cd8..fc4fd541 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/filter/MaxAllowedPayloadFilterTest.java @@ -22,6 +22,7 @@ import static com.mbed.coap.packet.Code.C413_REQUEST_ENTITY_TOO_LARGE; import static com.mbed.coap.utils.Assertions.assertEquals; import static com.mbed.coap.utils.Bytes.opaqueOfSize; +import static com.mbed.coap.utils.CoapRequestBuilderFilter.REQUEST_BUILDER_FILTER; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mbed.coap.packet.CoapRequest; @@ -31,7 +32,7 @@ class MaxAllowedPayloadFilterTest { - private final Service service = new MaxAllowedPayloadFilter(50, "too much") + private final Service service = REQUEST_BUILDER_FILTER.andThen(new MaxAllowedPayloadFilter(50, "too much")) .then(coapRequest -> completedFuture(of(C201_CREATED))); @Test diff --git a/coap-core/src/test/java/com/mbed/coap/server/filter/TokenGeneratorFilterTest.java b/coap-core/src/test/java/com/mbed/coap/server/filter/TokenGeneratorFilterTest.java index f9b6db66..0d57f891 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/filter/TokenGeneratorFilterTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/filter/TokenGeneratorFilterTest.java @@ -39,7 +39,7 @@ void shouldSetTokenToRequest() { return ok("ok").toFuture(); }); - assertEquals(ok("ok"), service.apply(get("/test")).join()); + assertEquals(ok("ok"), service.apply(get("/test").build()).join()); } @Test @@ -49,7 +49,7 @@ void shouldNotSetTokenToWhenAlreadyExists() { return ok("ok").toFuture(); }); - assertEquals(ok("ok"), service.apply(get("/test").token(123)).join()); + assertEquals(ok("ok"), service.apply(get("/test").token(123).build()).join()); } @Test diff --git a/coap-core/src/test/java/com/mbed/coap/server/observe/NotificationsReceiverTest.java b/coap-core/src/test/java/com/mbed/coap/server/observe/NotificationsReceiverTest.java index 6cc25d3a..aab7e0af 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/observe/NotificationsReceiverTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/observe/NotificationsReceiverTest.java @@ -46,7 +46,7 @@ void setUp() { @Test void shouldNotifyAndRetrieveBlocks() throws InterruptedException { - given(service.apply(get("/obs").block2Res(1, S_16, false))).willReturn(ok("bbb").toFuture()); + given(service.apply(get("/obs").block2Res(1, S_16, false).build())).willReturn(ok("bbb").toFuture()); SeparateResponse obs = ok("aaaaaaaaaaaaaaaa").observe(2).block2Res(0, S_16, true).toSeparate(of("100"), null); // when @@ -58,7 +58,7 @@ void shouldNotifyAndRetrieveBlocks() throws InterruptedException { @Test void shouldFailWhenUnexpectedBlockRetrieving() { - given(service.apply(get("/obs").block2Res(1, S_16, false))).willReturn(notFound().toFuture()); + given(service.apply(get("/obs").block2Res(1, S_16, false).build())).willReturn(notFound().toFuture()); SeparateResponse obs = ok("aaaaaaaaaaaaaaaa").observe(2).block2Res(0, S_16, true).toSeparate(of("100"), null); // when diff --git a/coap-core/src/test/java/com/mbed/coap/server/observe/ObserversManagerTest.java b/coap-core/src/test/java/com/mbed/coap/server/observe/ObserversManagerTest.java index c34d8714..9d1e977b 100644 --- a/coap-core/src/test/java/com/mbed/coap/server/observe/ObserversManagerTest.java +++ b/coap-core/src/test/java/com/mbed/coap/server/observe/ObserversManagerTest.java @@ -87,7 +87,7 @@ public void doNotCreateObservationRelationWhenMissingObs() throws ExecutionExcep @Test public void doNotCreateObservationRelationWhenObsIsNot0() throws ExecutionException, InterruptedException { // when - assertNull(obsMgr.subscribe(get("/test").token(13).observe(10).from(PEER_1), ok("OK!")).options().getObserve()); + assertNull(obsMgr.subscribe(get("/test").token(13).options(o -> o.observe(10)).from(PEER_1), ok("OK!")).options().getObserve()); // then assertEquals(0, obsMgr.size()); diff --git a/coap-core/src/test/java/protocolTests/ClientServerWithBlocksTest.java b/coap-core/src/test/java/protocolTests/ClientServerWithBlocksTest.java index 6ee332f5..b72e6fce 100644 --- a/coap-core/src/test/java/protocolTests/ClientServerWithBlocksTest.java +++ b/coap-core/src/test/java/protocolTests/ClientServerWithBlocksTest.java @@ -32,7 +32,6 @@ import com.mbed.coap.client.CoapClient; import com.mbed.coap.exception.CoapBlockException; import com.mbed.coap.exception.CoapException; -import com.mbed.coap.packet.BlockOption; import com.mbed.coap.packet.BlockSize; import com.mbed.coap.packet.CoapPacket; import com.mbed.coap.packet.CoapRequest; @@ -231,7 +230,7 @@ public void incompleteBlockRequest() throws Exception { CoapRequest request = put("/chang-res") .payload(body) - .options(o -> o.block1Req(new BlockOption(1, BlockSize.S_128, true))) + .options(o -> o.block1Req(1, BlockSize.S_128, true)) .toLocal(SERVER_PORT); CoapResponse resp = cnn.clientService().apply(request).join(); diff --git a/coap-core/src/testFixtures/java/com/mbed/coap/utils/Assertions.java b/coap-core/src/testFixtures/java/com/mbed/coap/utils/Assertions.java index b53b9d66..0b61f1ac 100644 --- a/coap-core/src/testFixtures/java/com/mbed/coap/utils/Assertions.java +++ b/coap-core/src/testFixtures/java/com/mbed/coap/utils/Assertions.java @@ -15,6 +15,7 @@ */ package com.mbed.coap.utils; +import com.mbed.coap.packet.CoapRequest; import com.mbed.coap.packet.CoapResponse; public class Assertions { @@ -23,4 +24,8 @@ public static void assertEquals(CoapResponse.Builder expected, CoapResponse actu org.junit.jupiter.api.Assertions.assertEquals(expected.build(), actual); } + public static void assertEquals(CoapRequest.Builder expected, CoapRequest actual) { + org.junit.jupiter.api.Assertions.assertEquals(expected.build(), actual); + } + } diff --git a/coap-core/src/testFixtures/java/com/mbed/coap/utils/CoapRequestBuilderFilter.java b/coap-core/src/testFixtures/java/com/mbed/coap/utils/CoapRequestBuilderFilter.java new file mode 100644 index 00000000..74dd4d3e --- /dev/null +++ b/coap-core/src/testFixtures/java/com/mbed/coap/utils/CoapRequestBuilderFilter.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mbed.coap.utils; + +import com.mbed.coap.packet.CoapRequest; +import com.mbed.coap.packet.CoapResponse; + +public class CoapRequestBuilderFilter { + + public static final Filter REQUEST_BUILDER_FILTER = (request, service) -> { + return service.apply(request.build()); + }; + +} diff --git a/coap-core/src/testFixtures/java/protocolTests/IntegrationTestBase.java b/coap-core/src/testFixtures/java/protocolTests/IntegrationTestBase.java index 135bade8..98aca1ce 100644 --- a/coap-core/src/testFixtures/java/protocolTests/IntegrationTestBase.java +++ b/coap-core/src/testFixtures/java/protocolTests/IntegrationTestBase.java @@ -150,14 +150,14 @@ public void resourceManipulationTest() throws CoapException, IOException { @Test public void requestWithAccept() throws Exception { - CoapRequest request = get("/test2").accept(MediaTypes.CT_APPLICATION_JSON); + CoapRequest.Builder request = get("/test2").accept(MediaTypes.CT_APPLICATION_JSON); assertEquals(Code.C406_NOT_ACCEPTABLE, client.sendSync(request).getCode()); } @Test public void simpleRequestWithCustomHeader() throws Exception { - CoapRequest request = get("/test/1") + CoapRequest.Builder request = get("/test/1") .options(o -> o.custom(74, Opaque.variableUInt(0x010203L))); assertEquals("Dziala", client.sendSync(request).getPayloadString()); @@ -165,7 +165,7 @@ public void simpleRequestWithCustomHeader() throws Exception { @Test public void simpleRequestWithCriticalCustomHeader() throws Exception { - CoapRequest request = get("/test/1") + CoapRequest.Builder request = get("/test/1") .options(o -> o.custom(71, Opaque.variableUInt(0x010203L))); assertEquals(Code.C402_BAD_OPTION, client.sendSync(request).getCode()); @@ -173,7 +173,7 @@ public void simpleRequestWithCriticalCustomHeader() throws Exception { @Test public void simpleRequestWithNonCriticalCustomHeader() throws Exception { - CoapRequest request = get("/test/1") + CoapRequest.Builder request = get("/test/1") .options(o -> o.custom(72, Opaque.ofBytes(1, 2, 3))); assertEquals("Dziala", client.sendSync(request).getPayloadString()); diff --git a/coap-metrics/src/test/java/org/opencoap/coap/metrics/micrometer/MicrometerMetricsFilterTest.java b/coap-metrics/src/test/java/org/opencoap/coap/metrics/micrometer/MicrometerMetricsFilterTest.java index a19e846b..ab80c16a 100644 --- a/coap-metrics/src/test/java/org/opencoap/coap/metrics/micrometer/MicrometerMetricsFilterTest.java +++ b/coap-metrics/src/test/java/org/opencoap/coap/metrics/micrometer/MicrometerMetricsFilterTest.java @@ -18,7 +18,9 @@ import static com.mbed.coap.packet.CoapRequest.get; import static com.mbed.coap.packet.CoapResponse.ok; import static com.mbed.coap.utils.Assertions.assertEquals; +import static com.mbed.coap.utils.CoapRequestBuilderFilter.REQUEST_BUILDER_FILTER; import static com.mbed.coap.utils.FutureHelpers.failedFuture; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -35,8 +37,8 @@ class MicrometerMetricsFilterTest { private final MeterRegistry registry = new SimpleMeterRegistry(); private final MicrometerMetricsFilter filter = MicrometerMetricsFilter.builder().registry(registry).build(); - private final Service okService = filter.then(__ -> ok("OK").toFuture()); - private final Service failingService = filter.then(__ -> failedFuture(new Exception("error message"))); + private final Service okService = REQUEST_BUILDER_FILTER.andThen(filter).then(__ -> ok("OK").toFuture()); + private final Service failingService = REQUEST_BUILDER_FILTER.andThen(filter).then(__ -> failedFuture(new Exception("error message"))); @BeforeEach public void beforeEach() { @@ -107,7 +109,7 @@ public void shouldUseDefinedRouteForAllMeteredRequests() { .registry(registry) .build(); - Service svc = filterWithRoute.then(__ -> ok("OK").toFuture()); + Service svc = REQUEST_BUILDER_FILTER.andThen(filterWithRoute).then(__ -> ok("OK").toFuture()); svc.apply(get("/test/1")).join(); svc.apply(get("/test/2")).join(); svc.apply(get("/hello")).join();