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

Add setUp and tearDown to simplify tests. #108

Closed
wants to merge 6 commits into from

Conversation

hayd
Copy link
Contributor

@hayd hayd commented Jan 13, 2019

This also adds a main.ts which allows one to to grep
through tests. Ideally this would recursively import
all test.ts or *_test.ts files.

The idea was that this could later be called by deno test.

Note: The first commit is a small cleanup after #105.

hayd added 2 commits January 12, 2019 17:42
This also adds a main.ts which allows one to to grep
through tests. Ideally this would recursively import
all test.ts or *_test.ts files.
});
// Wait for fileServer to spool up.
await new Promise(res => setTimeout(res, 1000));
Copy link
Member

Choose a reason for hiding this comment

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

We really need a better way to do this...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wonder if what you want is:

isReady(() => bool)
timeout: number

A waitUntil async funtion could check isReady every second (?) until timeout.

Copy link
Contributor Author

@hayd hayd Jan 13, 2019

Choose a reason for hiding this comment

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

This can be done pretty easily with these utils:

setUp(async function startFileServer() {
  fileServer = run({
    args: ["deno", "--allow-net", "http/file_server.ts", ".", "--cors"]
  });
  // Wait for fileServer to spool up.
  // await new Promise(res => setTimeout(res, 1000));
  await waitUntil(async function() {
    try { await fetch("http://localhost:4500/"); return true }
    catch(e) { return false } ;
  }, 1000)
});

// given
async function waitUntil(isReady: ()=>boolean|Promise<boolean>, timeout: number): Promise<void> {
  let t = 0;
  while (!await isReady()) {
    await delay(1000);
    if (t++ > timeout) {
      throw Error(`Timeout waiting for ${isReady}`)
    }
  }
}

async function delay(ms: number): Promise<void> {
  await new Promise(res => setTimeout(res, ms));
}

do waitUntil and delay belong in an std as standalone?

I can update this PR...

Edit: I suspect until is a better name than waitUntil.

Copy link
Member

Choose a reason for hiding this comment

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

I think a better way to wait for file_server to be ready is to read from its stdout and wait until you see "HTTP server listening on http://0.0.0.0:4500/"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

const data = new Uint8Array(50);
const r = await fileServer.stdout.read(data);
const s = new TextDecoder().decode(data.subarray(0, r.nread));
return s.includes("server listening");
Copy link
Member

@ry ry Jan 13, 2019

Choose a reason for hiding this comment

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

There's no guarantee that the read will get an entire line. So this is not correct.
I suggest using something like this (untested)

async function waitForFileServerReady(fileServer: deno.Process): Promise<bool> {
  let stdout = new TextProtoReader(fileServer.stdout);
  let err = null;
  while (!err) {
    let [line, err] = await r.readLine();
    if (line.includes("server listening")) return true;
  }
  return false;
}

Copy link
Member

Choose a reason for hiding this comment

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

(As a warning, it may be that TextProtoReader only works on \r\n line breaks... but try this first..)

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this look right?

setUp(async function startFileServer() {
  fileServer = run({
    args: ["deno", "--allow-net", "http/file_server.ts", ".", "--cors"],
    stdout: "piped"
  });

  const r = new TextProtoReader(new BufReader(fileServer.stdout));
  const [s, err] = await r.readLine();
  assert(err == null);
  assert(s.includes("server listening"))
});

Copy link
Member

Choose a reason for hiding this comment

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

Yes, but fileServer needs to have fileServer.close() and fileServer.stdout.close() called on it during tearDown

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fileServer.close() is in tearDown.
That doesn't imply fileServer.stdout.close() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@@ -13,7 +13,8 @@ test(function t2() {
/** A more complicated test that runs a subprocess. */
test(async function catSmoke() {
const p = run({
args: ["deno", "examples/cat.ts", "README.md"]
args: ["deno", "examples/cat.ts", "README.md"],
Copy link
Member

Choose a reason for hiding this comment

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

While you're fixing this, can we cat a smaller file? I've noticed this is flooding the log

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The piped stops it flooding the log.

Copy link
Member

Choose a reason for hiding this comment

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

👍

}
export function tearDown(t: TestFunction): void {
tearDowns.push(t);
}
Copy link
Member

Choose a reason for hiding this comment

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

Can we just fix timer for starting fileServer in this PR and leave out the setUP and tearDown stuff?

Because modifying testing will effect all of deno, this needs to be considered very carefully. I'm not sure I agree with setting a global setUp/tearDown.

Please just manually do the setUP and tearDown for each of the fileServer tests with the new initialization. After that's landed let's discuss these testing changes (in gitter if you have time)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure I agree with setting a global setUp/tearDown.

I would prefer this was per-file, but am not sure on the trick to make this work.

I also want to improve this across all of deno / have it considered carefully.

I could tease it apart:

  • timing of fileserver
  • main.ts for testing
  • setUp + tearDown (to discuss)

Copy link
Member

Choose a reason for hiding this comment

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

timing of fileserver

Let's do just this in this PR.

main.ts for testing

Yeah. I think we should get rid of the "automatic" run behavior that we currently have
https://github.com/denoland/deno_std/blob/b99d7d3e0f61216db7b5a5ad2bc254f8ac97ff4d/testing/mod.ts#L166
and rather require users to call runTests() explicitly.

Copy link
Member

Choose a reason for hiding this comment

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

@hayd I'm very interested in having your improvements here. I do think they should be split up into different PRs tho. For simplicity, I'm going to close this one.

@hayd
Copy link
Contributor Author

hayd commented Jan 17, 2019

I wonder if an alternative for the setUp/tearDown (or setup/teardown) here is to have test take these as options arguments. That way if you did want every test to wrap with the same setup/teardown you could define your own partial function.

Edit: i.e.

test(function foo() {...}, { setup: setup, teardown: teardown })
// is equivalent to
test({
  setup()
  try {
    foo()
  } finally {
    teardown()
  }
})

@hayd
Copy link
Contributor Author

hayd commented Jan 17, 2019

An alternative might look like this: hayd@987ef51

inverted-capital added a commit to dreamcatcher-tech/napps that referenced this pull request Oct 24, 2024
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.

2 participants