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

composer: add initial version #75

Closed
wants to merge 2 commits into from
Closed

Conversation

jxs
Copy link
Member

@jxs jxs commented Nov 18, 2022

This is an initial version of the composer tool. I am submitting this as a draft PR so we can broaden the discussion regarding the assumptions I did.
I followed the idea of using csv files with sqlite from @MarcoPolo which turned great cause it allows us to model the data and create all the combinations in a much simpler way using sql.

But due to the difficulty of modeling all the test and build parameters into csv files, including the different natures of go and rust test plans which use different builders, and after speaking with @laurentsenta and @MarcoPolo it occurred to me that if we simplify on the builder to be docker:generic and, pass the version as we currently do via [groups.build_config.build_args]
and pass all the test parameters (transport, muxer, protocol) when launching the container the work becomes a lot easier for the composer and we could also combine it with testground/testground#1522.
Does testground currently support passing env vars when launching containers @laurentsenta?

While on the Go side we'd had to change the test plans to start using docker:generic and change the way the parameters are passed, the changes required on the Rust side we'd just to rename the binary files to match the VERSION passed on the composition.toml file.

Wdyt of using just docker:generic to simplify the process @laurentsenta @mxinden?
a run of composer with these csv files produces the following composition.toml

Thanks.

@MarcoPolo
Copy link
Contributor

does testground support passing env vars when launching containers @laurentsenta?

Pretty sure it must because this is how the testground SDK gets all the information.

@p-shahi
Copy link
Member

p-shahi commented Nov 18, 2022

Drive by: not entirely certain as I'm not following closely but might need testground/testground#1505 to pair with testground/testground#1522

@@ -0,0 +1,11 @@
id,muxer
Copy link
Member

Choose a reason for hiding this comment

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

Naive question, will there be an additional csv for security protocol TLS/Noise, or is that being handled differently?

Copy link
Member Author

Choose a reason for hiding this comment

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

will be another file, i.e. sec.csv:

id,protocol
rust-master,noise
rust-master, tls
rust-0.49.0,noise
rust-0.49.0,tls

that is then queried along the other ones.
The process of adding implementations can be improved later, either by creating a cli tool that does it or, getting another primary format, that is then parsed by the composer and converted to sql

Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

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

Thanks!

I added some thoughts :)

Comment on lines +1 to +24
{
"name": "composer",
"version": "0.0.1",
"description": "",
"main": "index.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^18.8.4",
"@types/yargs": "^17.0.13",
"ts-node": "^10.9.1",
"typescript": "^4.8.4"
},
"dependencies": {
"@iarna/toml": "^2.2.5",
"@types/iarna__toml": "^2.0.2",
"sqlite": "^4.1.2",
"sqlite3": "^5.1.2",
"yargs": "^17.6.2"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Has DENO been considered as an alternative? It would allow us to put everything in a single file without having to install dependencies etc.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for bringing this, yeah I considered but as it wasn't present by default on ubuntu-latest and we weren't using container images on the workflow I didn't want to introduce it. But if we can I am happy to use it if everyone agrees.

Copy link
Contributor

Choose a reason for hiding this comment

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

Installing it seems to be easy enough: https://github.com/denoland/setup-deno

I think this would be a good usecase for it, should make this script a lot more maintainable.

Comment on lines +1 to +2
import sqlite3 from "sqlite3";
import { open } from "sqlite";
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the difference between these two packages?

Copy link
Member Author

Choose a reason for hiding this comment

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

sqlite is a wrapper library that uses sqlite3 as the driver.

// Call sqlite to process the csv resource files and generate a database.
// We call the sqlite process instead of doing it here cause
// the dot commands are interpreted by the sqlite cli tool not sqlite itself,
// and it is a lot faster parsing the csv's.
Copy link
Contributor

Choose a reason for hiding this comment

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

Our CSVs are <10 lines long. What am I meant to take away from this comment?

Copy link
Member Author

@jxs jxs Nov 21, 2022

Choose a reason for hiding this comment

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

that we can't call sqlite dot commands via the database driver, therefore we do it via execFile therefore instead of parsing the csv file with js, we do it with sqlite instead cause it's faster.

Our CSVs are <10 lines long.

but they are expected to grow I assume, do you suggest importing, parsing and inserting in typescript land instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

Our CSVs are <10 lines long.

but they are expected to grow I assume

I am guessing they would have to grow into the thousands for performance to become a problem and thus a driving factor for the design. I hope that we won't have CSV files that are 1000s of lines long!

do you suggest importing, parsing and inserting in typescript land instead?

I think we should do whatever results in the better design. If we want to have a test for this, I think it will likely be easier if we don't need to set up dummy files for the tests but can pass data in as variables. That would suggest that we use SQL to insert the data which in turn means parsing the files in TS.

Comment on lines 100 to 155
const db = await open({
filename: DB,
driver: sqlite3.Database,
});

// Generate the testing combinations by SELECT'ing from both transports
// and muxers tables the distinct combinations where the transport and the muxer
// of the different libp2p implementations match.
const queryResults =
await db.all(`SELECT DISTINCT a.id as id1, b.id as id2, a.transport, ma.muxer
FROM transports a, transports b, muxers ma, muxers mb
WHERE a.id != b.id
AND a.transport == b.transport
AND a.id == ma.id
AND b.id == mb.id
AND ma.muxer == mb.muxer;`);
await db.close();

let global = new Global(
"multidimensional-testing",
"multidimensional",
argv.total_instances
);
let composition = new Composition(global, []);

for (let row of queryResults) {
// Instance count is hardcoded to 1 for now.
let instance = new Instance(1);

let build_args1 = new BuildArgs(
row.transport,
row.muxer,
row.id1,
argv.gitRef,
argv.gitTarget
);
let build_config1 = new BuildConfig(build_args1);
let group1 = new Group(row.id1, BUILDER, instance, build_config1);

let build_args2 = new BuildArgs(
row.transport,
row.muxer,
row.id2,
argv.gitRef,
argv.gitTarget
);
let build_config2 = new BuildConfig(build_args2);
let group2 = new Group(row.id2, BUILDER, instance, build_config2);

let run = new Run(
`${row.id1} x ${row.id2} x ${row.transport} x ${row.muxer}`,
[group1, group2]
);

composition.runs.push(run);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice to have a test for this snippet of code.

  1. So we can make sure it works.
  2. To make review easier: I don't have to run this locally to see the output.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah agree, and I am planning to do it after closing the spec.

Comment on lines +2 to +9
rust-master,tcp
rust-master,quic
rust-master,tcp
rust-0.49.0,tcp
rust-0.48.0,tcp
rust-0.47.0,tcp
go-0.23.4,tcp
go-0.23.4,quic
Copy link
Contributor

Choose a reason for hiding this comment

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

This is going to get really repetitive (and error prone, see lines 2 and 4 are duplicates) as we release new versions. If we already build a tool that generates the combinations for us, wouldn't it make more sense to track a semver specifier that marks, which versions support which feature?

What we would track is:

language quic yamux mplex tcp
rust > 0.50.0 > 0.20.01 ... ...
go > 0.24.3 ... ... ...

A null entry would mean unsupported.

If we ever decide to remove a feature, we can use a semver range: > 0.50.0 < 0.57.0.

Given this table, we only need one other list for each language that specifies the versions we want to test, e.g. for Rust, that could say:

  • 0.45.0
  • 0.46.0
  • ...

I am not sure if sqlite is still the best tool for this. We might be able to use it to generate the combinations initially but throw out the ones that don't match the semver range. There might also be a module that can do semver parsing in sqlite, I haven't checked.

In any case, I think this would be a lot more maintainable going forward.

Thoughts?

Footnotes

  1. Just making this 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.

this links with @p-shahi's question on #75 (comment) and your comment on #75 (comment) I think.

Yeah this seems to me an elegant solution to solve the increasing number of dimensions into csv files and I don't think it is incompatible with using sqlite. I.e we could define the format suggested above with semver's and then transform it into the csv "tables" and insert them into sqlite tables for then query them.

But I'd leave this to a subsequent phase, as a improvement to the Extract part of the ETL. Wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

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

I like this as well! agree with @jxs this should be a next step rather than a requirement for the MVP.

Copy link
Contributor

Choose a reason for hiding this comment

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

I am okay with doing it in a follow-up if we think that the overall design holds.

Your reference to ETL is interesting. I hadn't considered that we can use the suggested table to then produce the current ones. I would have seen that as an unnecessary intermediate step but perhaps it is easier to implement if we do the generation in multiple steps, thus forming a pipeline.

.catch((err) => {
console.error(err);
process.exit(1);
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

(creating here just to get a thread)

pass all the test parameters (transport, muxer, protocol) when launching the container the work becomes a lot easier for the composer and we could also combine it with testground/testground#1522.
Does testground currently support passing env vars when launching containers @laurentsenta?

Yes, the idiomatic solution is to use the run parameters,
there is an example of this in the ping test:

secureChannel = runenv.StringParam("secure_channel")
maxLatencyMs = runenv.IntParam("max_latency_ms")
iterations = runenv.IntParam("iterations")

You'd pass the parameters in the runs directly or in the runs.group field:

[runs.test_params]
iterations = "5"

.then(() => process.exit(0))
.catch((err) => {
console.error(err);
process.exit(1);
Copy link
Collaborator

Choose a reason for hiding this comment

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

(another thread)

Wdyt of using just docker:generic to simplify the process @laurentsenta @mxinden?

If you want to tackle this question as part of this PR:

Initially, we planned on:

  • Implementing the test using testground builders + runners,
  • Rely on docker:generic and docker_extensions to implement missing features,
  • As we converge to a reliable solution, make the features Testground natives (add a docker:rust builder for example, and other simplifications).
  • With this approach, I would NOT recommend moving to docker:generic, but instead moving features into testground.

It seems we're now moving towards a different design:

- the first should be runtime parameters whereas version should be a
  build parameters
- separate Go and Rust git ref and target
@tinytb tinytb mentioned this pull request Nov 28, 2022
13 tasks
@p-shahi
Copy link
Member

p-shahi commented Dec 5, 2022

@jxs What's the remaining work to get the composer in (& promote to ready for review)? #88 is not using this yet right?

@MarcoPolo
Copy link
Contributor

@p-shahi i think we'll continue this work in #85. And we'll extend #88 to support this test matrix (#88 I don't think #88 is using this yet).

@p-shahi
Copy link
Member

p-shahi commented Dec 10, 2022

closing in favor of #85

@p-shahi p-shahi closed this Dec 10, 2022
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.

5 participants