Skip to content

Commit

Permalink
Add cucumber test for GRPC API interceptor
Browse files Browse the repository at this point in the history
  • Loading branch information
sgayangi committed Oct 11, 2024
1 parent 42d69e4 commit adf0993
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 45 deletions.
10 changes: 0 additions & 10 deletions adapter/internal/oasparser/model/adapter_internal_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"time"

"github.com/google/uuid"
"github.com/sirupsen/logrus"
"github.com/wso2/apk/adapter/config"
"github.com/wso2/apk/adapter/internal/interceptor"
"github.com/wso2/apk/adapter/internal/loggers"
Expand Down Expand Up @@ -1297,15 +1296,6 @@ func (adapterInternalAPI *AdapterInternalAPI) SetInfoGRPCRouteCR(grpcRoute *gwap
Name: string(filter.ExtensionRef.Name),
Namespace: grpcRoute.Namespace,
}.String()]; found {
logrus.Info("filter.ExtensionRef.Kind == constants.KindAPIPolicy")
logrus.Info(apiPolicy.Name)
logrus.Info(apiPolicy.Name)
if apiPolicy.Spec.Default != nil {
logrus.Info(apiPolicy.Spec.Default.RequestInterceptors)
}
if apiPolicy.Spec.Default != nil {
logrus.Info(apiPolicy.Spec.Default.ResponseInterceptors)
}
resourceAPIPolicy = concatAPIPolicies(apiPolicy, &ref)
} else {
return fmt.Errorf(`apipolicy: %s has not been resolved, spec.targetRef.kind should be
Expand Down
30 changes: 0 additions & 30 deletions adapter/internal/operator/controllers/dp/api_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1089,36 +1089,6 @@ func (apiReconciler *APIReconciler) getResolvedBackendsMappingForGRPC(ctx contex
}
}
}

for _, filter := range rule.Filters {
if filter.RequestMirror != nil {
mirrorBackend := filter.RequestMirror.BackendRef
mirrorBackendNamespacedName := types.NamespacedName{
Name: string(mirrorBackend.Name),
Namespace: utils.GetNamespace(mirrorBackend.Namespace, grpcRoute.Namespace),
}
if string(*mirrorBackend.Kind) == constants.KindBackend {
if _, exists := backendMapping[mirrorBackendNamespacedName.String()]; !exists {
resolvedMirrorBackend := utils.GetResolvedBackend(ctx, apiReconciler.client, mirrorBackendNamespacedName, &api)
if resolvedMirrorBackend != nil {
backendMapping[mirrorBackendNamespacedName.String()] = resolvedMirrorBackend
} else {
return nil, fmt.Errorf("unable to find backend %s", mirrorBackendNamespacedName.String())
}
}
} else if string(*mirrorBackend.Kind) == constants.KindService {
var err error
service, err := utils.GetService(ctx, apiReconciler.client, utils.GetNamespace(mirrorBackend.Namespace, grpcRoute.Namespace), string(mirrorBackend.Name))
if err != nil {
return nil, fmt.Errorf("unable to find service %s", mirrorBackendNamespacedName.String())
}
backendMapping[mirrorBackendNamespacedName.String()], err = utils.GetResolvedBackendFromService(service, int(*mirrorBackend.Port))
if err != nil {
return nil, fmt.Errorf("error in getting service information %s", service)
}
}
}
}
}

// Resolve backends in InterceptorServices
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import io.cucumber.java.en.And;

import io.grpc.Status;
import io.grpc.StatusRuntimeException;
Expand Down Expand Up @@ -248,6 +249,18 @@ public void GetStudent(String arg0, int arg1) throws StatusRuntimeException {
}
}

@And("the GRPC response should contain header {string}")
public void GetGRPCMetadata(String arg0) throws StatusRuntimeException {
try {
String header = SimpleGRPCStudentClient.getResponseHeader(arg0);
Assert.assertNotNull(header);
Assert.assertEquals(header, "Interceptor-Response-header-value");
} catch (StatusRuntimeException e) {
sharedContext.setGrpcStatusCode(e.getStatus().getCode().value());
logger.error(e.getMessage() + " Status code: " + e.getStatus().getCode().value());
}
}

@Then("I make grpc request GetStudent default version to {string} with port {int}")
public void GetStudentDefaultVersion(String arg0, int arg1) throws StatusRuntimeException {
try {
Expand Down Expand Up @@ -329,8 +342,9 @@ public void checkEnforcerLogs(DataTable dataTable) throws IOException, Interrupt
}
try {
String logs = api.readNamespacedPodLog(podName, namespace).container("enforcer").sinceSeconds(60).execute();
Assert.assertNotNull(logs, String.format("Could not find any logs in the last 60 seconds. PodName: %s, namespace: %s", podName, namespace));
for(String word : stringsToCheck) {
Assert.assertNotNull(logs, String.format(
"Could not find any logs in the last 60 seconds. PodName: %s, namespace: %s", podName, namespace));
for (String word : stringsToCheck) {
Assert.assertTrue(logs.contains(word), "Expected word '" + word + "' not found in logs");
}
} catch (ApiException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,32 @@

import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall;
import io.grpc.ForwardingClientCall.SimpleForwardingClientCall;
import io.grpc.ForwardingClientCallListener.SimpleForwardingClientCallListener;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.CallOptions;
import io.grpc.ClientCall;
import io.grpc.Channel;
import java.util.Map;

import java.util.Map;

public class GenericClientInterceptor implements ClientInterceptor {

private Map<String, String> headers;
private Metadata responseHeaders;

public GenericClientInterceptor(Map<String, String> headers) {
this.headers = headers;
}

public void setResponseHeaders(Metadata responseHeaders) {
this.responseHeaders = responseHeaders;
}

public Metadata getResponseHeaders() {
return this.responseHeaders;
}

@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
Expand All @@ -31,7 +40,18 @@ public void start(Listener<RespT> responseListener, Metadata headersMetadata) {
headers.forEach((key, value) -> headersMetadata.put(
Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER), value));

super.start(responseListener, headersMetadata);
super.start(new SimpleForwardingClientCallListener<RespT>(responseListener) {
@Override
public void onHeaders(Metadata headers) {
/**
* if you don't need receive header from server,
* you can use {@link io.grpc.stub.MetadataUtils#attachHeaders}
* directly to send header
*/
setResponseHeaders(headers);
super.onHeaders(headers);
}
}, headersMetadata);
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.apache.commons.logging.LogFactory;

import io.grpc.ManagedChannel;
import io.grpc.Metadata;

import org.wso2.apk.integration.utils.GenericClientInterceptor;
import org.wso2.apk.integration.utils.clients.student_service.StudentRequest;
import org.wso2.apk.integration.utils.clients.student_service.StudentResponse;
Expand All @@ -24,6 +26,7 @@ public class SimpleGRPCStudentClient {
private static final int EVENTUAL_SUCCESS_RESPONSE_TIMEOUT_IN_SECONDS = 10;
private final String host;
private final int port;
private static Metadata responseHeaders;

public SimpleGRPCStudentClient(String host, int port) {
this.host = host;
Expand Down Expand Up @@ -53,6 +56,7 @@ public StudentResponse GetStudent(Map<String, String> headers) throws StatusRunt
log.error("Failed to get student");
throw new RuntimeException("Failed to get student");
}
setResponseHeaders(interceptor.getResponseHeaders());
return response;
} catch (SSLException e) {
throw new RuntimeException("Failed to create SSL context", e);
Expand All @@ -72,6 +76,18 @@ public StudentResponse GetStudent(Map<String, String> headers) throws StatusRunt
}
}

public static String getResponseHeader(String headerName) {
Metadata.Key<String> headerValue = Metadata.Key.of(headerName, Metadata.ASCII_STRING_MARSHALLER);
if (responseHeaders == null) {
return "";
}
return responseHeaders.get(headerValue);
}

public void setResponseHeaders(Metadata metadata) {
SimpleGRPCStudentClient.responseHeaders = metadata;
}

public StudentResponse GetStudentDefaultVersion(Map<String, String> headers) throws StatusRuntimeException {
ManagedChannel managedChannel = null;
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: "6a254687f3229c35dd0189aac7f7fc4b6228e97a"
basePath: "/org.apk"
version: "v1"
type: "GRPC"
id: "grpc-interceptor-api"
endpointConfigurations:
production:
endpoint: "http://grpc-backend:6565"
defaultVersion: false
subscriptionValidation: false
operations:
- target: "student_service.StudentService"
verb: "GetStudent"
secured: true
scopes: []
- target: "student_service.StudentService"
verb: "GetStudentStream"
secured: true
scopes: []
- target: "student_service.StudentService"
verb: "SendStudentStream"
secured: true
scopes: []
- target: "student_service.StudentService"
verb: "SendAndGetStudentStream"
secured: true
scopes: []
apiPolicies:
request:
- policyName: "Interceptor"
policyVersion: v1
parameters:
backendUrl: "http://interceptor-service.apk-integration-test.svc.cluster.local:8443"
contextEnabled: true
headersEnabled: true
bodyEnabled: true
response:
- policyName: "Interceptor"
policyVersion: v1
parameters:
backendUrl: "http://interceptor-service.apk-integration-test.svc.cluster.local:8443"
contextEnabled: true
headersEnabled: true
bodyEnabled: true
21 changes: 21 additions & 0 deletions test/cucumber-tests/src/test/resources/tests/api/GRPC.feature
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,25 @@ Feature: Generating APK conf for gRPC API
Given The system is ready
And I have a valid subscription
When I undeploy the API whose ID is "grpc-default-version-api"
Then the response status code should be 202

Scenario: Deploying gRPC API with interceptor policy
Given The system is ready
And I have a valid subscription
When I use the APK Conf file "artifacts/apk-confs/grpc/grpc-interceptor.apk-conf"
And the definition file "artifacts/definitions/student.proto"
And make the API deployment request
Then the response status code should be 200
Then I set headers
| Authorization | bearer ${accessToken} |
And I make grpc request GetStudent to "default.gw.wso2.com" with port 9095
And the gRPC response status code should be 0
And the student response body should contain name: "Student" age: 10
And the GRPC response should contain header "interceptor-response-header"


Scenario: Undeploy API
Given The system is ready
And I have a valid subscription
When I undeploy the API whose ID is "grpc-interceptor-api"
Then the response status code should be 202

0 comments on commit adf0993

Please sign in to comment.