Skip to content

Commit ea38e01

Browse files
authored
Merge pull request #774 from kaleido-io/contract-api-fix
Add E2E test for contract APIs and fix postgres migration
2 parents fab9e31 + 64aeb7b commit ea38e01

File tree

7 files changed

+132
-4
lines changed

7 files changed

+132
-4
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
BEGIN;
2+
ALTER TABLE contractapis DROP COLUMN message_id;
3+
COMMIT;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
BEGIN;
2+
ALTER TABLE contractapis ADD COLUMN message_id UUID NOT NULL;
3+
COMMIT;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-- SQLite doesn't need any change here because it already had the correct columns
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-- SQLite doesn't need any change here because it already had the correct columns

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@
4444
"release": "v1.0.0"
4545
},
4646
"cli": {
47-
"tag": "v0.0.48"
47+
"tag": "v1.0.0"
4848
}
4949
}

test/e2e/ethereum_contract_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,57 @@ func (suite *EthereumContractTestSuite) TestFFIInvokeMethod() {
247247
assert.Equal(suite.testState.t, `{"output":"42"}`, string(resJSON))
248248
DeleteContractListener(suite.T(), suite.testState.client1, listener.ID)
249249
}
250+
251+
func (suite *EthereumContractTestSuite) TestContractAPIMethod() {
252+
defer suite.testState.done()
253+
254+
received1 := wsReader(suite.testState.ws1, true)
255+
APIName := fftypes.NewUUID().String()
256+
257+
ffiReference := &fftypes.FFIReference{
258+
ID: suite.interfaceID,
259+
}
260+
261+
location := map[string]interface{}{
262+
"address": suite.contractAddress,
263+
}
264+
locationBytes, _ := json.Marshal(location)
265+
266+
createContractAPIResult, err := CreateContractAPI(suite.T(), suite.testState.client1, APIName, ffiReference, fftypes.JSONAnyPtr(string(locationBytes)))
267+
assert.NotNil(suite.T(), createContractAPIResult)
268+
assert.NoError(suite.T(), err)
269+
270+
listener, err := CreateContractAPIListener(suite.T(), suite.testState.client1, APIName, "Changed", "firefly_e2e")
271+
assert.NoError(suite.T(), err)
272+
273+
listeners := GetContractListeners(suite.T(), suite.testState.client1, suite.testState.startTime)
274+
assert.Equal(suite.T(), 1, len(listeners))
275+
assert.Equal(suite.T(), listener.BackendID, listeners[0].BackendID)
276+
277+
input := fftypes.JSONAny(`{"newValue": 42}`)
278+
invokeResult, err := InvokeContractAPIMethod(suite.T(), suite.testState.client1, APIName, "set", &input)
279+
assert.NoError(suite.testState.t, err)
280+
assert.NotNil(suite.T(), invokeResult)
281+
282+
match := map[string]interface{}{
283+
"info": map[string]interface{}{
284+
"address": suite.contractAddress,
285+
},
286+
"output": map[string]interface{}{
287+
"_value": "42",
288+
"_from": suite.testState.org1key.Value,
289+
},
290+
"listener": listener.ID.String(),
291+
}
292+
event := waitForContractEvent(suite.T(), suite.testState.client1, received1, match)
293+
assert.NotNil(suite.T(), event)
294+
assert.NoError(suite.testState.t, err)
295+
296+
res, err := QueryContractAPIMethod(suite.T(), suite.testState.client1, APIName, "get", fftypes.JSONAnyPtr("{}"))
297+
assert.NoError(suite.testState.t, err)
298+
resJSON, err := json.Marshal(res)
299+
assert.NoError(suite.testState.t, err)
300+
assert.Equal(suite.testState.t, `{"output":"42"}`, string(resJSON))
301+
302+
DeleteContractListener(suite.T(), suite.testState.client1, listener.ID)
303+
}

test/e2e/restclient_test.go

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ var (
6161
urlContractQuery = "/namespaces/default/contracts/query"
6262
urlContractInterface = "/namespaces/default/contracts/interfaces"
6363
urlContractListeners = "/namespaces/default/contracts/listeners"
64+
urlContractAPI = "/namespaces/default/apis"
6465
urlBlockchainEvents = "/namespaces/default/blockchainevents"
6566
urlGetOrganizations = "/network/organizations"
6667
urlGetOrgKeys = "/namespaces/ff_system/identities/%s/verifiers"
@@ -650,15 +651,15 @@ func CreateFFIContractListener(t *testing.T, client *resty.Client, ffiReference
650651
},
651652
EventPath: eventPath,
652653
}
653-
var sub fftypes.ContractListener
654+
var listener fftypes.ContractListener
654655
path := urlContractListeners
655656
resp, err := client.R().
656657
SetBody(&body).
657-
SetResult(&sub).
658+
SetResult(&listener).
658659
Post(path)
659660
require.NoError(t, err)
660661
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
661-
return &sub
662+
return &listener
662663
}
663664

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

732+
func CreateContractAPI(t *testing.T, client *resty.Client, name string, FFIReference *fftypes.FFIReference, location *fftypes.JSONAny) (interface{}, error) {
733+
apiReqBody := &fftypes.ContractAPI{
734+
Name: name,
735+
Interface: FFIReference,
736+
Location: location,
737+
}
738+
739+
var res interface{}
740+
path := urlContractAPI
741+
resp, err := client.R().
742+
SetBody(apiReqBody).
743+
SetResult(&res).
744+
SetQueryParam("confirm", "true").
745+
Post(path)
746+
require.NoError(t, err)
747+
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
748+
return res, err
749+
}
750+
751+
func InvokeContractAPIMethod(t *testing.T, client *resty.Client, APIName string, methodName string, input *fftypes.JSONAny) (interface{}, error) {
752+
apiReqBody := map[string]interface{}{
753+
"input": input,
754+
}
755+
var res interface{}
756+
path := fmt.Sprintf("%s/%s/invoke/%s", urlContractAPI, APIName, methodName)
757+
resp, err := client.R().
758+
SetBody(apiReqBody).
759+
SetResult(&res).
760+
SetQueryParam("confirm", "true").
761+
Post(path)
762+
require.NoError(t, err)
763+
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
764+
return res, err
765+
}
766+
767+
func QueryContractAPIMethod(t *testing.T, client *resty.Client, APIName string, methodName string, input *fftypes.JSONAny) (interface{}, error) {
768+
apiReqBody := map[string]interface{}{
769+
"input": input,
770+
}
771+
var res interface{}
772+
path := fmt.Sprintf("%s/%s/query/%s", urlContractAPI, APIName, methodName)
773+
resp, err := client.R().
774+
SetBody(apiReqBody).
775+
SetResult(&res).
776+
Post(path)
777+
require.NoError(t, err)
778+
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
779+
return res, err
780+
}
781+
782+
func CreateContractAPIListener(t *testing.T, client *resty.Client, APIName, eventName, topic string) (*fftypes.ContractListener, error) {
783+
apiReqBody := map[string]interface{}{
784+
"topic": topic,
785+
}
786+
var listener fftypes.ContractListener
787+
path := fmt.Sprintf("%s/%s/listeners/%s", urlContractAPI, APIName, eventName)
788+
resp, err := client.R().
789+
SetBody(apiReqBody).
790+
SetResult(&listener).
791+
Post(path)
792+
require.NoError(t, err)
793+
require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String())
794+
return &listener, err
795+
}
796+
731797
func GetEvent(t *testing.T, client *resty.Client, eventID string) (interface{}, error) {
732798
var res interface{}
733799
path := fmt.Sprintf("%s/%s", urlGetEvents, eventID)

0 commit comments

Comments
 (0)