Skip to content

Commit b1f429c

Browse files
authored
5 full testsuite for the mcp server (#6)
* Add testsuite with MCP typescript SDK
1 parent 1b868d8 commit b1f429c

File tree

79 files changed

+3467
-431
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+3467
-431
lines changed

.gitignore

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
node_modules/
2+
.node_modules/
3+
built/*
4+
tests/cases/rwc/*
5+
tests/cases/perf/*
6+
!tests/cases/webharness/compilerToString.js
7+
test-args.txt
8+
~*.docx
9+
\#*\#
10+
.\#*
11+
tests/baselines/local/*
12+
tests/baselines/local.old/*
13+
tests/services/baselines/local/*
14+
tests/baselines/prototyping/local/*
15+
tests/baselines/rwc/*
16+
tests/baselines/reference/projectOutput/*
17+
tests/baselines/local/projectOutput/*
18+
tests/baselines/reference/testresults.tap
19+
tests/baselines/symlinks/*
20+
tests/services/baselines/prototyping/local/*
21+
tests/services/browser/typescriptServices.js
22+
src/harness/*.js
23+
src/compiler/diagnosticInformationMap.generated.ts
24+
src/compiler/diagnosticMessages.generated.json
25+
src/parser/diagnosticInformationMap.generated.ts
26+
src/parser/diagnosticMessages.generated.json
27+
rwc-report.html
28+
*.swp
29+
build.json
30+
*.actual
31+
tests/webTestServer.js
32+
tests/webTestServer.js.map
33+
tests/webhost/*.d.ts
34+
tests/webhost/webtsc.js
35+
tests/cases/**/*.js
36+
tests/cases/**/*.js.map
37+
*.config
38+
scripts/eslint/built/
39+
scripts/debug.bat
40+
scripts/run.bat
41+
scripts/**/*.js
42+
scripts/**/*.js.map
43+
coverage/
44+
internal/
45+
**/.DS_Store
46+
.settings
47+
**/.vs
48+
**/.vscode/*
49+
!**/.vscode/tasks.json
50+
!**/.vscode/settings.template.json
51+
!**/.vscode/launch.template.json
52+
!**/.vscode/extensions.json
53+
!tests/cases/projects/projectOption/**/node_modules
54+
!tests/cases/projects/NodeModulesSearch/**/*
55+
!tests/baselines/reference/project/nodeModules*/**/*
56+
.idea
57+
yarn.lock
58+
yarn-error.log
59+
.parallelperf.*
60+
tests/baselines/reference/dt
61+
.failed-tests
62+
TEST-results.xml
63+
package-lock.json
64+
.eslintcache
65+
*v8.log
66+
/lib/
67+
.env

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Not implmented:
4646

4747
See currently open issues for details. In general the following topics are prioritized:
4848

49-
- Full test suite especially covering session handling and error scenarios
49+
- ✅ Test suite using an MCP client --> exists via TypeScript SDK in folder test [Test](/test/README.md)
5050
- Demonstrate ways to use OAuth reducing challenges with only standard compliant clients
5151
- Cleanup batch job / report to delete outdated sessions
5252
- Improve logging by increasing the logged scope

abaplint.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@
846846
"severity": "Error"
847847
},
848848
"unused_types": {
849-
"exclude": [],
849+
"exclude": ["zcl_mcp_resp_get_prompt"],
850850
"severity": "Error",
851851
"skipNames": []
852852
},

src/ajson/zcl_mcp_ajson.clas.abap

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ class zcl_mcp_ajson definition
3434
delete for zif_mcp_ajson~delete,
3535
touch_array for zif_mcp_ajson~touch_array,
3636
push for zif_mcp_ajson~push,
37-
stringify for zif_mcp_ajson~stringify.
37+
stringify for zif_mcp_ajson~stringify,
38+
touch_object for zif_mcp_ajson~touch_object.
3839

3940
aliases:
4041
clone for zif_mcp_ajson~clone,
@@ -967,4 +968,61 @@ CLASS zcl_mcp_ajson IMPLEMENTATION.
967968
ms_opts-to_abap_corresponding_only = iv_enable.
968969
ri_json = me.
969970
endmethod.
971+
972+
method zif_mcp_ajson~touch_object.
973+
974+
data lr_node type ref to zif_mcp_ajson_types=>ty_node.
975+
data ls_deleted_node type zif_mcp_ajson_types=>ty_node.
976+
data ls_new_node like line of mt_json_tree.
977+
data ls_split_path type zif_mcp_ajson_types=>ty_path_name.
978+
979+
read_only_watchdog( ).
980+
981+
ls_split_path = lcl_utils=>split_path( iv_path ).
982+
if ls_split_path is initial. " Assign root, exceptional processing
983+
ls_new_node-path = ls_split_path-path.
984+
ls_new_node-name = ls_split_path-name.
985+
ls_new_node-type = zif_mcp_ajson_types=>node_type-object.
986+
insert ls_new_node into table mt_json_tree.
987+
return.
988+
endif.
989+
990+
if iv_clear = abap_true.
991+
ls_deleted_node = delete_subtree(
992+
iv_path = ls_split_path-path
993+
iv_name = ls_split_path-name ).
994+
else.
995+
lr_node = get_item( iv_path ).
996+
endif.
997+
998+
if lr_node is initial. " Or node was cleared
999+
1000+
data lr_parent type ref to zif_mcp_ajson_types=>ty_node.
1001+
lr_parent = prove_path_exists( ls_split_path-path ).
1002+
assert lr_parent is not initial.
1003+
1004+
lr_parent->children = lr_parent->children + 1.
1005+
1006+
ls_new_node-path = ls_split_path-path.
1007+
ls_new_node-name = ls_split_path-name.
1008+
ls_new_node-type = zif_mcp_ajson_types=>node_type-object.
1009+
1010+
if ms_opts-keep_item_order = abap_true.
1011+
if ls_deleted_node is not initial.
1012+
ls_new_node-order = ls_deleted_node-order.
1013+
else.
1014+
ls_new_node-order = lr_parent->children.
1015+
endif.
1016+
endif.
1017+
1018+
insert ls_new_node into table mt_json_tree.
1019+
1020+
elseif lr_node->type <> zif_mcp_ajson_types=>node_type-object.
1021+
zcx_mcp_ajson_error=>raise( |Path [{ iv_path }] already used and is not object| ) ##NO_TEXT.
1022+
endif.
1023+
1024+
ri_json = me.
1025+
1026+
endmethod.
1027+
9701028
ENDCLASS.

src/ajson/zcl_mcp_ajson.clas.testclasses.abap

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,6 +2488,7 @@ class ltcl_writer_test definition final
24882488
methods setx_float for testing raising zcx_mcp_ajson_error.
24892489
methods setx_complex for testing raising zcx_mcp_ajson_error.
24902490
methods setx_complex_w_keep_order for testing raising zcx_mcp_ajson_error.
2491+
methods touch_object for testing raising zcx_mcp_ajson_error.
24912492

24922493
methods set_with_type_slice
24932494
importing
@@ -3800,6 +3801,125 @@ class ltcl_writer_test implementation.
38003801

38013802
endmethod.
38023803

3804+
method touch_object.
3805+
3806+
data lo_cut type ref to zcl_mcp_ajson.
3807+
data lo_nodes_exp type ref to lcl_nodes_helper.
3808+
data li_writer type ref to zif_mcp_ajson.
3809+
3810+
" Test 1: Create empty object at path
3811+
lo_cut = zcl_mcp_ajson=>create_empty( ).
3812+
li_writer = lo_cut.
3813+
3814+
create object lo_nodes_exp.
3815+
lo_nodes_exp->add( ' | |object | ||1' ).
3816+
lo_nodes_exp->add( '/ |a |object | ||0' ).
3817+
3818+
li_writer->touch_object( iv_path = '/a' ).
3819+
3820+
cl_abap_unit_assert=>assert_equals(
3821+
act = lo_cut->mt_json_tree
3822+
exp = lo_nodes_exp->sorted( ) ).
3823+
3824+
cl_abap_unit_assert=>assert_equals(
3825+
act = lo_cut->stringify( )
3826+
exp = '{"a":{}}' ).
3827+
3828+
" Test 2: Create empty object at root level
3829+
lo_cut = zcl_mcp_ajson=>create_empty( ).
3830+
li_writer = lo_cut.
3831+
3832+
create object lo_nodes_exp.
3833+
lo_nodes_exp->add( ' | |object | ||0' ).
3834+
3835+
li_writer->touch_object( iv_path = '/' ).
3836+
3837+
cl_abap_unit_assert=>assert_equals(
3838+
act = lo_cut->mt_json_tree
3839+
exp = lo_nodes_exp->sorted( ) ).
3840+
3841+
cl_abap_unit_assert=>assert_equals(
3842+
act = lo_cut->stringify( )
3843+
exp = '{}' ).
3844+
3845+
" Test 3: Create nested objects
3846+
lo_cut = zcl_mcp_ajson=>create_empty( ).
3847+
li_writer = lo_cut.
3848+
3849+
create object lo_nodes_exp.
3850+
lo_nodes_exp->add( ' | |object | ||1' ).
3851+
lo_nodes_exp->add( '/ |a |object | ||1' ).
3852+
lo_nodes_exp->add( '/a/ |b |object | ||1' ).
3853+
lo_nodes_exp->add( '/a/b/ |c |object | ||0' ).
3854+
3855+
li_writer->touch_object( iv_path = '/a' ).
3856+
li_writer->touch_object( iv_path = '/a/b' ).
3857+
li_writer->touch_object( iv_path = '/a/b/c' ).
3858+
3859+
cl_abap_unit_assert=>assert_equals(
3860+
act = lo_cut->mt_json_tree
3861+
exp = lo_nodes_exp->sorted( ) ).
3862+
3863+
cl_abap_unit_assert=>assert_equals(
3864+
act = lo_cut->stringify( )
3865+
exp = '{"a":{"b":{"c":{}}}}' ).
3866+
3867+
" Test 4: Clear existing content
3868+
lo_cut = zcl_mcp_ajson=>create_empty( ).
3869+
li_writer = lo_cut.
3870+
3871+
li_writer->set(
3872+
iv_path = '/a/x'
3873+
iv_val = 'abc' ).
3874+
3875+
create object lo_nodes_exp.
3876+
lo_nodes_exp->add( ' | |object | ||1' ).
3877+
lo_nodes_exp->add( '/ |a |object | ||0' ).
3878+
3879+
li_writer->touch_object(
3880+
iv_path = '/a'
3881+
iv_clear = abap_true ).
3882+
3883+
cl_abap_unit_assert=>assert_equals(
3884+
act = lo_cut->mt_json_tree
3885+
exp = lo_nodes_exp->sorted( ) ).
3886+
3887+
cl_abap_unit_assert=>assert_equals(
3888+
act = lo_cut->stringify( )
3889+
exp = '{"a":{}}' ).
3890+
3891+
" Test 5: Error when existing node isn't an object
3892+
lo_cut = zcl_mcp_ajson=>create_empty( ).
3893+
li_writer = lo_cut.
3894+
3895+
li_writer->touch_array( iv_path = '/a' ).
3896+
3897+
data lx type ref to zcx_mcp_ajson_error.
3898+
try.
3899+
li_writer->touch_object( iv_path = '/a' ).
3900+
cl_abap_unit_assert=>fail( ).
3901+
catch zcx_mcp_ajson_error into lx.
3902+
cl_abap_unit_assert=>assert_equals(
3903+
act = lx->message
3904+
exp = 'Path [/a] already used and is not object' ).
3905+
endtry.
3906+
3907+
" Test 6: With item ordering - FIXED TYPE ISSUE
3908+
lo_cut = zcl_mcp_ajson=>create_empty( ).
3909+
li_writer = lo_cut.
3910+
li_writer->keep_item_order( ).
3911+
3912+
li_writer->set(
3913+
iv_path = '/b'
3914+
iv_val = 1 ).
3915+
li_writer->touch_object( '/a' ).
3916+
3917+
cl_abap_unit_assert=>assert_equals(
3918+
act = lo_cut->stringify( )
3919+
exp = '{"b":1,"a":{}}' ).
3920+
3921+
endmethod.
3922+
38033923
endclass.
38043924

38053925

src/ajson/zif_mcp_ajson.intf.abap

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,14 @@ interface zif_mcp_ajson
259259
raising
260260
zcx_mcp_ajson_error.
261261

262+
methods touch_object
263+
importing
264+
iv_path type string
265+
iv_clear type abap_bool default abap_false
266+
returning
267+
value(ri_json) type ref to zif_mcp_ajson
268+
raising
269+
zcx_mcp_ajson_error.
270+
271+
262272
endinterface.

src/data/zcl_mcp_req_call_tool.clas.testclasses.abap

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,9 @@ CLASS ltcl_mcp_req_call_tool IMPLEMENTATION.
9898
" Expected - name is required but missing
9999
cl_abap_unit_assert=>assert_equals( exp = 'ZMCP'
100100
act = lx_error->if_t100_message~t100key-msgid ).
101+
" required_params message number
101102
cl_abap_unit_assert=>assert_equals( exp = '002'
102-
act = lx_error->if_t100_message~t100key-msgno ). " required_params message number
103+
act = lx_error->if_t100_message~t100key-msgno ).
103104
ENDTRY.
104105
ENDMETHOD.
105106

@@ -120,8 +121,9 @@ CLASS ltcl_mcp_req_call_tool IMPLEMENTATION.
120121
" Expected - name is empty
121122
cl_abap_unit_assert=>assert_equals( exp = 'ZMCP'
122123
act = lx_error->if_t100_message~t100key-msgid ).
124+
" unknown_tool message number
123125
cl_abap_unit_assert=>assert_equals( exp = '009'
124-
act = lx_error->if_t100_message~t100key-msgno ). " unknown_tool message number
126+
act = lx_error->if_t100_message~t100key-msgno ).
125127
ENDTRY.
126128
ENDMETHOD.
127129
ENDCLASS.

src/data/zcl_mcp_req_get_prompt.clas.testclasses.abap

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,9 @@ CLASS ltcl_mcp_req_get_prompt IMPLEMENTATION.
102102
" Expected - name is required but missing
103103
cl_abap_unit_assert=>assert_equals( exp = 'ZMCP'
104104
act = lx_error->if_t100_message~t100key-msgid ).
105+
" required_params message number
105106
cl_abap_unit_assert=>assert_equals( exp = '002'
106-
act = lx_error->if_t100_message~t100key-msgno ). " required_params message number
107+
act = lx_error->if_t100_message~t100key-msgno ).
107108
ENDTRY.
108109
ENDMETHOD.
109110

@@ -122,8 +123,9 @@ CLASS ltcl_mcp_req_get_prompt IMPLEMENTATION.
122123
" Expected - name is empty
123124
cl_abap_unit_assert=>assert_equals( exp = 'ZMCP'
124125
act = lx_error->if_t100_message~t100key-msgid ).
126+
" prompt_name_invalid message number
125127
cl_abap_unit_assert=>assert_equals( exp = '001'
126-
act = lx_error->if_t100_message~t100key-msgno ). " prompt_name_invalid message number
128+
act = lx_error->if_t100_message~t100key-msgno ).
127129
ENDTRY.
128130
ENDMETHOD.
129131
ENDCLASS.

src/data/zcl_mcp_req_read_resource.clas.testclasses.abap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ CLASS ltcl_mcp_req_read_resource IMPLEMENTATION.
3636
cl_abap_unit_assert=>fail( 'Expected exception for missing URI' ).
3737
CATCH zcx_mcp_server.
3838
" Expected - URI is required but missing
39-
ENDTRY.
39+
ENDTRY. "#EC EMPTY_CATCH
4040
ENDMETHOD.
4141
ENDCLASS.

0 commit comments

Comments
 (0)