Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update logs in WebSub Module #280

Merged
merged 16 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
if: failure()
with:
name: Ballerina Internal Log
path: websubhub-ballerina/ballerina-internal.log
path: websub-ballerina/ballerina-internal.log
if-no-files-found: ignore
- name: Generate Codecov Report
if: github.event_name == 'pull_request'
Expand Down
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Multipart content retrieval on event-notification.
- Subscriber resubscription event.
- [Log error when return from the remote method leads to an error](https://github.com/ballerina-platform/ballerina-standard-library/issues/1450)
- [WebSubHub Compiler Plugin does not allow additional methods inside service declaration](https://github.com/ballerina-platform/ballerina-standard-library/issues/1417)

## [1.2.0-beta.1] - 2021-05-06

Expand Down
2 changes: 1 addition & 1 deletion websub-ballerina/errors.bal
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# Represents a webSub distinct error.
public type Error distinct error<CommonResponse>;

# Represents a websubhub service execution error.
# Represents a websub service execution error.
public type ServiceExecutionError distinct error<CommonResponse>;

# Represents a listener errors.
Expand Down
5 changes: 3 additions & 2 deletions websub-ballerina/sub_listener.bal
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ public class Listener {
if serviceConfig is SubscriberServiceConfiguration {
error? result = initiateSubscription(serviceConfig, <string>callback);
if result is error {
string errorMsg = string`Subscription initiation failed due to [${result.message()}]`;
string errorDetails = result.message();
string errorMsg = string`Subscription initiation failed due to: ${errorDetails}`;
return error SubscriptionInitiationError(errorMsg);
}
}
Expand Down Expand Up @@ -322,7 +323,7 @@ isolated function initiateSubscription(SubscriberServiceConfiguration serviceCon
var response = subscriberClientEp->subscribe(request);
if response is SubscriptionChangeResponse {
string subscriptionSuccessMsg = string`Subscription Request successfully sent to Hub[${response.hub}], for Topic[${response.topic}], with Callback [${callbackUrl}]`;
log:printInfo(string`${subscriptionSuccessMsg}. Awaiting intent verification.`);
log:printDebug(string`${subscriptionSuccessMsg}`);
} else {
return response;
}
Expand Down
8 changes: 2 additions & 6 deletions websub-ballerina/subscriber_client.bal
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import ballerina/url;
import ballerina/http;
import ballerina/log;
import ballerina/mime;

# The HTTP based client for WebSub subscription and unsubscription.
Expand All @@ -42,7 +41,7 @@ public client class SubscriptionClient {

# Sends a subscription request to the provided `hub`.
# ```ballerina
# websub:SubscriptionChangeResponse response = check websubHubClientEP->subscribe(subscriptionRequest);
# websub:SubscriptionChangeResponse response = check subscriberClientEp->subscribe(subscriptionRequest);
# ```
#
# + subscriptionRequest - The request payload containing the subscription details
Expand All @@ -59,7 +58,7 @@ public client class SubscriptionClient {

# Sends an unsubscription request to a WebSub Hub.
# ```ballerina
# websub:SubscriptionChangeResponse response = check websubHubClientEP->unsubscribe(subscriptionRequest);
# websub:SubscriptionChangeResponse response = check subscriberClientEp->unsubscribe(subscriptionRequest);
# ```
# + unsubscriptionRequest - The request payload containing the unsubscription details
# + return - The `websub:SubscriptionChangeResponse` indicating that the unsubscription initiation was successful
Expand Down Expand Up @@ -151,9 +150,6 @@ isolated function processHubResponse(@untainted string hub, @untainted string mo
}
return error SubscriptionInitiationError(errorMessage);
} else {
if responseStatusCode != http:STATUS_ACCEPTED {
log:printWarn(string`Subscription request considered successful for non 202 status code: ${responseStatusCode.toString()}`);
}
SubscriptionChangeResponse subscriptionChangeResponse = {hub:hub, topic:topic, response:hubResponse};
return subscriptionChangeResponse;
}
Expand Down
14 changes: 6 additions & 8 deletions websub-ballerina/tests/subscriber_with_error_return_types.bal
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,16 @@ listener Listener errorReturnsSubscriberListener = new (9099);

var subscriberWithErrorReturns = @SubscriberServiceConfig { target: "http://0.0.0.0:9191/common/discovery", leaseSeconds: 36000 }
service object {
isolated remote function onSubscriptionValidationDenied(SubscriptionDeniedError msg) returns Acknowledgement|error? {
return error Error("Error occured while processing request");
isolated remote function onSubscriptionValidationDenied(SubscriptionDeniedError msg) returns error? {
return error ("Error occured while processing request");
}

isolated remote function onSubscriptionVerification(SubscriptionVerification msg)
returns SubscriptionVerificationSuccess|SubscriptionVerificationError|error {
return error Error("Error occured while processing request");
isolated remote function onSubscriptionVerification(SubscriptionVerification msg) returns error {
return error ("Error occured while processing request");
}

isolated remote function onEventNotification(ContentDistributionMessage event)
returns Acknowledgement|SubscriptionDeletedError|error? {
return error Error("Error occured while processing request");
isolated remote function onEventNotification(ContentDistributionMessage event) returns error? {
return error ("Error occured while processing request");
}
};

Expand Down
49 changes: 49 additions & 0 deletions websub-ballerina/tests/subscription_initiation_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import ballerina/test;
import ballerina/http;
import ballerina/log;

const string CALLBACK = "https://sample.subscriber.com/subscriber";
const string DISCOVERY_SUCCESS_URL = "http://127.0.0.1:9192/common/discovery";
Expand Down Expand Up @@ -68,6 +69,11 @@ isolated function testSubscriptionInitiationFailureWithDiscoveryUrl() returns @t
SubscriberServiceConfiguration config = getServiceConfig(DISCOVERY_FAILURE_URL);
var response = initiateSubscription(config, CALLBACK);
test:assertTrue(response is ResourceDiscoveryFailedError);
if response is error {
string errorDetails = response.message();
string errorMsg = string`Subscription initiation failed due to: ${errorDetails}`;
log:printError(errorMsg);
}
}

@test:Config {
Expand All @@ -77,5 +83,48 @@ isolated function testSubscriptionInitiationFailureWithHubAndTopic() returns @ta
SubscriberServiceConfiguration config = getServiceConfig([ HUB_FAILURE_URL, COMMON_TOPIC ]);
var response = initiateSubscription(config, CALLBACK);
test:assertTrue(response is SubscriptionInitiationError);
if response is error {
string errorDetails = response.message();
string errorMsg = string`Subscription initiation failed due to: ${errorDetails}`;
log:printError(errorMsg);
}
}

final var websubServiceObj = service object {
isolated remote function onEventNotification(ContentDistributionMessage event)
returns Acknowledgement {
return ACKNOWLEDGEMENT;
}
};

listener Listener ls = new (9100);

@test:Config {
groups: ["subscriptionInitiation"]
}
function testSubInitFailedWithListenerForResourceDiscoveryFailure() returns @tainted error? {
var res = ls.attachWithConfig(websubServiceObj, getServiceConfig(DISCOVERY_FAILURE_URL), "sub");
test:assertFalse(res is error);
var startDetails = ls.'start();
test:assertTrue(startDetails is error);
if startDetails is error {
string expected = "Subscription initiation failed due to: Link header unavailable in discovery response";
test:assertEquals(startDetails.message(), expected);
}
check ls.gracefulStop();
}

@test:Config {
groups: ["subscriptionInitiation"]
}
function testSubInitFailedWithListenerForSubFailure() returns @tainted error? {
var res = ls.attachWithConfig(websubServiceObj, getServiceConfig([ HUB_FAILURE_URL, COMMON_TOPIC ]), "sub");
test:assertFalse(res is error);
var startDetails = ls.'start();
test:assertTrue(startDetails is error);
if startDetails is error {
string expected = "Subscription initiation failed due to: Error in request: Mode[subscribe] at Hub[http://127.0.0.1:9192/common/failed] - no matching resource found for path : /common/failed , method : POST";
test:assertEquals(startDetails.message(), expected);
}
check ls.gracefulStop();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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 io.ballerina.stdlib.websub;

/**
* {@code Constants} contains the public constants to be used.
*/
public interface Constants {
String PACKAGE_ORG = "ballerina";
String PACKAGE_NAME = "websub";

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove empty line ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack. Will fix this with next PR.

String SERVICE_OBJECT = "WEBSUB_SERVICE_OBJECT";
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
import io.ballerina.runtime.api.Environment;
import io.ballerina.runtime.api.Future;
import io.ballerina.runtime.api.Module;
import io.ballerina.runtime.api.async.Callback;
import io.ballerina.runtime.api.async.StrandMetadata;
import io.ballerina.runtime.api.creators.ErrorCreator;
import io.ballerina.runtime.api.creators.ValueCreator;
import io.ballerina.runtime.api.types.MethodType;
import io.ballerina.runtime.api.utils.StringUtils;
Expand All @@ -35,14 +33,12 @@

import java.util.ArrayList;

import static io.ballerina.runtime.api.utils.StringUtils.fromString;
import static io.ballerina.stdlib.websub.Constants.SERVICE_OBJECT;

/**
* {@code NativeHttpToWebsubAdaptor} is a wrapper object used for service method execution.
*/
public class NativeHttpToWebsubAdaptor {
public static final String SERVICE_OBJECT = "WEBSUB_SERVICE_OBJECT";

public static void externInit(BObject adaptor, BObject service) {
adaptor.addNativeData(SERVICE_OBJECT, service);
}
Expand Down Expand Up @@ -83,20 +79,8 @@ private static Object invokeRemoteFunction(Environment env, BObject bSubscriberS
StrandMetadata metadata = new StrandMetadata(module.getOrg(), module.getName(), module.getVersion(),
parentFunctionName);
Object[] args = new Object[]{message, true};
env.getRuntime().invokeMethodAsync(bSubscriberService, remoteFunctionName, null, metadata, new Callback() {
@Override
public void notifySuccess(Object result) {
balFuture.complete(result);
}

@Override
public void notifyFailure(BError bError) {
BString errorMessage = fromString("service method invocation failed: " + bError.getErrorMessage());
BError invocationError = ErrorCreator.createError(module, "ServiceExecutionError",
errorMessage, bError, null);
balFuture.complete(invocationError);
}
}, args);
env.getRuntime().invokeMethodAsync(bSubscriberService, remoteFunctionName, null, metadata,
new SubscriberCallback(balFuture, module), args);
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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 io.ballerina.stdlib.websub;

import io.ballerina.runtime.api.Future;
import io.ballerina.runtime.api.Module;
import io.ballerina.runtime.api.async.Callback;
import io.ballerina.runtime.api.creators.ErrorCreator;
import io.ballerina.runtime.api.types.Type;
import io.ballerina.runtime.api.values.BError;
import io.ballerina.runtime.api.values.BString;

import static io.ballerina.runtime.api.utils.StringUtils.fromString;

/**
* {@code SubscriberCallback} used to handle the websub remote method invocation results.
*/
public class SubscriberCallback implements Callback {
private final Future future;
private final Module module;

public SubscriberCallback(Future future, Module module) {
this.future = future;
this.module = module;
}

@Override
public void notifySuccess(Object result) {
if (result instanceof BError) {
BError error = (BError) result;
if (!isModuleDefinedError(error)) {
error.printStackTrace();
}
}

future.complete(result);
}

@Override
public void notifyFailure(BError bError) {
bError.printStackTrace();
BString errorMessage = fromString("service method invocation failed: " + bError.getErrorMessage());
BError invocationError = ErrorCreator.createError(module, "ServiceExecutionError",
errorMessage, bError, null);
future.complete(invocationError);
}

private boolean isModuleDefinedError(BError error) {
Type errorType = error.getType();
Module packageDetails = errorType.getPackage();
String orgName = packageDetails.getOrg();
String packageName = packageDetails.getName();
return Constants.PACKAGE_ORG.equals(orgName) && Constants.PACKAGE_NAME.equals(packageName);
}
}