diff --git a/.gitattributes b/.gitattributes index cbdcbbc258e..5d410439284 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ *.js text eol=lf +# Byte-exact: the benchmark pins this fixture's SHA-256. +zeppelin-web-angular/e2e/fixtures/performance/*.json -text diff --git a/zeppelin-web-angular/.gitignore b/zeppelin-web-angular/.gitignore index d0a457873a3..bb775e418da 100644 --- a/zeppelin-web-angular/.gitignore +++ b/zeppelin-web-angular/.gitignore @@ -51,6 +51,7 @@ Thumbs.db /test-results-classic/ /playwright/.cache/ /playwright/.auth/ +/e2e/performance/baselines/*.json # .env diff --git a/zeppelin-web-angular/.prettierignore b/zeppelin-web-angular/.prettierignore index a16d95f3945..ed1a946bfb3 100644 --- a/zeppelin-web-angular/.prettierignore +++ b/zeppelin-web-angular/.prettierignore @@ -15,5 +15,6 @@ projects/*/coverage/* playwright-report/* playwright-coverage/* test-results/* +e2e/fixtures/performance/*.json .angular/* diff --git a/zeppelin-web-angular/e2e/fixtures/performance/notebook-route-100-paragraphs.json b/zeppelin-web-angular/e2e/fixtures/performance/notebook-route-100-paragraphs.json new file mode 100644 index 00000000000..79fde9f44fa --- /dev/null +++ b/zeppelin-web-angular/e2e/fixtures/performance/notebook-route-100-paragraphs.json @@ -0,0 +1,3319 @@ +{ + "name": "notebook-route-100-paragraphs", + "paragraphs": [ + { + "id": "paragraph_perf_001", + "title": "Baseline paragraph 001", + "text": "%sh\necho baseline-001", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 001\n" + } + ] + } + }, + { + "id": "paragraph_perf_002", + "title": "Baseline paragraph 002", + "text": "%sh\necho baseline-002", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 002\n" + } + ] + } + }, + { + "id": "paragraph_perf_003", + "title": "Baseline paragraph 003", + "text": "%sh\necho baseline-003", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 003\n" + } + ] + } + }, + { + "id": "paragraph_perf_004", + "title": "Baseline paragraph 004", + "text": "%sh\necho baseline-004", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 004\n" + } + ] + } + }, + { + "id": "paragraph_perf_005", + "title": "Baseline paragraph 005", + "text": "%sh\necho baseline-005", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 005\n" + } + ] + } + }, + { + "id": "paragraph_perf_006", + "title": "Baseline paragraph 006", + "text": "%sh\necho baseline-006", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 006\n" + } + ] + } + }, + { + "id": "paragraph_perf_007", + "title": "Baseline paragraph 007", + "text": "%sh\necho baseline-007", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 007\n" + } + ] + } + }, + { + "id": "paragraph_perf_008", + "title": "Baseline paragraph 008", + "text": "%sh\necho baseline-008", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 008\n" + } + ] + } + }, + { + "id": "paragraph_perf_009", + "title": "Baseline paragraph 009", + "text": "%sh\necho baseline-009", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 009\n" + } + ] + } + }, + { + "id": "paragraph_perf_010", + "title": "Baseline paragraph 010", + "text": "%sh\necho baseline-010", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 010\n" + } + ] + } + }, + { + "id": "paragraph_perf_011", + "title": "Baseline paragraph 011", + "text": "%sh\necho baseline-011", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 011\n" + } + ] + } + }, + { + "id": "paragraph_perf_012", + "title": "Baseline paragraph 012", + "text": "%sh\necho baseline-012", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 012\n" + } + ] + } + }, + { + "id": "paragraph_perf_013", + "title": "Baseline paragraph 013", + "text": "%sh\necho baseline-013", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 013\n" + } + ] + } + }, + { + "id": "paragraph_perf_014", + "title": "Baseline paragraph 014", + "text": "%sh\necho baseline-014", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 014\n" + } + ] + } + }, + { + "id": "paragraph_perf_015", + "title": "Baseline paragraph 015", + "text": "%sh\necho baseline-015", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 015\n" + } + ] + } + }, + { + "id": "paragraph_perf_016", + "title": "Baseline paragraph 016", + "text": "%sh\necho baseline-016", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 016\n" + } + ] + } + }, + { + "id": "paragraph_perf_017", + "title": "Baseline paragraph 017", + "text": "%sh\necho baseline-017", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 017\n" + } + ] + } + }, + { + "id": "paragraph_perf_018", + "title": "Baseline paragraph 018", + "text": "%sh\necho baseline-018", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 018\n" + } + ] + } + }, + { + "id": "paragraph_perf_019", + "title": "Baseline paragraph 019", + "text": "%sh\necho baseline-019", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 019\n" + } + ] + } + }, + { + "id": "paragraph_perf_020", + "title": "Baseline paragraph 020", + "text": "%sh\necho baseline-020", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 020\n" + } + ] + } + }, + { + "id": "paragraph_perf_021", + "title": "Baseline paragraph 021", + "text": "%sh\necho baseline-021", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 021\n" + } + ] + } + }, + { + "id": "paragraph_perf_022", + "title": "Baseline paragraph 022", + "text": "%sh\necho baseline-022", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 022\n" + } + ] + } + }, + { + "id": "paragraph_perf_023", + "title": "Baseline paragraph 023", + "text": "%sh\necho baseline-023", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 023\n" + } + ] + } + }, + { + "id": "paragraph_perf_024", + "title": "Baseline paragraph 024", + "text": "%sh\necho baseline-024", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 024\n" + } + ] + } + }, + { + "id": "paragraph_perf_025", + "title": "Baseline paragraph 025", + "text": "%sh\necho baseline-025", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 025\n" + } + ] + } + }, + { + "id": "paragraph_perf_026", + "title": "Baseline paragraph 026", + "text": "%sh\necho baseline-026", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 026\n" + } + ] + } + }, + { + "id": "paragraph_perf_027", + "title": "Baseline paragraph 027", + "text": "%sh\necho baseline-027", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 027\n" + } + ] + } + }, + { + "id": "paragraph_perf_028", + "title": "Baseline paragraph 028", + "text": "%sh\necho baseline-028", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 028\n" + } + ] + } + }, + { + "id": "paragraph_perf_029", + "title": "Baseline paragraph 029", + "text": "%sh\necho baseline-029", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 029\n" + } + ] + } + }, + { + "id": "paragraph_perf_030", + "title": "Baseline paragraph 030", + "text": "%sh\necho baseline-030", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 030\n" + } + ] + } + }, + { + "id": "paragraph_perf_031", + "title": "Baseline paragraph 031", + "text": "%sh\necho baseline-031", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 031\n" + } + ] + } + }, + { + "id": "paragraph_perf_032", + "title": "Baseline paragraph 032", + "text": "%sh\necho baseline-032", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 032\n" + } + ] + } + }, + { + "id": "paragraph_perf_033", + "title": "Baseline paragraph 033", + "text": "%sh\necho baseline-033", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 033\n" + } + ] + } + }, + { + "id": "paragraph_perf_034", + "title": "Baseline paragraph 034", + "text": "%sh\necho baseline-034", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 034\n" + } + ] + } + }, + { + "id": "paragraph_perf_035", + "title": "Baseline paragraph 035", + "text": "%sh\necho baseline-035", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 035\n" + } + ] + } + }, + { + "id": "paragraph_perf_036", + "title": "Baseline paragraph 036", + "text": "%sh\necho baseline-036", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 036\n" + } + ] + } + }, + { + "id": "paragraph_perf_037", + "title": "Baseline paragraph 037", + "text": "%sh\necho baseline-037", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 037\n" + } + ] + } + }, + { + "id": "paragraph_perf_038", + "title": "Baseline paragraph 038", + "text": "%sh\necho baseline-038", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 038\n" + } + ] + } + }, + { + "id": "paragraph_perf_039", + "title": "Baseline paragraph 039", + "text": "%sh\necho baseline-039", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 039\n" + } + ] + } + }, + { + "id": "paragraph_perf_040", + "title": "Baseline paragraph 040", + "text": "%sh\necho baseline-040", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 040\n" + } + ] + } + }, + { + "id": "paragraph_perf_041", + "title": "Baseline paragraph 041", + "text": "%sh\necho baseline-041", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 041\n" + } + ] + } + }, + { + "id": "paragraph_perf_042", + "title": "Baseline paragraph 042", + "text": "%sh\necho baseline-042", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 042\n" + } + ] + } + }, + { + "id": "paragraph_perf_043", + "title": "Baseline paragraph 043", + "text": "%sh\necho baseline-043", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 043\n" + } + ] + } + }, + { + "id": "paragraph_perf_044", + "title": "Baseline paragraph 044", + "text": "%sh\necho baseline-044", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 044\n" + } + ] + } + }, + { + "id": "paragraph_perf_045", + "title": "Baseline paragraph 045", + "text": "%sh\necho baseline-045", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 045\n" + } + ] + } + }, + { + "id": "paragraph_perf_046", + "title": "Baseline paragraph 046", + "text": "%sh\necho baseline-046", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 046\n" + } + ] + } + }, + { + "id": "paragraph_perf_047", + "title": "Baseline paragraph 047", + "text": "%sh\necho baseline-047", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 047\n" + } + ] + } + }, + { + "id": "paragraph_perf_048", + "title": "Baseline paragraph 048", + "text": "%sh\necho baseline-048", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 048\n" + } + ] + } + }, + { + "id": "paragraph_perf_049", + "title": "Baseline paragraph 049", + "text": "%sh\necho baseline-049", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 049\n" + } + ] + } + }, + { + "id": "paragraph_perf_050", + "title": "Baseline paragraph 050", + "text": "%sh\necho baseline-050", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 050\n" + } + ] + } + }, + { + "id": "paragraph_perf_051", + "title": "Baseline paragraph 051", + "text": "%sh\necho baseline-051", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 051\n" + } + ] + } + }, + { + "id": "paragraph_perf_052", + "title": "Baseline paragraph 052", + "text": "%sh\necho baseline-052", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 052\n" + } + ] + } + }, + { + "id": "paragraph_perf_053", + "title": "Baseline paragraph 053", + "text": "%sh\necho baseline-053", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 053\n" + } + ] + } + }, + { + "id": "paragraph_perf_054", + "title": "Baseline paragraph 054", + "text": "%sh\necho baseline-054", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 054\n" + } + ] + } + }, + { + "id": "paragraph_perf_055", + "title": "Baseline paragraph 055", + "text": "%sh\necho baseline-055", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 055\n" + } + ] + } + }, + { + "id": "paragraph_perf_056", + "title": "Baseline paragraph 056", + "text": "%sh\necho baseline-056", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 056\n" + } + ] + } + }, + { + "id": "paragraph_perf_057", + "title": "Baseline paragraph 057", + "text": "%sh\necho baseline-057", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 057\n" + } + ] + } + }, + { + "id": "paragraph_perf_058", + "title": "Baseline paragraph 058", + "text": "%sh\necho baseline-058", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 058\n" + } + ] + } + }, + { + "id": "paragraph_perf_059", + "title": "Baseline paragraph 059", + "text": "%sh\necho baseline-059", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 059\n" + } + ] + } + }, + { + "id": "paragraph_perf_060", + "title": "Baseline paragraph 060", + "text": "%sh\necho baseline-060", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 060\n" + } + ] + } + }, + { + "id": "paragraph_perf_061", + "title": "Baseline paragraph 061", + "text": "%sh\necho baseline-061", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 061\n" + } + ] + } + }, + { + "id": "paragraph_perf_062", + "title": "Baseline paragraph 062", + "text": "%sh\necho baseline-062", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 062\n" + } + ] + } + }, + { + "id": "paragraph_perf_063", + "title": "Baseline paragraph 063", + "text": "%sh\necho baseline-063", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 063\n" + } + ] + } + }, + { + "id": "paragraph_perf_064", + "title": "Baseline paragraph 064", + "text": "%sh\necho baseline-064", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 064\n" + } + ] + } + }, + { + "id": "paragraph_perf_065", + "title": "Baseline paragraph 065", + "text": "%sh\necho baseline-065", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 065\n" + } + ] + } + }, + { + "id": "paragraph_perf_066", + "title": "Baseline paragraph 066", + "text": "%sh\necho baseline-066", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 066\n" + } + ] + } + }, + { + "id": "paragraph_perf_067", + "title": "Baseline paragraph 067", + "text": "%sh\necho baseline-067", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 067\n" + } + ] + } + }, + { + "id": "paragraph_perf_068", + "title": "Baseline paragraph 068", + "text": "%sh\necho baseline-068", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 068\n" + } + ] + } + }, + { + "id": "paragraph_perf_069", + "title": "Baseline paragraph 069", + "text": "%sh\necho baseline-069", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 069\n" + } + ] + } + }, + { + "id": "paragraph_perf_070", + "title": "Baseline paragraph 070", + "text": "%sh\necho baseline-070", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 070\n" + } + ] + } + }, + { + "id": "paragraph_perf_071", + "title": "Baseline paragraph 071", + "text": "%sh\necho baseline-071", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 071\n" + } + ] + } + }, + { + "id": "paragraph_perf_072", + "title": "Baseline paragraph 072", + "text": "%sh\necho baseline-072", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 072\n" + } + ] + } + }, + { + "id": "paragraph_perf_073", + "title": "Baseline paragraph 073", + "text": "%sh\necho baseline-073", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 073\n" + } + ] + } + }, + { + "id": "paragraph_perf_074", + "title": "Baseline paragraph 074", + "text": "%sh\necho baseline-074", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 074\n" + } + ] + } + }, + { + "id": "paragraph_perf_075", + "title": "Baseline paragraph 075", + "text": "%sh\necho baseline-075", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 075\n" + } + ] + } + }, + { + "id": "paragraph_perf_076", + "title": "Baseline paragraph 076", + "text": "%sh\necho baseline-076", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 076\n" + } + ] + } + }, + { + "id": "paragraph_perf_077", + "title": "Baseline paragraph 077", + "text": "%sh\necho baseline-077", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 077\n" + } + ] + } + }, + { + "id": "paragraph_perf_078", + "title": "Baseline paragraph 078", + "text": "%sh\necho baseline-078", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 078\n" + } + ] + } + }, + { + "id": "paragraph_perf_079", + "title": "Baseline paragraph 079", + "text": "%sh\necho baseline-079", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 079\n" + } + ] + } + }, + { + "id": "paragraph_perf_080", + "title": "Baseline paragraph 080", + "text": "%sh\necho baseline-080", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "Idle text result 080\n" + } + ] + } + }, + { + "id": "paragraph_perf_081", + "title": "Baseline paragraph 081", + "text": "%sh\necho baseline-081", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_082", + "title": "Baseline paragraph 082", + "text": "%sh\necho baseline-082", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_083", + "title": "Baseline paragraph 083", + "text": "%sh\necho baseline-083", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_084", + "title": "Baseline paragraph 084", + "text": "%sh\necho baseline-084", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_085", + "title": "Baseline paragraph 085", + "text": "%sh\necho baseline-085", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_086", + "title": "Baseline paragraph 086", + "text": "%sh\necho baseline-086", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_087", + "title": "Baseline paragraph 087", + "text": "%sh\necho baseline-087", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_088", + "title": "Baseline paragraph 088", + "text": "%sh\necho baseline-088", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_089", + "title": "Baseline paragraph 089", + "text": "%sh\necho baseline-089", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_090", + "title": "Baseline paragraph 090", + "text": "%sh\necho baseline-090", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": false, + "tableHide": false, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {}, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "key\tvalue\nalpha\t1\nbeta\t2\ngamma\t3\n" + } + ] + } + }, + { + "id": "paragraph_perf_091", + "title": "Baseline paragraph 091", + "text": "%sh\necho baseline-091", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_092", + "title": "Baseline paragraph 092", + "text": "%sh\necho baseline-092", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_093", + "title": "Baseline paragraph 093", + "text": "%sh\necho baseline-093", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_094", + "title": "Baseline paragraph 094", + "text": "%sh\necho baseline-094", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_095", + "title": "Baseline paragraph 095", + "text": "%sh\necho baseline-095", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_096", + "title": "Baseline paragraph 096", + "text": "%sh\necho baseline-096", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_097", + "title": "Baseline paragraph 097", + "text": "%sh\necho baseline-097", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_098", + "title": "Baseline paragraph 098", + "text": "%sh\necho baseline-098", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_099", + "title": "Baseline paragraph 099", + "text": "%sh\necho baseline-099", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + }, + { + "id": "paragraph_perf_100", + "title": "Baseline paragraph 100", + "text": "%sh\necho baseline-100", + "user": "anonymous", + "status": "READY", + "config": { + "colWidth": 12, + "fontSize": 9, + "enabled": true, + "editorHide": true, + "tableHide": true, + "title": false, + "editorSetting": { + "language": "sh", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "runtimeInfos": {} + } + ], + "config": { + "isZeppelinNotebook": true + }, + "info": {} +} diff --git a/zeppelin-web-angular/e2e/models/notebook-performance-page.ts b/zeppelin-web-angular/e2e/models/notebook-performance-page.ts new file mode 100644 index 00000000000..5b2ba38faa8 --- /dev/null +++ b/zeppelin-web-angular/e2e/models/notebook-performance-page.ts @@ -0,0 +1,66 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Page } from '@playwright/test'; + +// JUSTIFIED: This fixed Angular baseline measures existing hosts and Monaco attachment, +// not a cross-framework user flow; these elements have no accessible role or test ID. +const selectors = { + actionBar: 'zeppelin-notebook-action-bar', + paragraphs: 'zeppelin-notebook-paragraph', + editor: '.monaco-editor' +}; + +export class NotebookPerformancePage { + constructor(private readonly page: Page) {} + + async measureReady() { + // JUSTIFIED: Evaluate the three readiness signals together on the browser clock; + // separate host-side assertions would add polling/IPC delay to the measured time. + const ready = await this.page.waitForFunction( + ({ actionBar, paragraphs, editor }) => { + const bar = document.querySelector(actionBar); + const style = bar && getComputedStyle(bar); + if ( + !bar || + !bar.getClientRects().length || + style?.visibility === 'hidden' || + style?.display === 'none' || + document.querySelectorAll(paragraphs).length !== 100 || + !document.querySelector(`${paragraphs} ${editor}`) + ) { + return false; + } + return performance.now(); + }, + selectors, + { timeout: 60000, polling: 'raf' } + ); + const notebookReadyMs = (await ready.jsonValue()) as number; + await ready.dispose(); + // Post-measurement sanity check of the ready condition; timing comes from the in-page wait above. + await expect(this.page.locator(selectors.actionBar)).toBeVisible(); + await expect(this.page.locator(selectors.paragraphs)).toHaveCount(100); + // JUSTIFIED: The benchmark explicitly requires the first Monaco editor to be attached. + await expect(this.page.locator(`${selectors.paragraphs} ${selectors.editor}`).first()).toBeAttached(); + const paint = await this.page.waitForFunction( + () => { + return performance.getEntriesByName('first-contentful-paint')[0]?.startTime || false; + }, + undefined, + { timeout: 10000 } + ); + const fcpMs = (await paint.jsonValue()) as number; + await paint.dispose(); + return { notebookReadyMs, fcpMs }; + } +} diff --git a/zeppelin-web-angular/e2e/performance/README.md b/zeppelin-web-angular/e2e/performance/README.md new file mode 100644 index 00000000000..f1f8b70e0d7 --- /dev/null +++ b/zeppelin-web-angular/e2e/performance/README.md @@ -0,0 +1,49 @@ + + +# Notebook route benchmark contract + +ZEPPELIN-6668 defines the fixture and measurement format. It does not establish a pinned Angular baseline. Generated JSON is ignored by Git. + +Build with `npm run build`, then serve `dist/zeppelin` with an isolated local Zeppelin backend. The benchmark imports one note and deletes that note in cleanup. Do not point it at a shared notebook store. It checks the served index's entry script list and the served entry asset hashes against the local build before importing the fixture; server-injected inline markup does not affect this check. The normal E2E suite does not run this benchmark; no development server is started by its config. Each measured navigation's response is checked again after recording readiness, before accepting the sample, so validation does not delay the measured ready time. + +To serve the fresh build, start Zeppelin from this source tree after `npm run build`. In `zeppelin-server`'s `ZeppelinConfiguration`, `zeppelin.default.ui` defaults to `new` and `zeppelin.angular.war` defaults to `zeppelin-web-angular/dist/zeppelin`, so the benchmark requests that `dist` at `/` unless either property is overridden. Use `localhost` in `PLAYWRIGHT_BASE_URL`: unless `zeppelin.server.allowed.origins` is set, the server accepts a WebSocket origin only from `localhost` or its own host name, so a `127.0.0.1` origin never loads the note. + +`playwright.performance.config.js` intentionally throws when `PLAYWRIGHT_BASE_URL` or `PERF_NOTEBOOK_DISPOSABLE=1` is missing, so `npx playwright test --list --config playwright.performance.config.js` needs them too. + +```sh +# From zeppelin-web-angular, with the built application served at this origin: +PLAYWRIGHT_BASE_URL=http://localhost:8080 \ + PERF_NOTEBOOK_DISPOSABLE=1 \ + npm run perf:notebook-baseline + +# Contract validation only: one cold and one warm sample, plus an unrecorded prime. +PLAYWRIGHT_BASE_URL=http://localhost:8080 \ + PERF_NOTEBOOK_DISPOSABLE=1 \ + PERF_NOTEBOOK_DRY_RUN=1 \ + npm run perf:notebook-baseline +``` + +The standard Chromium project and its automatic authentication setup are reused. Traces, screenshots, video, retries, parallel workers and service workers are disabled for measurement. Measurement contexts inherit the project's viewport, user agent, device scale factor, mobile/touch, locale, timezone, color scheme, permissions, HTTPS error and extra HTTP header options. Each cold run uses a new browser context (empty HTTP cache). Warm runs reuse one context/page after one unrecorded priming navigation; each run performs a full document navigation. OS/server caches are not flushed. The default is 10 cold samples followed by 10 warm samples, with no outlier removal. + +The fixture is `../fixtures/performance/notebook-route-100-paragraphs.json`: 80 idle TEXT-result paragraphs, 10 idle TABLE-result paragraphs, and 10 collapsed code paragraphs, all in READY status; note import resets paragraph status to READY. No interpreter executes. The pinned `fixtureSha256` constant in `notebook-baseline.ts` is checked before import, and the composition is validated. A deliberate fixture revision must update that constant and be reviewed as a benchmark contract change. + +`notebookReadyMs` is the browser's `performance.now()` when the action bar is visible, exactly 100 paragraph hosts are attached, and the first Monaco editor is attached, checked together once per animation frame, so it has roughly one-frame (about 16 ms at 60 Hz) resolution. It is relative to that document's navigation start, not the preceding import. `fcpMs` is the browser `first-contentful-paint` Performance entry. Missing readiness or FCP fails the run; there is no timeout fallback metric. + +Outputs are `baselines/.raw.json` and `.summary.json`. Both contain schema version, run ID/time, dry-run flag, Zeppelin commit and dirty-tree flag, OS/release, CPU model, physical memory bytes, browser/Node versions, build command, fixture path/SHA-256, base URL, viewport, run counts and bundle measurements. Raw samples contain `cache` (`cold` or `warm`), one-based `run`, `notebookReadyMs` and `fcpMs`. Summary groups each metric by cache mode with count, median and nearest-rank p95 (`ceil(0.95 * n)`); an even sample count uses the two middle values' mean for the median. With 10 runs, p95 is the slowest run. A dry run is schema evidence, not a baseline. Outputs are git-ignored; add a recorded baseline with `git add -f`. `buildCommand` records the documented build command; it is not verified. The measured build is identified by the recorded bundle SHA-256 values, which are checked against the served index and entry assets before measurement. + +`bundles.angularEntryChunks` lists JavaScript entry scripts from the built Angular `index.html`. `bundles.reactRemoteEntry` measures the separately served `assets/react/remoteEntry.js`. Each file records relative path, SHA-256, raw bytes and gzip bytes. These are entry asset measurements, not the whole `dist` tree or a claim about the complete notebook route's lazy-loaded bundle size. + +Focused static checks: `npm run test:shell -- test/notebook-baseline.spec.ts` and `npx eslint e2e/performance/*.ts e2e/models/notebook-performance-page.ts`. diff --git a/zeppelin-web-angular/e2e/performance/notebook-baseline.ts b/zeppelin-web-angular/e2e/performance/notebook-baseline.ts new file mode 100644 index 00000000000..f027332f5e6 --- /dev/null +++ b/zeppelin-web-angular/e2e/performance/notebook-baseline.ts @@ -0,0 +1,135 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import { resolve, relative } from 'node:path'; +import { gzipSync } from 'node:zlib'; + +export const fixturePath = 'e2e/fixtures/performance/notebook-route-100-paragraphs.json'; +const fixtureSha256 = '7f94de1f9a7e529c7baf473a8bba9ab017f410c896f21bd8357922b63bd81fde'; +export type Sample = { cache: 'cold' | 'warm'; run: number; notebookReadyMs: number; fcpMs: number }; + +export const normalizeBundlePath = (path: string): string => path.replace(/\\/g, '/'); + +export const loadFixture = (root: string) => { + const bytes = readFileSync(resolve(root, fixturePath)); + const sha256 = createHash('sha256').update(bytes).digest('hex'); + if (sha256 !== fixtureSha256) { + throw new Error('Benchmark fixture SHA-256 mismatch'); + } + const note = JSON.parse(bytes.toString('utf8')); + validateFixture(note); + return { note, sha256 }; +}; + +export const validateFixture = (note: { + paragraphs: Array<{ + id: string; + status: string; + config: { editorHide: boolean; tableHide: boolean }; + results?: { code: string; msg: Array<{ type: string; data: string }> }; + }>; +}): void => { + const paragraphs = note.paragraphs; + if (!Array.isArray(paragraphs) || paragraphs.length !== 100 || new Set(paragraphs.map(p => p.id)).size !== 100) { + throw new Error('Benchmark fixture requires 100 distinct paragraphs'); + } + paragraphs.forEach((p, index) => { + const collapsed = index >= 90; + const result = p.results?.msg; + if ( + p.config.editorHide !== collapsed || + p.config.tableHide !== collapsed || + p.status !== 'READY' || + (collapsed + ? p.results !== undefined + : p.results?.code !== 'SUCCESS' || + result?.length !== 1 || + result[0].type !== (index < 80 ? 'TEXT' : 'TABLE') || + !result[0].data) + ) { + throw new Error( + `Benchmark fixture paragraph ${index + 1} violates the 80 text / 10 table / 10 collapsed contract` + ); + } + }); +}; + +export const summarize = (samples: Sample[], runs: number) => { + return Object.fromEntries( + (['cold', 'warm'] as const).map(cache => { + const group = samples.filter(sample => sample.cache === cache); + if (group.length !== runs || group.some((sample, index) => sample.run !== index + 1)) { + throw new Error(`Expected exactly ${runs} ordered ${cache} samples`); + } + const metrics = Object.fromEntries( + (['notebookReadyMs', 'fcpMs'] as const).map(metric => { + const values = group.map(sample => sample[metric]).sort((a, b) => a - b); + if (values.some(value => !Number.isFinite(value) || value <= 0)) { + throw new Error(`Missing or invalid ${metric}`); + } + const middle = Math.floor(values.length / 2); + return [ + metric, + { + median: values.length % 2 ? values[middle] : (values[middle - 1] + values[middle]) / 2, + p95: values[Math.ceil(values.length * 0.95) - 1] + } + ]; + }) + ); + return [cache, { count: group.length, ...metrics }]; + }) + ); +}; + +const angularEntryScripts = (index: string): string[] => { + const scripts = [...index.matchAll(/]*\bsrc=["']([^"']+)["'][^>]*>/gi)].map(match => match[1]); + if (!scripts.length || !scripts.some(script => /^main[.-].*\.js$/.test(script))) { + throw new Error( + 'Build output must contain a hashed Angular main entry script; run the production build (npm run build)' + ); + } + for (const script of scripts) { + if (!/^[\w.-]+\.js$/.test(script)) { + throw new Error(`Unexpected Angular entry script: ${script}`); + } + } + return scripts; +}; + +export const validateServedIndex = (root: string, servedIndex: string): void => { + const expected = angularEntryScripts(readFileSync(resolve(root, 'dist/zeppelin/index.html'), 'utf8')); + const actual = angularEntryScripts(servedIndex); + if (JSON.stringify(actual) !== JSON.stringify(expected)) { + throw new Error(`Served Angular entry scripts do not match the local build: ${JSON.stringify(actual)}`); + } +}; + +export const measureBundles = (root: string) => { + const angularRoot = resolve(root, 'dist/zeppelin'); + const scripts = angularEntryScripts(readFileSync(resolve(angularRoot, 'index.html'), 'utf8')); + const measure = (path: string) => { + const bytes = readFileSync(path); + return { + path: normalizeBundlePath(relative(root, path)), + rawBytes: bytes.length, + gzipBytes: gzipSync(bytes).length, + sha256: createHash('sha256').update(bytes).digest('hex') + }; + }; + const angularEntryChunks = [...new Set(scripts)].map(script => { + return measure(resolve(angularRoot, script)); + }); + return { angularEntryChunks, reactRemoteEntry: measure(resolve(angularRoot, 'assets/react/remoteEntry.js')) }; +}; diff --git a/zeppelin-web-angular/e2e/performance/notebook-route-baseline.spec.ts b/zeppelin-web-angular/e2e/performance/notebook-route-baseline.spec.ts new file mode 100644 index 00000000000..de07da0d104 --- /dev/null +++ b/zeppelin-web-angular/e2e/performance/notebook-route-baseline.spec.ts @@ -0,0 +1,184 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { execFileSync } from 'node:child_process'; +import { createHash, randomUUID } from 'node:crypto'; +import { mkdirSync, writeFileSync } from 'node:fs'; +import { cpus, platform, release, totalmem } from 'node:os'; +import { resolve } from 'node:path'; +import { expect, test, BrowserContextOptions, Page } from '@playwright/test'; +import { NotebookPerformancePage } from '../models/notebook-performance-page'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../utils'; +import { + fixturePath, + loadFixture, + measureBundles, + Sample, + summarize, + validateFixture, + validateServedIndex +} from './notebook-baseline'; + +const inheritedContextOptions = [ + 'viewport', + 'userAgent', + 'deviceScaleFactor', + 'isMobile', + 'hasTouch', + 'locale', + 'timezoneId', + 'colorScheme', + 'permissions', + 'ignoreHTTPSErrors', + 'extraHTTPHeaders' +] as const; + +// JUSTIFIED: The issue fixes this path outside tests/; the dedicated config isolates +// the benchmark from normal E2E runs and owns the deliberate cold/warm sequence. +test.describe('Notebook route performance contract', () => { + addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK); + + let importedNoteId: string | undefined; + + test.afterEach(async ({ request }) => { + const noteId = importedNoteId; + importedNoteId = undefined; + if (!noteId) { + return; + } + try { + const deleted = await request.delete(`/api/notebook/${encodeURIComponent(noteId)}`); + if (!deleted.ok()) { + console.warn(`Benchmark note ${noteId} was not deleted (${deleted.status()}): ${await deleted.text()}`); + } + } catch (error) { + console.warn(`Benchmark note ${noteId} was not deleted: ${error}`); + } + }); + + test('records every cold and warm sample with readiness, FCP and build metadata', async ({ + browser, + request, + baseURL + }, testInfo) => { + const root = resolve(__dirname, '../..'); + const { note, sha256 } = loadFixture(root); + const bundles = measureBundles(root); + const dryRun = process.env.PERF_NOTEBOOK_DRY_RUN === '1'; + const runs = dryRun ? 1 : 10; + const runId = randomUUID(); + const metadata = { + schemaVersion: 1, + runId, + generatedAt: new Date().toISOString(), + dryRun, + zeppelinCommit: execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' }).trim(), + workingTreeDirty: + execFileSync('git', ['status', '--porcelain'], { cwd: root, encoding: 'utf8' }).trim().length > 0, + os: { platform: platform(), release: release() }, + cpuModel: cpus()[0]?.model ?? 'unknown', + memoryBytes: totalmem(), + browserVersion: browser.version(), + nodeVersion: process.version, + buildCommand: 'npm run build', + fixture: { path: fixturePath, sha256 }, + baseURL, + viewport: testInfo.project.use.viewport, + runsPerCache: runs, + warmPrimingNavigations: 1, + percentileMethod: 'nearest-rank', + bundles + }; + + await test.step('Given the built assets and the fixed imported note', async () => { + const index = await request.get('/'); + expect(index.ok()).toBe(true); + validateServedIndex(root, await index.text()); + for (const bundle of [...bundles.angularEntryChunks, bundles.reactRemoteEntry]) { + const response = await request.get(`/${bundle.path.replace('dist/zeppelin/', '')}`); + expect(response.ok()).toBe(true); + expect( + createHash('sha256') + .update(await response.body()) + .digest('hex') + ).toBe(bundle.sha256); + } + }); + + const imported = await request.post('/api/notebook/import', { + params: { notePath: `/__performance__/${runId}` }, + data: note + }); + expect(imported.ok(), `Notebook import failed (${imported.status()}): ${await imported.text()}`).toBe(true); + const noteId = (await imported.json()).body; + expect(typeof noteId).toBe('string'); + expect(noteId.length).toBeGreaterThan(0); + importedNoteId = noteId; + const samples: Sample[] = []; + const { use } = testInfo.project; + const contextOptions: BrowserContextOptions = { + ...Object.fromEntries(inheritedContextOptions.map(key => [key, use[key]])), + baseURL, + // browser.newContext resolves a relative storage state path against the process cwd, not the config. + storageState: typeof use.storageState === 'string' ? resolve(root, use.storageState) : use.storageState, + serviceWorkers: 'block' + }; + const navigate = async (page: Page) => { + await page.goto('about:blank'); + const navigation = await page.goto(`/#/notebook/${encodeURIComponent(noteId)}`, { waitUntil: 'commit' }); + const metrics = await new NotebookPerformancePage(page).measureReady(); + if (!navigation) { + throw new Error('The benchmark requires a full document navigation response'); + } + validateServedIndex(root, await navigation.text()); + await waitForZeppelinReady(page); + return metrics; + }; + const persisted = await request.get(`/api/notebook/${encodeURIComponent(noteId)}`); + expect(persisted.ok()).toBe(true); + validateFixture((await persisted.json()).body); + + await test.step('When each cold navigation uses a new context with an empty HTTP cache', async () => { + for (let run = 1; run <= runs; run++) { + const context = await browser.newContext(contextOptions); + try { + samples.push({ cache: 'cold', run, ...(await navigate(await context.newPage())) }); + } finally { + await context.close(); + } + } + }); + + await test.step('When warm navigations reuse one context after one unrecorded prime', async () => { + const context = await browser.newContext(contextOptions); + try { + const page = await context.newPage(); + await navigate(page); + for (let run = 1; run <= runs; run++) { + samples.push({ cache: 'warm', run, ...(await navigate(page)) }); + } + } finally { + await context.close(); + } + }); + + await test.step('Then raw samples and median/p95 retain every measurement', async () => { + expect(samples).toHaveLength(runs * 2); + const summary = summarize(samples, runs); + const output = resolve(root, 'e2e/performance/baselines'); + mkdirSync(output, { recursive: true }); + writeFileSync(resolve(output, `${runId}.raw.json`), `${JSON.stringify({ ...metadata, samples }, null, 2)}\n`); + writeFileSync(resolve(output, `${runId}.summary.json`), `${JSON.stringify({ ...metadata, summary }, null, 2)}\n`); + console.log(`Benchmark outputs: e2e/performance/baselines/${runId}.{raw,summary}.json`); + }); + }); +}); diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index c5e994ea0ae..87234f95c15 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -32,6 +32,7 @@ "check:core-contract-server": "node --test e2e/core-contract/capture-server.test.mjs", "e2e:core-contract": "playwright test --config playwright.core-contract.config.js --project=chromium", "e2e:core-contract:live": "cross-env ZEPPELIN_E2E_LIVE_CAPTURE=1 playwright test --config playwright.core-contract.config.js --project=chromium", + "perf:notebook-baseline": "playwright test --config playwright.performance.config.js --project chromium", "e2e:fast": "playwright test --project=chromium", "e2e:classic": "playwright test --config playwright.classic.config.js", "e2e:ui": "playwright test --ui", diff --git a/zeppelin-web-angular/playwright.config.js b/zeppelin-web-angular/playwright.config.js index bc4a0112613..e8ee9a11bb7 100644 --- a/zeppelin-web-angular/playwright.config.js +++ b/zeppelin-web-angular/playwright.config.js @@ -19,8 +19,8 @@ process.env.PLAYWRIGHT_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || defaultBase // https://playwright.dev/docs/test-configuration module.exports = defineConfig({ ...baseConfig, - // Classic specs have their own config; Node fixture tests must stay outside Playwright. - testIgnore: [/tests\/classic\/.*\.spec\.ts/, /core-contract\/.*\.test\.mjs/], + // Classic, core-contract, and performance specs have their own runners. + testIgnore: [/tests\/classic\/.*\.spec\.ts/, /core-contract\/.*\.test\.mjs/, /e2e\/performance\/.*\.spec\.ts$/], // Live captures run only through playwright.core-contract.config.js. grepInvert: /@live/, reporter: [ diff --git a/zeppelin-web-angular/playwright.performance.config.js b/zeppelin-web-angular/playwright.performance.config.js new file mode 100644 index 00000000000..05996c61c94 --- /dev/null +++ b/zeppelin-web-angular/playwright.performance.config.js @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { defineConfig } = require('@playwright/test'); +const baseURL = process.env.PLAYWRIGHT_BASE_URL; +if (!baseURL || process.env.PERF_NOTEBOOK_DISPOSABLE !== '1') { + throw new Error('Set PLAYWRIGHT_BASE_URL and PERF_NOTEBOOK_DISPOSABLE=1 for an isolated local Zeppelin backend'); +} +const target = new URL(baseURL); +if ( + !['localhost', '127.0.0.1', '[::1]'].includes(target.hostname) || + target.protocol !== 'http:' || + target.username || + target.password || + target.search || + target.hash || + // Root deployment only: the spec requests '/' and bundle paths relative to the origin. + target.pathname !== '/' +) { + throw new Error('The benchmark requires an explicit loopback HTTP origin serving npm run build output'); +} +const standard = require('./playwright.config'); +module.exports = defineConfig({ + ...standard, + testMatch: /performance\/notebook-route-baseline\.spec\.ts/, + testIgnore: [], + globalSetup: undefined, + globalTeardown: undefined, + webServer: undefined, + fullyParallel: false, + workers: 1, + retries: 0, + timeout: 30 * 60 * 1000, + reporter: 'list', + use: { ...standard.use, trace: 'off', video: 'off', screenshot: 'off', serviceWorkers: 'block' }, + projects: standard.projects.filter(project => ['setup', 'chromium'].includes(project.name)) +}); diff --git a/zeppelin-web-angular/test/notebook-baseline.spec.ts b/zeppelin-web-angular/test/notebook-baseline.spec.ts new file mode 100644 index 00000000000..0172f60aea3 --- /dev/null +++ b/zeppelin-web-angular/test/notebook-baseline.spec.ts @@ -0,0 +1,151 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, resolve } from 'node:path'; +import { afterEach, describe, expect, it } from 'vitest'; +import { + fixturePath, + loadFixture, + measureBundles, + normalizeBundlePath, + Sample, + summarize, + validateFixture, + validateServedIndex +} from '../e2e/performance/notebook-baseline'; + +describe('Notebook benchmark contract', () => { + const temporaryRoots: string[] = []; + const tempRoot = () => { + const root = mkdtempSync(resolve(tmpdir(), 'zeppelin-perf-contract-')); + temporaryRoots.push(root); + return root; + }; + afterEach(() => temporaryRoots.splice(0).forEach(root => rmSync(root, { recursive: true, force: true }))); + + it('normalizes native Windows bundle paths for browser requests', () => { + expect(normalizeBundlePath('dist\\zeppelin\\assets\\react\\remoteEntry.js')).toBe( + 'dist/zeppelin/assets/react/remoteEntry.js' + ); + }); + + it('accepts the versioned fixture and rejects changed bytes against its committed hash', () => { + const { note } = loadFixture(process.cwd()); + expect(note.paragraphs).toHaveLength(100); + expect(new Set(note.paragraphs.map((paragraph: { status: string }) => paragraph.status))).toEqual( + new Set(['READY']) + ); + const root = tempRoot(); + mkdirSync(dirname(resolve(root, fixturePath)), { recursive: true }); + writeFileSync(resolve(root, fixturePath), `${readFileSync(fixturePath, 'utf8')}\n`); + expect(() => loadFixture(root)).toThrow('SHA-256 mismatch'); + }); + + it.each(['missing', 'duplicate', 'result', 'expanded', 'running'])( + 'rejects the %s fixture contract mutation', + mutation => { + const { note } = loadFixture(process.cwd()); + if (mutation === 'missing') note.paragraphs.pop(); + if (mutation === 'duplicate') note.paragraphs[1].id = note.paragraphs[0].id; + if (mutation === 'result') note.paragraphs[80].results.msg[0].type = 'TEXT'; + if (mutation === 'expanded') note.paragraphs[90].config.editorHide = false; + if (mutation === 'running') note.paragraphs[0].status = 'RUNNING'; + expect(() => validateFixture(note)).toThrow('Benchmark fixture'); + } + ); + + it('retains the outlier and computes median and nearest-rank p95 separately by cache mode', () => { + const samples: Sample[] = (['cold', 'warm'] as const).flatMap(cache => + Array.from({ length: 10 }, (_, index) => ({ + cache, + run: index + 1, + notebookReadyMs: index === 9 ? 1000 : index + 1, + fcpMs: index + 1 + })) + ); + expect(summarize(samples, 10)).toEqual({ + cold: { count: 10, notebookReadyMs: { median: 5.5, p95: 1000 }, fcpMs: { median: 5.5, p95: 10 } }, + warm: { count: 10, notebookReadyMs: { median: 5.5, p95: 1000 }, fcpMs: { median: 5.5, p95: 10 } } + }); + expect(samples).toHaveLength(20); + }); + + it('distinguishes nearest-rank p95 from the max and from interpolation at n=20', () => { + const samples: Sample[] = (['cold', 'warm'] as const).flatMap(cache => + Array.from({ length: 20 }, (_, index) => ({ + cache, + run: index + 1, + notebookReadyMs: (index + 1) * 10, + fcpMs: index + 1 + })) + ); + expect(summarize(samples, 20).cold).toEqual({ + count: 20, + notebookReadyMs: { median: 105, p95: 190 }, + fcpMs: { median: 10.5, p95: 19 } + }); + }); + + it('rejects a missing run or metric instead of publishing an incomplete summary', () => { + const cold: Sample = { cache: 'cold', run: 1, notebookReadyMs: 10, fcpMs: 5 }; + expect(() => summarize([cold], 1)).toThrow('warm samples'); + expect(() => summarize([cold, { ...cold, cache: 'warm', fcpMs: NaN }], 1)).toThrow('Missing or invalid fcpMs'); + expect(summarize([cold, { ...cold, cache: 'warm' }], 1).cold).toEqual({ + count: 1, + notebookReadyMs: { median: 10, p95: 10 }, + fcpMs: { median: 5, p95: 5 } + }); + }); + + it('rejects an old served index even when both builds remain available, while allowing server-injected markup', () => { + const root = tempRoot(); + const dist = resolve(root, 'dist/zeppelin'); + mkdirSync(dist, { recursive: true }); + const current = ''; + writeFileSync(resolve(dist, 'index.html'), current); + for (const name of ['runtime.new.js', 'main.new.js', 'runtime.old.js', 'main.old.js']) { + writeFileSync(resolve(dist, name), name); + } + expect(() => validateServedIndex(root, current.replace(/\.new\.js/g, '.old.js'))).toThrow( + 'Served Angular entry scripts do not match the local build' + ); + expect(() => + validateServedIndex(root, `${current}`) + ).not.toThrow(); + }); + + it('measures only Angular index entry scripts and the separate React entry, and fails if the latter is missing', () => { + const root = tempRoot(); + const dist = resolve(root, 'dist/zeppelin'); + mkdirSync(resolve(dist, 'assets/react'), { recursive: true }); + writeFileSync( + resolve(dist, 'index.html'), + '' + ); + writeFileSync(resolve(dist, 'runtime.abc.js'), 'runtime'); + writeFileSync(resolve(dist, 'main.abc.js'), 'application'); + writeFileSync(resolve(dist, 'lazy.js'), 'unrelated lazy chunk'); + writeFileSync(resolve(dist, 'assets/react/remoteEntry.js'), 'remote'); + const result = measureBundles(root); + expect(result.angularEntryChunks.map(chunk => chunk.path)).toEqual([ + 'dist/zeppelin/runtime.abc.js', + 'dist/zeppelin/main.abc.js' + ]); + expect(result.angularEntryChunks.map(chunk => chunk.rawBytes)).toEqual([7, 11]); + expect(result.reactRemoteEntry.rawBytes).toBe(6); + expect(result.reactRemoteEntry.gzipBytes).toBeGreaterThan(0); + rmSync(resolve(dist, 'assets/react/remoteEntry.js')); + expect(() => measureBundles(root)).toThrow(); + }); +});