The Wayback Machine - https://web.archive.org/web/20200908052056/https://github.com/scala-js/scala-js/issues/4054
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty jsEnvInput causes freeze #4054

Closed
japgolly opened this issue May 19, 2020 · 15 comments
Closed

Empty jsEnvInput causes freeze #4054

japgolly opened this issue May 19, 2020 · 15 comments
Assignees
Labels
bug
Milestone

Comments

@japgolly
Copy link
Contributor

@japgolly japgolly commented May 19, 2020

How on earth to do configure SBT and/or Scala.JS to allow a JS module without tests?

I have no idea what the default jsEnv is or how it works but a new module with basically just enablePlugins(ScalaJSPlugin, JSDependenciesPlugin) and not much else, running test throws an exception:

[error] stack trace is suppressed; run last demo / Test / jsEnvInput for the full output
[error] (demo / Test / jsEnvInput) java.nio.file.NoSuchFileException: require-file:/tmp/tmp-12228659344646593601react.development.js

I'm trying a few things but to no avail. One of the things I've tried is Test / jsEnvInput := Nil but when I run test it just hangs. Presumably it simply doesn't handle this case and sits around waiting for the jsEnv to signal completion.

If Test / jsEnvInput := Nil I think either one of two things should happen

  • either there should probably be an assertion when the tests start to say "hey, it can't be empty!"
  • or it should accept that empty means nothing to do, and just return early with success or completion
@sjrd
Copy link
Member

@sjrd sjrd commented May 19, 2020

Why not just

Test / test := {}

?

@sjrd
Copy link
Member

@sjrd sjrd commented May 19, 2020

That said, not having anything shouldn't throw an exception in the first place. I can't reproduce that behavior, even with the JSDependenciesPlugin.


Now, emptying Test / jsEnvInput would be bad, yes, because you remove the script that connects to the server to listen to test execution commands sent by sbt. We can probably emit some kind of error in that situation, indeed. But yeah, you shouldn't empty Test / jsEnvInput, that is not going to help.

@japgolly
Copy link
Contributor Author

@japgolly japgolly commented May 19, 2020

Using Test / test := {} has the same problem of:

[error] stack trace is suppressed; run last demo / Test / jsEnvInput for the full output
[error] (demo / Test / jsEnvInput) java.nio.file.NoSuchFileException: require-file:/tmp/tmp-12228659344646593601react.development.js
@japgolly
Copy link
Contributor Author

@japgolly japgolly commented May 19, 2020

ah sorry - correction:

Using Test / test := {} works but when I do a release with sbt-release, then the above error about demo / Test / jsEnvInput appears.

@japgolly
Copy link
Contributor Author

@japgolly japgolly commented May 19, 2020

I can't reproduce that behavior, even with the JSDependenciesPlugin.

@sjrd I can provide a repo if you like :)

I had a similar error with the same kind of message in a cross-build project until have moved the enablePlugins(JSDependenciesPlugin) configuration to be in the .js module only.

@plokhotnyuk Unfortunately in my case it's not a cross-project but a plain JS-only module

@sjrd
Copy link
Member

@sjrd sjrd commented May 19, 2020

@sjrd I can provide a repo if you like :)

Yes, please.

@gzm0
Copy link
Contributor

@gzm0 gzm0 commented May 19, 2020

Which jsEnv are you running with? If the jsEnv terminates without connecting to the test adapter, the test adapter should fail, not hang. However, if the jsEnv does not terminate, there's nothing the test adapter can do (except for timing out, which we probably should consider).

@gzm0
Copy link
Contributor

@gzm0 gzm0 commented May 19, 2020

Actually, scratch that. If the input is empty, scalaJSCom.init never gets called. So the underlying connection is actually established and the jsEnv may not terminate. So the jsEnv is working correctly.

To avoid the hanging, I don't think we have another option than setting a timeout on the TestAdapter's call.

@japgolly
Copy link
Contributor Author

@japgolly japgolly commented May 20, 2020

Alrighty, reproduction is here:

If you look at the module's config you can see that it only enables ScalaJSPlugin & JSDependenciesPlugin and doesn't configure tests at all. I'm not setting the jsEnv.

@sjrd
Copy link
Member

@sjrd sjrd commented May 21, 2020

Thank you. That's definitely JSDependenciesPlugin's fault. I have re-reported that specific issue at scala-js/jsdependencies#40.

@japgolly
Copy link
Contributor Author

@japgolly japgolly commented May 22, 2020

Thanks @sjrd !

@sjrd
Copy link
Member

@sjrd sjrd commented May 22, 2020

Actually, scratch that. If the input is empty, scalaJSCom.init never gets called. So the underlying connection is actually established and the jsEnv may not terminate. So the jsEnv is working correctly.

To avoid the hanging, I don't think we have another option than setting a timeout on the TestAdapter's call.

IIUC, the jsEnv itself already terminates: the execution of all the scripts finishes, and nothing was put in the event queue nor the I/O handlers, so the Node.js process should finish on its own. That means that

  1. ExternalJSRun.future should complete with a successful(()).
  2. At that point, the nodejs.ComSupport should be able to complete its own future (not sure whether it should be a success or a failure at this point, but that doesn't matter).
  3. Which should in turn cause the JSEnvRPC to cancel all pending RPC calls
  4. And that should cause TestAdapter.loadFrameworks to fail, instead of hanging.

Is the above reasoning correct? If yes, what is going wrong that causes the hanging? Perhaps a race between cancelling call RPC calls versus starting the loadFrameworks RPC call?

@gzm0
Copy link
Contributor

@gzm0 gzm0 commented May 22, 2020

nothing was put in the event queue nor the I/O handlers

The com run establishes a connection to the JVM unconditionally (even if init is not called). So there are open I/O handlers, hence Node.js does not terminate.

This is a specification problem in the JSEnv that allows not calling scalaJSCom.init on a com run. Allowing this, enables to cleanly terminate the JSEnv (by closing the connection from the JVM side).

It is unclear to me how to resolve this. We could:

  • Change the specification and require init to be called. Then we could only establish a connection to the JVM once init is called.
  • Fail if messages are in the inbound JS queue and init is not called after a certain amount of time (can't think of a better condition...)
  • Push the problem upwards to users of the JSEnv.
@gzm0
Copy link
Contributor

@gzm0 gzm0 commented May 25, 2020

After giving this some thought, I think we do not gain a lot with the first two options, because the JS side might as well have a bug so it doesn't answer to messages. To address this for now, I think we should simply refuse to create a TestAdapter with an empty input.

@gzm0 gzm0 self-assigned this May 25, 2020
@gzm0 gzm0 added this to the v1.1.1 milestone May 25, 2020
gzm0 added a commit to gzm0/scala-js that referenced this issue May 25, 2020
@gzm0 gzm0 added the bug label May 25, 2020
@gzm0 gzm0 linked a pull request that will close this issue May 25, 2020
gzm0 added a commit to gzm0/scala-js that referenced this issue May 25, 2020
This captures the most likely cause of scala-js#4054 and fails with an
informative error message.
@gzm0 gzm0 closed this in #4060 May 25, 2020
gzm0 added a commit that referenced this issue May 25, 2020
Mitigate #4054: Refuse to run TestAdapter with empty input
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

3 participants
You can’t perform that action at this time.