Skip to content

Commit

Permalink
Merge pull request #774 from kaleido-io/contract-api-fix
Browse files Browse the repository at this point in the history
Add E2E test for contract APIs and fix postgres migration
  • Loading branch information
nguyer authored Apr 27, 2022
2 parents fab9e31 + 64aeb7b commit ea38e01
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 4 deletions.
3 changes: 3 additions & 0 deletions db/migrations/postgres/000086_alter_contractapis.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
BEGIN;
ALTER TABLE contractapis DROP COLUMN message_id;
COMMIT;
3 changes: 3 additions & 0 deletions db/migrations/postgres/000086_alter_contractapis.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
BEGIN;
ALTER TABLE contractapis ADD COLUMN message_id UUID NOT NULL;
COMMIT;
1 change: 1 addition & 0 deletions db/migrations/sqlite/000086_alter_contractapis.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-- SQLite doesn't need any change here because it already had the correct columns
1 change: 1 addition & 0 deletions db/migrations/sqlite/000086_alter_contractapis.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-- SQLite doesn't need any change here because it already had the correct columns
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@
"release": "v1.0.0"
},
"cli": {
"tag": "v0.0.48"
"tag": "v1.0.0"
}
}
54 changes: 54 additions & 0 deletions test/e2e/ethereum_contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,57 @@ func (suite *EthereumContractTestSuite) TestFFIInvokeMethod() {
assert.Equal(suite.testState.t, `{"output":"42"}`, string(resJSON))
DeleteContractListener(suite.T(), suite.testState.client1, listener.ID)
}

func (suite *EthereumContractTestSuite) TestContractAPIMethod() {
defer suite.testState.done()

received1 := wsReader(suite.testState.ws1, true)
APIName := fftypes.NewUUID().String()

ffiReference := &fftypes.FFIReference{
ID: suite.interfaceID,
}

location := map[string]interface{}{
"address": suite.contractAddress,
}
locationBytes, _ := json.Marshal(location)

createContractAPIResult, err := CreateContractAPI(suite.T(), suite.testState.client1, APIName, ffiReference, fftypes.JSONAnyPtr(string(locationBytes)))
assert.NotNil(suite.T(), createContractAPIResult)
assert.NoError(suite.T(), err)

listener, err := CreateContractAPIListener(suite.T(), suite.testState.client1, APIName, "Changed", "firefly_e2e")
assert.NoError(suite.T(), err)

listeners := GetContractListeners(suite.T(), suite.testState.client1, suite.testState.startTime)
assert.Equal(suite.T(), 1, len(listeners))
assert.Equal(suite.T(), listener.BackendID, listeners[0].BackendID)

input := fftypes.JSONAny(`{"newValue": 42}`)
invokeResult, err := InvokeContractAPIMethod(suite.T(), suite.testState.client1, APIName, "set", &input)
assert.NoError(suite.testState.t, err)
assert.NotNil(suite.T(), invokeResult)

match := map[string]interface{}{
"info": map[string]interface{}{
"address": suite.contractAddress,
},
"output": map[string]interface{}{
"_value": "42",
"_from": suite.testState.org1key.Value,
},
"listener": listener.ID.String(),
}
event := waitForContractEvent(suite.T(), suite.testState.client1, received1, match)
assert.NotNil(suite.T(), event)
assert.NoError(suite.testState.t, err)

res, err := QueryContractAPIMethod(suite.T(), suite.testState.client1, APIName, "get", fftypes.JSONAnyPtr("{}"))
assert.NoError(suite.testState.t, err)
resJSON, err := json.Marshal(res)
assert.NoError(suite.testState.t, err)
assert.Equal(suite.testState.t, `{"output":"42"}`, string(resJSON))

DeleteContractListener(suite.T(), suite.testState.client1, listener.ID)
}
72 changes: 69 additions & 3 deletions test/e2e/restclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ var (
urlContractQuery = "/namespaces/default/contracts/query"
urlContractInterface = "/namespaces/default/contracts/interfaces"
urlContractListeners = "/namespaces/default/contracts/listeners"
urlContractAPI = "/namespaces/default/apis"
urlBlockchainEvents = "/namespaces/default/blockchainevents"
urlGetOrganizations = "/network/organizations"
urlGetOrgKeys = "/namespaces/ff_system/identities/%s/verifiers"
Expand Down Expand Up @@ -650,15 +651,15 @@ func CreateFFIContractListener(t *testing.T, client *resty.Client, ffiReference
},
EventPath: eventPath,
}
var sub fftypes.ContractListener
var listener fftypes.ContractListener
path := urlContractListeners
resp, err := client.R().
SetBody(&body).
SetResult(&sub).
SetResult(&listener).
Post(path)
require.NoError(t, err)
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
return &sub
return &listener
}

func GetContractListeners(t *testing.T, client *resty.Client, startTime time.Time) (subs []*fftypes.ContractListener) {
Expand Down Expand Up @@ -728,6 +729,71 @@ func CreateFFI(t *testing.T, client *resty.Client, ffi *fftypes.FFI) (interface{
return res, err
}

func CreateContractAPI(t *testing.T, client *resty.Client, name string, FFIReference *fftypes.FFIReference, location *fftypes.JSONAny) (interface{}, error) {
apiReqBody := &fftypes.ContractAPI{
Name: name,
Interface: FFIReference,
Location: location,
}

var res interface{}
path := urlContractAPI
resp, err := client.R().
SetBody(apiReqBody).
SetResult(&res).
SetQueryParam("confirm", "true").
Post(path)
require.NoError(t, err)
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
return res, err
}

func InvokeContractAPIMethod(t *testing.T, client *resty.Client, APIName string, methodName string, input *fftypes.JSONAny) (interface{}, error) {
apiReqBody := map[string]interface{}{
"input": input,
}
var res interface{}
path := fmt.Sprintf("%s/%s/invoke/%s", urlContractAPI, APIName, methodName)
resp, err := client.R().
SetBody(apiReqBody).
SetResult(&res).
SetQueryParam("confirm", "true").
Post(path)
require.NoError(t, err)
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
return res, err
}

func QueryContractAPIMethod(t *testing.T, client *resty.Client, APIName string, methodName string, input *fftypes.JSONAny) (interface{}, error) {
apiReqBody := map[string]interface{}{
"input": input,
}
var res interface{}
path := fmt.Sprintf("%s/%s/query/%s", urlContractAPI, APIName, methodName)
resp, err := client.R().
SetBody(apiReqBody).
SetResult(&res).
Post(path)
require.NoError(t, err)
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
return res, err
}

func CreateContractAPIListener(t *testing.T, client *resty.Client, APIName, eventName, topic string) (*fftypes.ContractListener, error) {
apiReqBody := map[string]interface{}{
"topic": topic,
}
var listener fftypes.ContractListener
path := fmt.Sprintf("%s/%s/listeners/%s", urlContractAPI, APIName, eventName)
resp, err := client.R().
SetBody(apiReqBody).
SetResult(&listener).
Post(path)
require.NoError(t, err)
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
return &listener, err
}

func GetEvent(t *testing.T, client *resty.Client, eventID string) (interface{}, error) {
var res interface{}
path := fmt.Sprintf("%s/%s", urlGetEvents, eventID)
Expand Down

0 comments on commit ea38e01

Please sign in to comment.