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

Adding tests in CI #105

Merged
merged 21 commits into from
Sep 26, 2023
Merged

Adding tests in CI #105

merged 21 commits into from
Sep 26, 2023

Conversation

TonioGela
Copy link
Member

After some brainstorming with @armanbilge, I added some tests to the CI to compile some scripts using scala-cli.

The whole logic is simple:

  • toolkitTesting / Test / test depends on toolkit.jvm / publishLocal so that before running the tests the artifact gets published locally
  • BuildInfo was added to have both scalaversion and version available in the test scope
  • scala-cli was added as a dependency and it's called like ScalaCli.main(Array("compile", "<tempFileName>"))

Two specialized method were added, to test both scala 3.x.x and 2.13.x syntax (and toolkit artifact)

Solves #50.

@TonioGela
Copy link
Member Author

@armanbilge at the moment, the jvm tests are called even in the js and native jobs. I fear this might cause flakiness regarding the artifact that will get published, and if maybe this will solve

lazy val root = tlCrossRootProject
  .aggregate(toolkit, toolkitTest)
  .configureJVM(
    _.settings(
      (Test / test) := (Test / test)
        .dependsOn(toolkitTesting / Test / test)
        .value
    )
  )

WDYT?

@armanbilge
Copy link
Member

armanbilge commented Sep 23, 2023

at the moment, the jvm tests are called even in the js and native jobs

They are? I don't think so.

Edit: so they are. but why 🤔

build.sbt Outdated Show resolved Hide resolved
@TonioGela
Copy link
Member Author

A thing to note is that ScalaCli.main calls System.exit(1) when it fails to compile, so the first broken test will fail fast for everything else. CI will still work and report its broken state, but we won't get a fancy output about the tests that are actually broken.

@armanbilge
Copy link
Member

Hmmm, that's actually quite annoying. What if we invoked scala-cli as an external process?

build.sbt Outdated
.in(file("toolkit-testing"))
.settings(
name := "toolkit-testing",
Test / test := (Test / test).dependsOn(toolkit.jvm / publishLocal).value,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't have to be this PR, but eventually I'd like to publish the JS and Native toolkits and test those as well.

Specifically, we seem to have an issue sometimes where the toolkit requires JS or Native versions newer than what the latest scala-cli is shipping by default, I wonder if we should try to avoid merging those ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this can be done easily, but using scala-cli as an external process, a thing that will solve the System.exit(1) too.

That's another point in favor of this solution 🤔

@TonioGela
Copy link
Member Author

Hmmm, that's actually quite annoying. What if we invoked scala-cli as an external process?

We could do that but I appreciate the leanness of the way is implemented now. I think another viable alternative might be to invoke the inner compile command internally and handle eventual Left, None, Failure or exceptions.

@armanbilge
Copy link
Member

think another viable alternative might be to invoke the inner compile command internally

Ah that's the other thing: I don't want to specialize to compile, I think it would be good if we actually try to run the scripts. Otherwise we won't pick up on issues like #105 (comment).

I know it's not as lean, but I think an external process is the way to go long-term.

@TonioGela
Copy link
Member Author

but I think an external process is the way to go long-term.

Hmm, let me think, what do we need apart calling the external process? Will adding VirtusLab/scala-cli-setup@main in the ci.yml be enough?

@armanbilge
Copy link
Member

We don't need to install anything, we already have scala-cli on the classpath since we added it as a dependency. We can load the classpath into the buildinfo and use that to invoke scala-cli as an ordinary java app.

@armanbilge
Copy link
Member

@TonioGela
Copy link
Member Author

Here's how we do something similar in Cats Effect for running IOApp tests.

https://github.com/typelevel/cats-effect/blob/a6c5b155be3b729af49eb26204e101f2d527fa80/ioapp-tests/src/test/scala/IOAppSpec.scala#L58-L69

This definitively requires a night of sleep before trying to be understood. I'll take a look at it tomorrow, thanks ;)

@TonioGela
Copy link
Member Author

I like the idea; it will require a bit of trial and error, but it's feasible. I'll bring this PR back to Draft to make some tests. I have a question, though: why the full classpath was "injected" as a Java property while the platform was injected using BuildInfo?

@TonioGela
Copy link
Member Author

I have a question, though: why the full classpath was "injected" as a Java property while the platform was injected using BuildInfo?

Because a setting cannot depend on a task ofc

@TonioGela
Copy link
Member Author

@armanbilge wdyt of the last commit? It's probably a bit overkilled, but it seems to work. Now it's the case to test both compilation and running for all the other platforms.

One thing I'm not 100% sure is how to structure the js and native tests: maybe it's the case to restore something like Test / test := (Test / test).dependsOn(toolkit.jvm / publishLocal).value, to let the test run after every platform has published locally its own artifact?

build.sbt Outdated
Comment on lines 76 to 79
Test / fork := true,
Test / javaOptions += s"-Dtoolkit.testing.classpath=${(Test / fullClasspath).value
.map(_.data.getAbsolutePath)
.mkString(File.pathSeparator)}"
Copy link
Member

@armanbilge armanbilge Sep 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this, we can just pass the classpath as a BuildInfo key. Then we also don't need to fork.

Also Compile / dependencyClasspath should be sufficient if we can move scala-cli out of test scope.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could do this only if Compile / dependencyClasspath is a setting. You can't depend on tasks, neither using .value in settings definition. I'll try but I'm not sure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh. Well that's annoying, forgot that. Ok, so then maybe we need to pass it as an env variable so that JS and Native can pick it up.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😎

    buildInfoKeys +=
      BuildInfoKey.map(Compile / dependencyClasspath) { case (k, v) =>
        (k, v.seq.map(_.data.getAbsolutePath).mkString(File.pathSeparator))
      }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be used in the CE build too :)

build.sbt Outdated Show resolved Hide resolved
@TonioGela
Copy link
Member Author

@armanbilge we should be done :)

Copy link
Member

@armanbilge armanbilge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really great! TIL a bunch of stuff too 🤓 Sorry, I just have way too many nitpicks 😅

@TonioGela
Copy link
Member Author

@armanbilge I've addressed most of the suggestions but:

  • I can't get toolkit-test to work at all, even locally. Shouldn't //> using test.toolkit typelevel:latest be enough?
  • Running on scala.js seems to fail to find the main class

@armanbilge
Copy link
Member

armanbilge commented Sep 25, 2023

  • I can't get toolkit-test to work at all,

What's the error? Are you publishing it locally?


  • Running on scala.js seems to fail to find the main class

Sorry running what exactly? And what is the exact error? I see the CI failure now.

java.lang.Exception: Non zero exit code (1) for run /tmp/3wmKco/.scala

Something seems wrong with the filename?

@TonioGela
Copy link
Member Author

What's the error? Are you publishing it locally?

Nope, I can't recall how to use the toolkit-test artifact, we haven't written a line on doc on how to use it 😓

build.sbt Outdated Show resolved Hide resolved
@armanbilge
Copy link
Member

Nope, I can't recall how to use the toolkit-test artifact,

You don't need to do anything, it's automatically in scope when you use scala-cli test command :)

@TonioGela
Copy link
Member Author

java.lang.Exception: Non zero exit code (1) for run /tmp/3wmKco/.scala

Something seems wrong with the filename?

O_O Is the Files[IO].tmpFile impl that works differently in scala.js? Let me check.

@TonioGela
Copy link
Member Author

TonioGela commented Sep 25, 2023

Nope, I can't recall how to use the toolkit-test artifact,

You don't need to do anything, it's automatically in scope when you use scala-cli test command :)

Using scala-cli test on this:

//> using toolkit typelevel::latest

import cats.effect.*
import munit.*

class Test extends CatsEffectSuite:
  test("test")(IO.unit)

or on the same but with test.toolkit always returns an error about munit not being found

@armanbilge
Copy link
Member

typelevel::latest it should be a single colon.

@TonioGela
Copy link
Member Author

CI's green

@TonioGela
Copy link
Member Author

TonioGela commented Sep 26, 2023

There's something that I don't understand about the native pipeline, it takes more than 60 seconds to compile the first snippet

It may be an ex-post explanation, but after all, within this timeout, we should:

  • start the testing machine
  • run java externally that will:
    • download the correct scala native version
    • compile the code
    • run the code

So the task is flaky by definition, as we rely on coursier and the internet speed of maven central (or whomever serves the scala native artifact).

The real question is: how could have taken just 30 seconds to do all of this before?

Copy link
Member

@armanbilge armanbilge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nicely done 👏

@TonioGela
Copy link
Member Author

The real question is: how could have taken just 30 seconds to do all of this before?

Some of the CI runs that passed before mangling the general timeout took more than 30 seconds O_O'
Is 38 seconds still less than 30 seconds?

@armanbilge
Copy link
Member

The 30 second timeout applies per-test, not per-suite. So maybe that's how? or was a single test taking 38 seconds?

@TonioGela
Copy link
Member Author

The 30 second timeout applies per-test, not per-suite. So maybe that's how? or was a single test taking 38 seconds?

Single test apparently: https://github.com/typelevel/toolkit/actions/runs/6309440614/job/17129364102

@TonioGela
Copy link
Member Author

Still, that's not a mistery that we'll solve here @armanbilge :D

Whenever you want,sir

@armanbilge armanbilge merged commit ef928b0 into typelevel:main Sep 26, 2023
11 checks passed
@mergify mergify bot added the tests label Sep 26, 2023
@armanbilge armanbilge linked an issue Sep 26, 2023 that may be closed by this pull request
@TonioGela TonioGela deleted the ci-tests branch September 26, 2023 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Adding tests in CI
2 participants