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

Pkg-tests testsuite #5392

Merged
merged 6 commits into from Feb 27, 2018
Merged

Pkg-tests testsuite #5392

merged 6 commits into from Feb 27, 2018

Conversation

arcanis
Copy link
Member

@arcanis arcanis commented Feb 22, 2018

Summary

This PR adds a new experimental testsuite. It has a few important differences compared to our current one:

  • It's much smaller, ofc 😛
  • It's only meant to test the core features common to every package manager
  • It doesn't rely on our internals (which is the main point imo)
    • Ex: it doesn't require us to instanciate a new Install class (it spawns a process instead)
    • Ex: it checks that the install worked by requiring the files (instead of checking the filesystem)
    • Thanks to the point above, it means that anybody can run it on their package manager
    • It will allow us to confidently rework our internals later on while still being able to trust our tests
  • The fixtures have a different layout. Our current fixture directory has a lot of fixtures, most of those are unique to specific tests. It makes it harder for us to write new tests:
    • We first need to find out which fixture folder kinda match the environment we want to test
    • Or we can create a new fixture, which will make the situation slightly worse next time
    • Fixture folders are frozen because we have no effective way to know what's important in them, especially when multiple tests might use them for different reasons.
    • In contrast, the fixtures in this PR are minimal, used across multiple tests, and have a clear semantic meaning (for example, no-deps ... has no deps. I let you guess for one-fixed-dep).
  • The tests are factorized and can "inherit" ones from the others, which allow us to run tests under different environments without having to duplicate code (for example we could easily run a set of tests with hoisting, and another without hoisting).

In this end, I think this experiment should benefit both the community at large and us in the long term. Having a generic testsuite will make it much easier for everyone involved to go fast without breaking things.

Test plan

Run yarn && yarn jest yarn.test.js in the pkg-tests directory.

@arcanis arcanis force-pushed the pkg-tests branch 3 times, most recently from f4da332 to 7161784 Compare February 22, 2018 13:47
"flowtype/require-valid-file-annotation": "off",
"flowtype/require-return-type": "off"
}
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Disabled flow (in this directory only) for the time being, the utils don't really need typing right now (especially since they're by definition covered by the tests :).

Copy link
Contributor

Choose a reason for hiding this comment

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

You are probably right but I think we should generally try to use flow types across the board. It seems that you could add flow types to everything rather quickly  1�7 do you mind spending some time on this? It will make it significantly easier for other people to work on this code, for example in Nuclide, where we have type definitions available and auto-completion.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also helps me review the code ;)

// eslint-disable-next-line
`require('dep-loop-entry') === require('dep-loop-entry').dependencies['dep-loop-exit'].dependencies['dep-loop-entry']`,
),
);
Copy link
Contributor

Choose a reason for hiding this comment

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

what do you expect here? Missing comparison! If you use eslint-plugin-jest, this will error.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch! I ran eslint from the repo root, and errors were successfully reported, but not this one. Maybe because of the await?

@cpojer
Copy link
Contributor

cpojer commented Feb 22, 2018

Really sweet. Can you fix CI, add flow types and possibly add this to the main Jest run with the multi-project-runner feature? https://facebook.github.io/jest/blog/2017/05/06/jest-20-delightful-testing-multi-project-runner.html

@buildsize
Copy link

buildsize bot commented Feb 23, 2018

This change will decrease the build size from 10.49 MB to 10.46 MB, a decrease of 28.18 KB (0%)

File name Previous Size New Size Change
yarn-[version].noarch.rpm 909.03 KB 906.78 KB -2.26 KB (0%)
yarn-[version].js 3.95 MB 3.94 MB -10.83 KB (0%)
yarn-legacy-[version].js 4.1 MB 4.09 MB -11.4 KB (0%)
yarn-v[version].tar.gz 914.25 KB 912.05 KB -2.19 KB (0%)
yarn_[version]all.deb 675.03 KB 673.53 KB -1.5 KB (0%)

@arcanis
Copy link
Member Author

arcanis commented Feb 23, 2018

Fixed Flow but prevented it from running on pkg-tests for now on CI environments. Integrating pkg-tests to our testsuite will be somewhat complex (we need to install its own dependencies + build yarn itself, and we can't make it a workspace because the root package.json is not private), so I'd like to do this in another PR to make things easier to review.

You can still run Flow if you go into packages/pkg-tests and manually run yarn && yarn flow.

@rally25rs
Copy link
Contributor

rally25rs commented Feb 24, 2018

My 1st thought: "It's a workspace nested in a workspace?" 🤔 I didn't know yarn would be ok with that.

Could you add a readme file that explains how this works and how to add tests? I think that was one of the shortcomings of the unit test framework; figuring out how to add tests was a bit of a painful expedition.

From a quick glance, it looks like this fires up an http server that acts as a custom registry that then serves the fixtures packages? That's a cool idea, and probably a lot easier to manage than what we do in the unit tests with mocking http requests.

I assume it is not a replacement for the existing unit tests, but a new suite of high-level "end to end" tests?

I'm also curious if you've showed this to anyone on npm team (zkat maybe?) to see if this is something they would like to use as well. It'd be really damn cool if we had a shared suite of "smoke tests".

Will this be able to handle things like github urls? Or really, all the crazy url formats that npm has introduced over the years? i.e. if I make a package in fixtures that has a dependency on "foo": "git+ssh://git@github.com/foo/foo#semver:^0.1.0" what will happen?

Is this just testing the install command at this point? If it becomes more of a "universal" tester, is there a way to accommodate command name and flag differences? (i.e. yarn add vs npm install)


The tests all fail for me with the error:

    Command failed: /Users/jvalore/.nvm/versions/node/v8.5.0/bin/node /Users/jvalore/Projects/yarn/packages/pkg-tests/../artifacts/yarn-1.4.1.js --cache-folder /var/folders/yf/gcmnw1y96k31lh9ttjhfm8v9ssxkkq/T/tmp-46652uoRI0M829loD/.cache install
    module.js:473
          throw err;
          ^

    Error: Cannot find module '/Users/jvalore/Projects/yarn/packages/artifacts/yarn-1.4.1.js'

How does it resolve what package manager to run? It looks like it's expecting yarn 1.4.1 from somewhere?

Edit:

If I change the path in yarn.test.js to ../../bin/yarn.js then the tests run, but almost all the tests timeout:

  ◄1�7 Basic tests  1�7 it should correctly install a single dependency that contains no sub-dependencies

    Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.

      at node_modules/jest-jasmine2/build/queue_runner.js:72:21
      at Timeout.callback [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:633:19)

@arcanis
Copy link
Member Author

arcanis commented Feb 25, 2018

Good questions!

My 1st thought: "It's a workspace nested in a workspace?" 🤔 I didn't know yarn would be ok with that.

Yarn doesn't support nested workspaces. However it's not one, because the pkg-tests directory is not configured as a workspace of the yarn repository (I think on the long term it might be valuable to move yarn itself into the packages directory as a workspace so that we can configure each of them as part of a workspace).

Could you add a readme file that explains how this works and how to add tests?

Will do 👍

From a quick glance, it looks like this fires up an http server that acts as a custom registry that then serves the fixtures packages?

Yep exactly!

I assume it is not a replacement for the existing unit tests, but a new suite of high-level "end to end" tests?

I think provided we can implement a decent number of tests it might prove a worthy replacement for most of our install tests (such as install/integration.js), and we could have a yarn-specific module that would test yarn-specific commands, but we'll probably always need unit tests for at least some part of the project (for example the utils).

I'm also curious if you've showed this to anyone on npm team (zkat maybe?) to see if this is something they would like to use as well. It'd be really damn cool if we had a shared suite of "smoke tests".

Not yet, I wanted to make it work here before bothering them, but I'd really like to know what they think of this once we get something going. I think the best thing in this project is that it's mostly project-agnostic, so if everyone contributes we can end up with something valuable for everyone.

Will this be able to handle things like github urls? Or really, all the crazy url formats that npm has introduced over the years? i.e. if I make a package in fixtures that has a dependency on "foo": "git+ssh://git@github.com/foo/foo#semver:^0.1.0" what will happen?

Git (and exotic registries in general) will be quite more difficult because we'll need to run a light git server somehow. I'm sure it can be done tho! Maybe by introducing settings in our package manager to specify a different target for github aliases (like resolving "foo/bar" to "localhost/foo/bar#semver" instead of "github.com/foo/bar#semver").

Is this just testing the install command at this point? If it becomes more of a "universal" tester, is there a way to accommodate command name and flag differences? (i.e. yarn add vs npm install)

Right now yes, I think work should focus around here since it's the most common and important brick, and all other commands are kinda optional (yarn add can be replaced by just updating the package.json manually, for example). However we could have per-package modules (for example pkg-tests-yarn, or pkg-tests-npm) that would test the rest of the commands against our respective CLI specifications.

How does it resolve what package manager to run? It looks like it's expecting yarn 1.4.1 from somewhere?

It uses a driver file which specifies what should be done when the tests invoke the run command. For example for Yarn, we just run the build artifact generated when you run yarn build-dist, but you can really do anything (in fact, you don't even have to shell out if you can use your package manager from an API).

I'll have to investigate the timeouts - can you try to increase the jasmine.DEFAULT_TIMEOUT_INTERVAL variable to something huge like 120000 and see if it helps and how much time do your tests take?

const pkgDriver = generatePkgDriver({
runDriver: (path, args, {registryUrl}) => {
const extraArgs = [`--cache-folder`, `${path}/.cache`];
return execFile(process.execPath, [`${process.cwd()}/../artifacts/yarn-1.4.1.js`, ...extraArgs, ...args], {
Copy link
Member Author

Choose a reason for hiding this comment

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

Path is no longer valid since I moved pkg-tests into packages/pkg-tests, I need to update it

Copy link
Contributor

Choose a reason for hiding this comment

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

The version changes constantly too. Too lazy to directly submit a PR to your branch... I wrote this to auto detect yarn:

// @flow

const fs = require('fs');
const {
  tests: {generatePkgDriver, startPackageServer, getPackageRegistry},
  exec: {execFile},
} = require(`pkg-tests-core`);

const {basic: basicSpecs, dragon: dragonSpecs} = require(`pkg-tests-specs`);

const yarnFileMatcher = /^yarn-\d+\.\d+\.\d+\.js$/;

const getYarnPath = function(): string {
  const artifactsFolder = `${process.cwd()}/../../artifacts`;
  const yarnFile = fs.readdirSync(artifactsFolder).find(file => yarnFileMatcher.test(file));
  if (!yarnFile) {
    throw new Error(`Unable to locate yarn in ${artifactsFolder}`);
  }
  return `${artifactsFolder}/${yarnFile}`;
};

const pkgDriver = generatePkgDriver({
  runDriver: (path, args, {registryUrl}) => {
    const extraArgs = [`--cache-folder`, `${path}/.cache`];
    const yarnPath = getYarnPath();
    return execFile(process.execPath, [yarnPath, ...extraArgs, ...args], {
      env: {[`NPM_CONFIG_REGISTRY`]: registryUrl, [`YARN_SILENT`]: `1`},
      cwd: path,
    });
  },
});

beforeEach(async () => {
  await startPackageServer();
  await getPackageRegistry();
});

basicSpecs(pkgDriver);
dragonSpecs(pkgDriver);

@rally25rs
Copy link
Contributor

A long timeout seems to expose an ESOCKETTIMEDOUT error?

  ◄1�7 Basic tests  1�7 it should install the dependencies of any dependency fetched from the internet

    Timeout - Async callback was not invoked within the 120000ms timeout specified by jest.setTimeout.

      at node_modules/jest-jasmine2/build/queue_runner.js:72:21
      at Timeout.callback [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:633:19)

  ◄1�7 Basic tests  1�7 it should install the dependencies of any dependency fetched from a local directory

    Command failed: /Users/jvalore/.nvm/versions/node/v8.5.0/bin/node /Users/jvalore/Projects/yarn/packages/pkg-tests/../../artifacts/yarn-1.5.0.js --cache-folder /var/folders/yf/gcmnw1y96k31lh9ttjhfm8v9ssxkkq/T/tmp-48925vtIlYFqBgkUi/.cache install
    warning package.json: No license field
    warning No license field
    error An unexpected error occurred: "http://localhost:49492/one-fixed-dep/-/one-fixed-dep-1.0.0.tgz: ESOCKETTIMEDOUT".

@arcanis
Copy link
Member Author

arcanis commented Feb 27, 2018

Fixed and fixed 👍 I'm now using dist/bin/yarn.js instead of the single-file bundle. Its path should stay the same regardless of the version.

package.json Outdated
@@ -107,7 +107,7 @@
"build-dist": "bash ./scripts/build-dist.sh",
"build-win-installer": "scripts\\build-windows-installer.bat",
"dupe-check": "yarn jsinspect ./src",
"lint": "eslint . && flow check",
"lint": "eslint src __tests__ && flow check",
Copy link
Contributor

Choose a reason for hiding this comment

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

why did you change this?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was for when there was no flow types, I'll revert it

@@ -0,0 +1,18 @@
[ignore]
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need a separate flowconfig here?


export type {PackageDriver} from './utils/tests';

const exec = require(`./utils/exec`);
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't the code style we are using for requires. Can you use single quotes?

@@ -17,6 +17,7 @@ const path = require('path');

const installFixturesLoc = path.join(__dirname, '..', 'fixtures', 'install');

// $FlowFixMe I don't understand the error
Copy link
Contributor

Choose a reason for hiding this comment

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

me neither. cc @calebmer any idea what this is supposed to be?

screen shot 2018-02-27 at 12 03 15

@@ -0,0 +1,4 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

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

Also not sure about this one. Can we please re-use the lint rules from the main folder? I don't think this test framework/suite should adhere to different lint rules than others.

@@ -0,0 +1,58 @@
// @flow
Copy link
Contributor

Choose a reason for hiding this comment

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

The rest of Yarn uses /* @flow */. Can we do the same here?

Copy link
Contributor

@cpojer cpojer left a comment

Choose a reason for hiding this comment

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

I'm gonna stamp this but I think it would be better next time to split a diff like this up into ten smaller ones, something like this:

  • Upgrade flow to 0.66.
  • Fix timers/update flow type to use TimeoutID.
  • Add scaffold for new test infra.
  • Add lots of test fixtures.
  • One commit for each new test you are adding.

Please consider splitting it up next time to reduce the review burden on people who look at your PRs. Thanks.

@arcanis arcanis merged commit 5fc6f7f into yarnpkg:master Feb 27, 2018
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.

None yet

3 participants