Skip to content

Run the ESQL test suites on Windows in CI - #881

Open
yutaro-sakamoto wants to merge 8 commits into
opensourcecobol:developfrom
yutaro-sakamoto:windows-esql-test-upstream
Open

yutaro-sakamoto wants to merge 8 commits into
opensourcecobol:developfrom
yutaro-sakamoto:windows-esql-test-upstream

Conversation

@yutaro-sakamoto

Copy link
Copy Markdown
Contributor

#862 の上に積んでいます。#862 がマージされるまで、このPRの差分にはそちらのコミットも含まれます。

概要 (日本語)

ESQL のテストスイートは Linux でしか CI で実行されていません。Windows 用のワークフロー .github/workflows/windows-test-esql.yml は ESQL サポートのマージ時から存在していますが、push.yml / pull-request.yml の側でコメントアウトされたままです。

動かなかった原因

1. cobj.exe が ESQL プログラムのコンパイル中に segfault していた。 develop の上でこのジョブを有効にすると、24 個のテストが cobj.exe のクラッシュで落ちます。コメントに残っていた「cobj.exe segfaults with the new esql-scanner」という推測とは異なり、原因は esql-scanner ではなく codegen.c の inside_check / inside_stack でした。ESQL のテストは -debug 付きで添字付きホスト変数を使うため、ほぼ全テストがこれを踏みます。#862 で修正済みのため、本PRはその上に積んでいます。

2. initdb がクラスタを作れていなかった。 --encoding=UTF8 を指定する一方でロケールを指定していませんでした。ランナーの既定ロケール English_United States.1252 は WIN1252 を要求するため、initdb はこの組み合わせを拒否します。--no-locale を渡し、どのエンコーディングとも両立する C ロケールでクラスタを作るようにしました。

3. esql-sqlca が 1 グループだけ失敗していた。 esql-sqlca.src/connect-disconnect.at はホスト部を持たない invalid というデータベースへ接続し、libcobj がそれを localhost:5432 の JDBC URL に変換した結果、接続が拒否されること (SQLCODE -402 / SQLSTATE 08001) を期待しています。Linux では PostgreSQL が別のサービスコンテナで動くためこれが成立しますが、Windows では同一マシン上にサーバがあるため接続がサーバまで届いてしまい、ロール invalid が存在しない認証エラー (SQLCODE -9999 / SQLSTATE 28000) になります。クラスタを 55432 番ポートで起動し、5432 番を空けたままにしています。

PostgreSQL の起動処理とDB接続情報の外出し

ワークフローに直接書くのではなく、いずれもファイルに切り出しました。CI 以外からも使えるようにするためです。

  • win/start-test-postgresql.ps1 — クラスタの初期化と起動を行います。CI 以外の Windows マシンでもそのまま使えるように、既存クラスタがあれば再利用し、-Stop で停止でき、ポート・データディレクトリ・データベース名・ロール名・PostgreSQL の場所をすべてパラメータにしてあります。--no-locale と既定以外のポートが必要な理由は、スクリプト冒頭のコメントに記録しました。
  • .github/workflows/db-settings/embed_db_info_windows.sh — 既存のコンテナ用スクリプトと同じ形式の Windows 版です。ワークフローはこれを tests/embed_db_info.sh にコピーします。接続情報の唯一の出どころとなるよう、start-test-postgresql.ps1 は既定のポート・データベース名・ロール名をこのファイルから読み取ります。

なお db-settings/ の embed_db_info_postgresql_15.sh / _9.6.sh は現状どこからも使われていません。Linux の ESQL ジョブは make dist の tar ボールから実行されて actions/checkout を行わず、tar ボールに .github/ が含まれないためです (同じ内容をワークフロー内で直接書き出しています)。Windows のジョブはリポジトリをチェックアウトするので、こちらは db-settings/ を使えます。

その他

  • initdb / pg_ctl / createdb の終了ステータスを確認し、失敗したらサーバログを出力します。
  • windows-test-other.yml と同じく、スイートごとに 1 ジョブへ分割しました。各ジョブが専用のクラスタを持つため、スイート同士が干渉しません。
  • tests/atlocal-win.env に RUN_MODULE_LOG を追加しました。tests/esql-misc.src/logging.at だけが使う変数ですが未定義だったため、コンパイル済みプログラムが java を伴わずに実行されていました。
  • esql-utf8 は対象外です。--enable-utf8 付きでコンフィグアしたコンパイラが必要ですが、Windows ビルドは Shift_JIS 専用のためです (他の UTF-8 スイートが Windows で実行されていないのと同じ理由です)。
  • サードパーティの GitHub Actions は追加していません。PostgreSQL の起動はすべて PowerShell で行っています。
  • 1 スイート内のグループは同じテーブル名を共有するため、スイート内は直列実行のままにしています。

Summary (English)

Stacked on #862; its commits appear in this diff until that one merges.

The ESQL suites only run in CI on Linux. .github/workflows/windows-test-esql.yml has existed since ESQL support was merged, but the job is still commented out in push.yml and pull-request.yml.

Why it did not work

1. cobj.exe segfaulted while compiling the ESQL programs. Enabling the job on develop fails 24 tests with a compiler crash. Contrary to the note left in the workflow ("cobj.exe segfaults with the new esql-scanner"), the cause is not the esql-scanner but the inside_check / inside_stack machinery in codegen.c: the ESQL tests compile with -debug and use subscripted host variables, so nearly all of them hit it. #862 fixes that, which is why this is stacked on it.

2. initdb never created a cluster. It asked for --encoding=UTF8 without naming a locale, which conflicts with the runner's default English_United States.1252 — that locale requires WIN1252, and initdb rejects the combination outright. Passing --no-locale creates the cluster with the C locale, which is compatible with every encoding.

3. One esql-sqlca group still failed. esql-sqlca.src/connect-disconnect.at connects to a database named invalid with no host part. libcobj turns that into a JDBC URL for localhost:5432, and the test expects the attempt to be refused (SQLCODE -402 / SQLSTATE 08001). On Linux that holds because PostgreSQL runs in a separate service container; on Windows the server is on the same machine, so the connection reached it and failed authentication instead, with the role invalid not existing (SQLCODE -9999 / SQLSTATE 28000). The cluster now listens on 55432, leaving 5432 closed.

Moving the setup out of the workflow

Both the PowerShell that brought PostgreSQL up and the heredoc that wrote embed_db_info.sh would have been inline in the workflow, where nothing outside CI can reach them. Both are files instead:

  • win/start-test-postgresql.ps1 initialises the cluster and starts it, and takes the same steps outside CI: it reuses a cluster it finds instead of failing, -Stop shuts the server down, and the port, cluster directory, database, role and PostgreSQL installation are all parameters. Its comment header records why --no-locale and the non-default port are required.
  • .github/workflows/db-settings/embed_db_info_windows.sh sits next to the scripts already there for the container hosts, and the workflow copies it into place. start-test-postgresql.ps1 reads its own default port, database and role out of that file, so it is the single source for the connection settings.

Note that db-settings/embed_db_info_postgresql_15.sh and _9.6.sh are currently unused: the Linux ESQL jobs run from the make dist tarball and never check the repository out, and .github/ is not part of the tarball, so they cannot read them and write the same content inline instead. The Windows job does check the repository out, so it can use db-settings/.

Also

  • Check the exit status of initdb / pg_ctl / createdb and print the server log when one of them fails.
  • Give each suite its own job, the way windows-test-other.yml does, so each suite gets a cluster to itself.
  • Define RUN_MODULE_LOG in tests/atlocal-win.env. Only tests/esql-misc.src/logging.at uses it, and it was missing, so that test ran the compiled program without a java command in front of it.
  • esql-utf8 is excluded: it needs a compiler configured with --enable-utf8 and the Windows build is Shift_JIS only, which is also why no other UTF-8 suite runs on Windows.
  • No third-party GitHub Actions were added; PostgreSQL is brought up entirely with PowerShell.
  • The groups of a suite share the tables they create, so each suite still runs its groups one at a time.

All jobs pass on this branch.

codegen.c kept the inside_check/inside_stack bookkeeping from the
original C code generator, but only the decrements survived the
rewrite to Java code generation: nothing ever increments inside_check.
On non-GCC builds (the MSVC-built cobj.exe) the counter goes negative
as soon as a runtime check is attached to a reference (-debug with a
variable subscript, reference modification or SEARCH ALL), and
inside_stack[inside_check - 1] then writes out of bounds, crashing the
compiler. GCC builds never compile these blocks, which is why Linux
was unaffected. Remove the machinery entirely: the generated Java
must not depend on the compiler that built cobj.

Un-skip the Windows tests that were failing due to this crash.

Fixes opensourcecobol#829, opensourcecobol#831, opensourcecobol#832, opensourcecobol#833, opensourcecobol#834 (sub-issues of opensourcecobol#828)
With -java-package the jar arguments were assembled as
package_dir + file_path_delimitor + class, mixing the '/' separators
from the package path with '\' on Windows (e.g. com/abc\prog.class),
which produces malformed entry names in the archive. The jar tool
accepts '/' everywhere, so join the paths with '/' unconditionally.

The class file cleanup after archiving had the opposite problem:
cmd.exe's del does not accept '/' separators. Build the remove paths
with the native separator, let cd handle the output directory, and
drop a leftover '#aaa' token that del would treat as an argument.

Un-skip the Windows jar test.

Fixes opensourcecobol#830 (sub-issue of opensourcecobol#828)
Removing the inside_check block exposed a variableScope finding for
'code' in joutput_stmt; declare it in the handler block where it is
used.
Every program in a translation unit becomes its own .java/.class file
named after the program ID, so two programs whose IDs differ only in
letter case overwrite each other's files on a case-insensitive
filesystem and the result silently misbehaves. On Windows, detect the
collision before code generation and fail with an explicit error.

The two affected tests stay skipped on Windows because the behavior
they exercise is impossible there by design; a new Windows-only test
verifies the diagnostic instead.

Fixes opensourcecobol#835 (sub-issue of opensourcecobol#828)
On case-insensitive file systems programs whose PROGRAM-IDs differ
only in letter case would generate class files with the same name;
cobj now reports a compile error there, so document the restriction
in the usage section.
* Use "cd /d" on Windows: cmd.exe's plain "cd" does not switch
  drives, so with -o pointing at another drive the jar and del
  commands would run against the wrong directory
* Replace the unbounded strcpy into package_dir_native with snprintf
  and give package_name_to_path an explicit output bound, so an
  overlong -java-package argument can no longer overflow the buffers
The Windows ESQL job has been present but commented out in push.yml and
pull-request.yml since the ESQL support was merged, because the workflow
could not bring up PostgreSQL on the runner.

initdb was called with --encoding=UTF8 while the runner's default locale
is English_United States.1252, and initdb rejects that combination
outright: the encoding a locale implies (WIN1252) has to match the one
asked for.  Pass --no-locale so the cluster is created with the C locale,
which is compatible with every encoding.  The suites only sort by numeric
columns and by values that are prefixes of each other, so the collation
that gives is fine, and lc_messages=C keeps the PostgreSQL error texts
esql-misc matches in English.

That alone is not enough.  esql-sqlca.src/connect-disconnect.at connects
to a database named "invalid" with no host part, which libcobj turns into
a JDBC URL for localhost:5432, and it expects the attempt to be refused
(SQLCODE -402 / SQLSTATE 08001).  On Linux that holds because PostgreSQL
runs in a separate service container; on Windows the server is on the
same machine, so the connection reaches it and fails authentication
instead, with the role "invalid" not existing (SQLCODE -9999 / SQLSTATE
28000).  The cluster therefore listens on 55432, leaving 5432 closed.

Rather than leaving any of this inline in the workflow, where nothing
outside CI can reach it:

- win/start-test-postgresql.ps1 initialises the cluster and starts it,
  and takes the same steps on a developer's own Windows machine: it
  reuses a cluster it finds instead of failing, -Stop shuts the server
  down, and the port, cluster directory, database, role and PostgreSQL
  installation are all parameters.  Its comment header records why
  --no-locale and the non-default port are required.
- .github/workflows/db-settings/embed_db_info_windows.sh joins the
  scripts already there for the container hosts, and the workflow copies
  it into place.  start-test-postgresql.ps1 reads its own default port,
  database and role out of that file, so the server and the compiled
  test programs cannot disagree.

Also:

- Check the exit status of initdb / pg_ctl / createdb and print the
  server log when one of them fails, instead of letting the job continue
  to the tests and fail there with a connection error.
- Give each suite its own job, the way windows-test-other.yml does, so a
  single suite can be re-run, and so that each suite gets a cluster to
  itself.
- Define RUN_MODULE_LOG in tests/atlocal-win.env.  Only
  tests/esql-misc.src/logging.at uses it, and it was missing, so that
  test ran the compiled program without a java command in front of it.
- Drop esql-utf8: it needs a compiler configured with --enable-utf8 and
  the Windows build is Shift_JIS only, which is also why no other UTF-8
  suite runs on Windows.
@yutaro-sakamoto
yutaro-sakamoto marked this pull request as ready for review August 8, 2026 12:49

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant