I am working on implementing WebSocket integration tests. I cannot get the mock user to be passed to the client.
#WithMockUser(value = "user", roles = "USER")
void test() throws ExecutionException, InterruptedException, TimeoutException {
webSocketStompClient = new WebSocketStompClient(
new SockJsClient(List.of(new WebSocketTransport(new StandardWebSocketClient())))
);
StompSession session = webSocketStompClient
.connect(String.format("ws://localhost:%d/ws", port),
new StompSessionHandlerAdapter() {
}
)
.get(1, SECONDS);
}
Unfortunately, I receive the following error:
TopicInterceptorIT > test() FAILED
java.util.concurrent.ExecutionException at TopicInterceptorIT.java:57
Caused by: org.springframework.messaging.simp.stomp.ConnectionLostException at DefaultStompSession.java:518
2022-01-17 12:04:19.415 WARN [,,,] 44518 --- [ XNIO-1 I/O-9] w.s.h.ExceptionWebSocketHandlerDecorator : Unhandled exception after connection closed for ExceptionWebSocketHandlerDecorator [delegate=LoggingWebSocketHandlerDecorator [delegate=WebSocketMsgEnhancer [delegate=SubProtocolWebSocketHandler[StompSubProtocolHandler[v10.stomp, v11.stomp, v12.stomp]]]]]
org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied
Do I have to manually create the access token and inject it into the request headers? Or is there an approach similar to the #WithMockUser over MockMvc familiar when testing REST endpoints?
Related
(for context, please see my previous question)
Still struggling to get a file from an SFTP server, persist it's content to a database and remove that file afterwards, if it was persisted without errors. I just can get the handling of handlers, gateways and flows right.
I need guidanc, please
What I have:
#Configuration
#EnableIntegration
class Sftp2DB {
#Bean
#InboundChannelAdapter(channel = "transform")
public MessageSource<InputStream> source() {
return Sftp
.inboundStreamingAdapter(template(this.sessionFactory))
.remoteDirectory("inbound")
.get();
}
#Transformer(inputChannel="transform", outputChannel = "persist")
public Message<MyEntity> transform(final Message<InputStream> in) throws IOException {
var entity = new MyEntity();
entity.setContent(in.getPayload().readAllBytes());
entity.setFilename(in.getHeaders().get(FileHeaders.FILENAME, String.class));
return MessageBuilder.withPayload(entity).build();
}
#ServiceActivator(inputChannel = "persist", outputChannel = "remove")
public JpaOutboundGateway persist() {
return Jpa
.updatingGateway(this.entityManager)
.entityClass(MyEntity.class)
.persistMode(PersistMode.PERSIST)
.get();
}
#ServiceActivator(inputChannel = "remove")
public AbstractRemoteFileOutboundGateway<LsEntry> remove() {
return Sftp
.outboundGateway(
this.sessionFactory,
"rm",
String.format("header['%s'] + '/' + header['%s']", FileHeaders.REMOTE_DIRECTORY, FileHeaders.REMOTE_FILE)
)
.get();
}
}
What I get:
2022-11-24 12:50:13.815 ERROR 948 --- [ scheduling-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessageHandlingException: error occurred in message handler [ServiceActivator for [org.springframework.integration.handler.MethodInvokingMessageProcessor#3be14a03] (Sftp2DB.remove.serviceActivator)]; nested exception is org.springframework.messaging.core.DestinationResolutionException: no output-channel or replyChannel header available, failedMessage=GenericMessage [payload=org.springframework.integration.jpa.outbound.JpaOutboundGateway#6a0e79fb, headers={id=788f63b5-ad62-de6b-bbb1-ecde94d23576, timestamp=1669290613815}]
There are two types of #ServiceActivator (and #Transformer etc).
POJO methods (like your transformer) and beans that define message handlers.
Your service activators need to be defined as #Bean s (like you did with your inbound channel adapter).
See https://docs.spring.io/spring-integration/docs/current/reference/html/configuration.html#annotations and https://docs.spring.io/spring-integration/docs/current/reference/html/configuration.html#annotations_on_beans
I'm following this example to create a web service secured with signature only: https://github.com/apache/cxf/blob/master/distribution/src/main/release/samples/ws_security/sign_enc/src/main/java/demo/wssec/server/Server.java
This is what my code looks like:
public static void main(String[] args) {
FooService service = new FooService();
String address = "http://localhost:1235/foo";
EndpointImpl endpoint = (EndpointImpl) javax.xml.ws.Endpoint.publish(address, service);
Map<String,Object> inProps = new HashMap<>();
inProps.put(WSHandlerConstants.ACTION, "Signature");
inProps.put(WSHandlerConstants.SIG_PROP_FILE, Server.class.getResource("./server_sign.properties"));
inProps.put("signatureKeyIdentifier", "DirectReference");
inProps.put("encryptionKeyTransportAlgorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
inProps.put("signatureAlgorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
endpoint.getInInterceptors().add(new WSS4JInInterceptor(inProps));}
When I send a soap messge to the server it throws an error:
org.apache.wss4j.common.ext.WSSecurityException: An error was discovered processing the <wsse:Security> header
Also it shows the message
Security processing failed (actions mismatch)
Why does this happen?
I am trying to connect to Binance websocket endpoint using RSocket with Spring, but I am getting the following exception.
java.lang.AssertionError: expectation "consumeNextWith" failed (expected: onNext(); actual: onError(java.nio.channels.ClosedChannelException))
Here is my testing code:
#SpringBootTest
#Slf4j
class RSocketClientIntegrationTest {
private static RSocketRequester requester;
#BeforeAll
public static void setupOnce(#Autowired RSocketRequester.Builder builder) {
// given
requester = builder
.connectWebSocket(URI.create("wss://stream.binance.com:9443/ws"))
.block();
}
#Test
void shouldRetrieveStockPricesFromTheService() {
//when
final Flux<String> aggregatedTradeStream = requester
.route("/bnbbtc#aggTrade")
.retrieveFlux(String.class)
.take(1)
.doOnError(e -> log.error(e.toString()));
// then
StepVerifier.create(aggregatedTradeStream)
.consumeNextWith(response -> {
assertThat(response).isNotNull();
})
.verifyComplete();
}
}
Can I connect straight into a WebSocket endpoint using RSocket or do I have to create a RSocket server that handles the websocket and then from this proxy server I connect to the websocket?
RSocket over WebSocket uses websocket as a transport to carry RSocket payloads. So you can't connect to a raw WebSocket and expect anything to work.
Try testing the above program against an endpoint like
wss://rsocket-demo.herokuapp.com/rsocket
See docs at https://rsocket-demo.herokuapp.com/
I want to mock RestTemplate object which is calling another microservice and receiving configuration for a particular device:
ResponseEntity<ConfigurationResponse> configurationResponse = restTemplate
.getForEntity("http://localhost:8081/configuration/serial/" + dto.getSerNum(), ConfigurationResponse.class);
I am mocking above RestTemplate like:
mockServer.expect(requestTo(
"http://localhost:8081/configuration/serial/" + device.getSerNum()))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess(toJson(
ConfigurationResponse.builder()
.ip("192.168.1.1")
.netMask("255.255.0.0")
.build()),
MediaType.APPLICATION_JSON_UTF8));
but after the test start I am receiving an exception:
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:8081/configuration/serial/XXX-BBB-KKK": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
I am instantiating RestTemplate and MockRestServiceServer like:
class DeviceServiceTest {
private DeviceService deviceService;
private DeviceRepository deviceRepository = mock(DeviceRepository.class);
private RestTemplate restTemplate = new RestTemplate();
private MockRestServiceServermockServer = MockRestServiceServer.createServer(restTemplate);
#BeforeEach
void setUp() {
deviceService = new DeviceService(deviceRepository);
mockServer = MockRestServiceServer.createServer(restTemplate);
restTemplate = new RestTemplate();
}
}
I used below example from link below
how-mock-rest-request
but it did not bring a desirable effect.
I will be grateful for a piece of advice on how to fix my mock to establish a connection in my test.
EDIT
Basing on the topic click I know that I suppose to have the same bean of RestTemplate in service and in the test but honestly I don't know how to make it happened. I am instantiating a RestTemplate object in a method which I am testing.
I need to consume a OAuth2 Rest service with ClientCredential Grant.
I'm using spring security and spring oauth2.
To get the access token i need to call the token uri passing to it a clientId and a password
Basically i need to send a POST with this body
{"clientId":"demo",
"password": "demo_password"
}
and I should get something like that in the response
{
"expiresIn": 3600,
"accessToken": "EF2I5xhL2GU9pAwK",
"statusCode": 200,
"refreshToken": "72BIcYWYhPjuPDGb"
}
I was trying to configure OAuth2RestTemplate in this way
#Configuration
#EnableOAuth2Client
public class RestTemplateConf {
#Value("${ApiClient}")
private String oAuth2ClientId;
#Value("${ApiSecret}")
private String oAuth2ClientSecret;
#Value("${ApiUrl}")
private String accessTokenUri;
#Bean
public OAuth2RestTemplate oAuthRestTemplate() {
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setClientId(oAuth2ClientId);
resourceDetails.setClientSecret(oAuth2ClientSecret);
resourceDetails.setAccessTokenUri(accessTokenUri);
resourceDetails.setTokenName("accessToken");
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, new DefaultOAuth2ClientContext());
return restTemplate;
}
}
but i get always
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is error="access_denied", error_description="Error requesting access token."] with root cause
org.springframework.web.client.HttpServerErrorException: 500 Internal Server Error
If i make a POST call to the tokenUri with POSTMAN, for instance, i get the token correctly...