Skip to content
This repository has been archived by the owner on Mar 27, 2024. It is now read-only.

test: DIDComm Router - Rest Binding BDD tests #1281

Merged
merged 1 commit into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions test/bdd/bddtests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,5 @@ func FeatureContext(s *godog.Suite) {

// Register router tests
route.NewRouteSDKSteps(bddContext).RegisterSteps(s)
route.NewRouteRESTSteps(bddContext).RegisterSteps(s)
}
66 changes: 66 additions & 0 deletions test/bdd/features/aries_router_e2e_controller.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#
# Copyright SecureKey Technologies Inc. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

@all
@aries_router_controller
Feature: DIDComm Transport between two Agents through DIDComm Routers [REST Binding]

# https://wiki.hyperledger.org/display/ARIES/DIDComm+MediatorRouter
Scenario: Decentralized Identifier(DID) Exchange between two Edge Agents(without Inbound) through Routers
# DID Exchange between Carl and his Router
Given "Carl" agent is running with controller "http://localhost:10081" and webhook "http://localhost:10082" and "all" as the transport return route option
And "Carl-Router" agent is running on "http://localhost:10091,ws://localhost:10092" with controller "http://localhost:10093" and webhook "http://localhost:10094"

When "Carl-Router" creates invitation through controller with label "carl-router-agent"
And "Carl" receives invitation from "Carl-Router" through controller

Then "Carl" approves exchange invitation through controller
And "Carl-Router" approves exchange request through controller

Then "Carl-Router" waits for post state event "completed" to webhook
And "Carl" waits for post state event "completed" to webhook

Then "Carl-Router" retrieves connection record through controller and validates that connection state is "completed"
And "Carl" retrieves connection record through controller and validates that connection state is "completed"
And "Carl" saves the connectionID to variable "xyz"

# DID Exchange between Dave and his Router
Given "Dave" agent is running with controller "http://localhost:10061" and webhook "http://localhost:10062" and "all" as the transport return route option
And "Dave-Router" agent is running on "http://localhost:10071,ws://localhost:10092" with controller "http://localhost:10073" and webhook "http://localhost:10074"

When "Dave-Router" creates invitation through controller with label "Dave-router-agent"
And "Dave" receives invitation from "Dave-Router" through controller

Then "Dave" approves exchange invitation through controller
And "Dave-Router" approves exchange request through controller

Then "Dave-Router" waits for post state event "completed" to webhook
And "Dave" waits for post state event "completed" to webhook

Then "Dave-Router" retrieves connection record through controller and validates that connection state is "completed"
And "Dave" retrieves connection record through controller and validates that connection state is "completed"
And "Dave" saves the connectionID to variable "abc"

# Carl registers her Router
And "Carl" unregisters the router
And "Carl" sets connection "xyz" as the router

# Dave registers his Router
And "Dave" unregisters the router
And "Dave" sets connection "abc" as the router

# DIDExchange between Alice and Bob through routers
When "Carl" creates invitation through controller with label "carl-agent"
And "Dave" receives invitation from "Carl" through controller

Then "Dave" approves exchange invitation through controller
And "Carl" approves exchange request through controller

Then "Carl" waits for post state event "completed" to webhook
And "Dave" waits for post state event "completed" to webhook

Then "Carl" retrieves connection record through controller and validates that connection state is "completed"
And "Dave" retrieves connection record through controller and validates that connection state is "completed"
4 changes: 2 additions & 2 deletions test/bdd/features/aries_router_e2e_sdk.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
#

@all
@aries_router
Feature: DIDComm Transport between two Agents through DIDComm Routers
@aries_router_sdk
Feature: DIDComm Transport between two Agents through DIDComm Routers [SDK]

# https://wiki.hyperledger.org/display/ARIES/DIDComm+MediatorRouter
Scenario: Decentralized Identifier(DID) Exchange between two Edge Agents(without Inbound) through Routers
Expand Down
24 changes: 24 additions & 0 deletions test/bdd/fixtures/agent-rest/.env
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,27 @@ CARL_WEBHOOK_PORT=10082
CARL_ROUTER_WEBHOOK_CONTAINER_NAME=carl.router.webhook.example.com
CARL_ROUTER_WEBHOOK_HOST=0.0.0.0
CARL_ROUTER_WEBHOOK_PORT=10094

# Dave agent configurations
DAVE_HOST=0.0.0.0
DAVE_API_PORT=10061
DAVE_DB_PATH=/tmp/db/aries
DAVE_WEBHOOK_PORT=10062

# Dave router configurations
DAVE_ROUTER_HOST=0.0.0.0
DAVE_ROUTER_HTTP_INBOUND_PORT=10071
DAVE_ROUTER_WS_INBOUND_PORT=10072
DAVE_ROUTER_API_PORT=10073
DAVE_ROUTER_DB_PATH=/tmp/db/aries
DAVE_ROUTER_WEBHOOK_PORT=10074

# Dave webhook configurations
DAVE_WEBHOOK_CONTAINER_NAME=dave.webhook.example.com
DAVE_WEBHOOK_HOST=0.0.0.0
DAVE_WEBHOOK_PORT=10062

# Dave Router webhook configurations
DAVE_ROUTER_WEBHOOK_CONTAINER_NAME=dave.router.webhook.example.com
DAVE_ROUTER_WEBHOOK_HOST=0.0.0.0
DAVE_ROUTER_WEBHOOK_PORT=10074
56 changes: 56 additions & 0 deletions test/bdd/fixtures/agent-rest/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,62 @@ services:
networks:
- bdd_net

dave.agent.example.com:
container_name: dave.aries.example.com
image: ${AGENT_REST_IMAGE}:${AGENT_REST_IMAGE_TAG}
environment:
- ARIESD_API_HOST=${DAVE_HOST}:${DAVE_API_PORT}
- ARIESD_WEBHOOK_URL=http://${DAVE_WEBHOOK_CONTAINER_NAME}:${DAVE_WEBHOOK_PORT}
- ARIESD_DEFAULT_LABEL=dave-agent
- ARIESD_DB_PATH=${DAVE_DB_PATH}
- ARIESD_OUTBOUND_TRANSPORT=${HTTP_SCHEME},${WS_SCHEME}
- ARIESD_TRANSPORT_RETURN_ROUTE=${TRANSPORT_RETURN_OPTION_ALL}
ports:
- ${DAVE_API_PORT}:${DAVE_API_PORT}
command: start
networks:
- bdd_net

dave.webhook.example.com:
container_name: ${DAVE_WEBHOOK_CONTAINER_NAME}
image: ${SAMPLE_WEBHOOK_IMAGE}:${SAMPLE_WEBHOOK_IMAGE_TAG}
environment:
- WEBHOOK_PORT=${DAVE_WEBHOOK_PORT}
ports:
- ${DAVE_WEBHOOK_PORT}:${DAVE_WEBHOOK_PORT}
networks:
- bdd_net

dave.router.agent.example.com:
container_name: dave.router.aries.example.com
image: ${AGENT_REST_IMAGE}:${AGENT_REST_IMAGE_TAG}
environment:
- ARIESD_API_HOST=${DAVE_ROUTER_HOST}:${DAVE_ROUTER_API_PORT}
- ARIESD_INBOUND_HOST=${HTTP_SCHEME}@${DAVE_ROUTER_HOST}:${DAVE_ROUTER_HTTP_INBOUND_PORT},${WS_SCHEME}@${DAVE_ROUTER_HOST}:${DAVE_ROUTER_WS_INBOUND_PORT}
- ARIESD_INBOUND_HOST_EXTERNAL=${HTTP_SCHEME}@http://dave.router.aries.example.com:${DAVE_ROUTER_HTTP_INBOUND_PORT},${WS_SCHEME}@ws://dave.router.aries.example.com:${DAVE_ROUTER_WS_INBOUND_PORT}
- ARIESD_WEBHOOK_URL=http://${DAVE_ROUTER_WEBHOOK_CONTAINER_NAME}:${DAVE_ROUTER_WEBHOOK_PORT}
- ARIESD_DB_PATH=${DAVE_ROUTER_DB_PATH}
- ARIESD_DEFAULT_LABEL=dave-router-agent
- ARIESD_OUTBOUND_TRANSPORT=${HTTP_SCHEME},${WS_SCHEME}
- ARIESD_HTTP_RESOLVER=${HTTP_DID_RESOLVER}
ports:
- ${DAVE_ROUTER_HTTP_INBOUND_PORT}:${DAVE_ROUTER_HTTP_INBOUND_PORT}
- ${DAVE_ROUTER_WS_INBOUND_PORT}:${DAVE_ROUTER_WS_INBOUND_PORT}
- ${DAVE_ROUTER_API_PORT}:${DAVE_ROUTER_API_PORT}
command: start
networks:
- bdd_net

dave.router.webhook.example.com:
container_name: ${DAVE_ROUTER_WEBHOOK_CONTAINER_NAME}
image: ${SAMPLE_WEBHOOK_IMAGE}:${SAMPLE_WEBHOOK_IMAGE_TAG}
environment:
- WEBHOOK_PORT=${DAVE_ROUTER_WEBHOOK_PORT}
ports:
- ${DAVE_ROUTER_WEBHOOK_PORT}:${DAVE_ROUTER_WEBHOOK_PORT}
networks:
- bdd_net

networks:
bdd_net:
driver: bridge
20 changes: 20 additions & 0 deletions test/bdd/pkg/didexchange/didexchange_controller_steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package didexchange
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -91,6 +92,9 @@ func (a *ControllerSteps) RegisterSteps(s *godog.Suite) { //nolint dupl
a.createImplicitInvitationWithDID)
s.Step(`^"([^"]*)" has established connection with "([^"]*)" through did exchange using controller$`,
a.performDIDExchange)
s.Step(`^"([^"]*)" validates that the invitation service endpoint of type "([^"]*)"$`,
a.validateInvitationEndpointScheme)
s.Step(`^"([^"]*)" saves the connectionID to variable "([^"]*)"$`, a.saveConnectionID)
}

func (a *ControllerSteps) pullWebhookEvents(agentID, state string) (string, error) {
Expand Down Expand Up @@ -246,6 +250,16 @@ func (a *ControllerSteps) verifyCreateInvitationResult(result *didexcmd.CreateIn
return nil
}

func (a *ControllerSteps) validateInvitationEndpointScheme(inviterAgentID, scheme string) error {
invitation := a.invitations[inviterAgentID]

if !strings.HasPrefix(invitation.ServiceEndpoint, scheme) {
return errors.New("invitation service endpoint - invalid transport type")
}

return nil
}

func (a *ControllerSteps) receiveInvitation(inviteeAgentID, inviterAgentID string) error {
destination, ok := a.bddContext.GetControllerURL(inviteeAgentID)
if !ok {
Expand Down Expand Up @@ -283,6 +297,12 @@ func (a *ControllerSteps) receiveInvitation(inviteeAgentID, inviterAgentID strin
return nil
}

func (a *ControllerSteps) saveConnectionID(agentID, varName string) error {
a.bddContext.Args[varName] = a.connectionIDs[agentID]

return nil
}

func (a *ControllerSteps) approveInvitation(agentID string) error {
return a.performApproveInvitation(agentID, false)
}
Expand Down
134 changes: 134 additions & 0 deletions test/bdd/pkg/route/route_controller_steps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package route

import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"

"github.com/cucumber/godog"

"github.com/hyperledger/aries-framework-go/pkg/common/log"
"github.com/hyperledger/aries-framework-go/test/bdd/pkg/context"
)

var logger = log.New("aries-framework/tests/messaging")

type registerRouteReq struct {
ConnectionID string `json:"connectionID"`
}

// RESTSteps is steps for route using REST APIs
type RESTSteps struct {
bddContext *context.BDDContext
}

// NewRouteRESTSteps return steps for route using REST APIs
func NewRouteRESTSteps(ctx *context.BDDContext) *RESTSteps {
return &RESTSteps{
bddContext: ctx,
}
}

// RegisterRoute registers the router for the agent.
func (d *RESTSteps) RegisterRoute(agentID, varName string) error {
connectionID := d.bddContext.Args[varName]

destination, ok := d.bddContext.GetControllerURL(agentID)
if !ok {
return fmt.Errorf(" unable to find controller URL registered for agent [%s]", agentID)
}

err := sendHTTP(http.MethodPost, destination+"/route/register", registerRouteReq{ConnectionID: connectionID}, nil)
if err != nil {
return fmt.Errorf("router registration : %w", err)
}

return nil
}

// UnregisterRoute unregisters the router.
func (d *RESTSteps) UnregisterRoute(agentID string) error {
destination, ok := d.bddContext.GetControllerURL(agentID)
if !ok {
return fmt.Errorf(" unable to find controller URL registered for agent [%s]", agentID)
}

err := sendHTTP(http.MethodDelete, destination+"/route/unregister", nil, nil)
if err != nil {
// ignore error if router is not registered (code=5003)
if strings.Contains(err.Error(), "\"code\":5003") {
logger.Infof("ignore unregister - router not registered")

return nil
}

return fmt.Errorf("router unregistration : %w", err)
}

return nil
}

// RegisterSteps registers router steps
func (d *RESTSteps) RegisterSteps(s *godog.Suite) {
s.Step(`^"([^"]*)" sets connection "([^"]*)" as the router$`, d.RegisterRoute)
s.Step(`^"([^"]*)" unregisters the router$`, d.UnregisterRoute)
}

func sendHTTP(method, destination string, reqMsg, respMsg interface{}) error {
message, err := json.Marshal(reqMsg)
if err != nil {
return fmt.Errorf("failed to prepare params : %w", err)
}

// create request
req, err := http.NewRequest(method, destination, bytes.NewBuffer(message))
if err != nil {
return fmt.Errorf("failed to create new http '%s' request for '%s', cause: %s", method, destination, err)
}

// set headers
req.Header.Set("Content-Type", "application/json")

// send http request
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("failed to get response from '%s', cause :%s", destination, err)
}

defer closeResponse(resp.Body)

data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("unable to read response from '%s', cause :%s", destination, err)
}

logger.Debugf("Got response from '%s' [method: %s], response payload: %s", destination, method, string(data))

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to get successful response from '%s', unexpected status code [%d], "+
"and message [%s]", destination, resp.StatusCode, string(data))
}

if respMsg == nil {
return nil
}

return json.Unmarshal(data, respMsg)
}

func closeResponse(c io.Closer) {
err := c.Close()
if err != nil {
logger.Errorf("Failed to close response body : %s", err)
}
}