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

impl: original integration test. #56

Closed
utam0k opened this issue Jun 2, 2021 · 37 comments
Closed

impl: original integration test. #56

utam0k opened this issue Jun 2, 2021 · 37 comments
Assignees

Comments

@utam0k
Copy link
Member

utam0k commented Jun 2, 2021

Youki is currently using the integration tests from rutime-tools, but there are some areas where this isn't sufficient (e.g. cgv2), so we will implement our own.

@niwatoliver
Copy link
Contributor

@utam0k I'd like to try it.

@utam0k
Copy link
Member Author

utam0k commented Jun 2, 2021

Sure! I assigned you to it. I'm looking forward your PR.

@niwatoliver
Copy link
Contributor

niwatoliver commented Jun 13, 2021

@utam0k

I would like to report that I was able to reproduce the container lifecycle of the tutorial on rust's cargo test, although it is still only in my repository.

And I have a few concerns that I would like to discuss with you.

  • I'm planning to run the test by using sudo to run the binary generated by cargo test --no-run, but is that OK?
  • The tutorial uses docker export $(docker create busybox) | tar -C rootfs -xvf - to create a rootfs, what should I do here in my test
  • I think the container created by youki create will be created in /run/youki, is there any problem to create it there when running the test?
  • I'm wondering how to delete the file created in /run/youki when the test fails.

As for the future roadmap, I would like to proceed as follows.

  1. start with youki create, write a test to see if youki start, youki state, youki kill, youki delete, etc. work properly, and I'll submit it as a pull request.

  2. I will implement the integration test with reference to https://github.com/opencontainers/runtime-tools/tree/master/validation

  3. I will add tests that runtime-tools does not seem to be sufficient.

Also, I would like to know if there are any high priority tests.

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Jun 19, 2021

Hey @minakawa-daiki ,sorry for delay in reply. If it is possible, can you try implementing the validation tests first? As once we have those, we can test the changes made on local system, currently the runtime-tools validation works in github action only, see discussion in #82 .

@utam0k can you take a look at the concerns? I think it would be fine to allow root requirements for running the tests, but it would be better to leave docket export part out of the tests, as it would force us to depend on docker being correctly configured and also the network status. It might be better to check if the rootfs folder exists in the root dir of project, and fail the test if it does not.

@utam0k
Copy link
Member Author

utam0k commented Jun 19, 2021

@YJDoc2 Thanks for your mention.

@utam0k
Copy link
Member Author

utam0k commented Jun 19, 2021

I think it is inevitable that you will need root privileges. I agree with the assumption that root privileges are required, although it is possible that rootless could be used to get around this.

As for rootfs, why not mimic runtime-tools and zip it up and put it in the repository first?

I'm planning to run the test by using sudo to run the binary generated by cargo test --no-run, but is that OK?
The tutorial uses docker export $(docker create busybox) | tar -C rootfs -xvf - to create a rootfs, what should I do here in my test

You can change the directory with the create argument, so run help and see what happens.

I think the container created by youki create will be created in /run/youki, is there any problem to create it there when running the test?
I'm wondering how to delete the file created in /run/youki when the test fails.

@utam0k
Copy link
Member Author

utam0k commented Jun 19, 2021

@YJDoc2 Sorry, he's actually a real friend of mine and I've been supporting him a lot on discord. Thank you for your attention. I'll use issues as much as possible to promote open discussion.

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Jun 19, 2021

Hey, I just thought that you missed the message, so I mentioned you 😅 Also, if possible, let us keep updating main points in issues, even if they are discussed elsewhere, not only for open discussion, but so that we will have history of issues and reason behind implementation at a single place, and can be referenced easily if needed 😃

@utam0k
Copy link
Member Author

utam0k commented Jun 19, 2021

@YJDoc2 Of course! I'll do my best to make it so.

@utam0k
Copy link
Member Author

utam0k commented Jul 28, 2021

@tsturzl @YJDoc2
This is one of the features that youki needs the most right now. However, I think there are still many things to be developed. How about getting collaborators involved to speed up the implementation?

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Jul 28, 2021

I agree. I think the work done by @minakawa-daiki has created a great base for integration tests 🎉

Currently we are using integration tests in runtime-tools, which only work in github CI/CD and does not seem to work on local machines, making it really hard to verify that changes made have not accidentally broken things elsewhere. Migrating all tests from runtime-tools to rust would not only allow us to confidently make changes, but reduce one of the external dependencies as well.

Currently there are around 56 tests in tuntime-tools, we can maybe make a separate issue for tracking how many are implemented , similar to cgroups tracking issues. I would really like to contribute in it as much as I can.

In case, list of test directories in runtime-tools/validation

config_updates_without_affect

create

default

delete

delete_only_create_resources

delete_resources

hooks

hooks_stdin

hostname

kill

kill_no_effect

killsig

linux_cgroups_blkio

linux_cgroups_cpus

linux_cgroups_devices

linux_cgroups_hugetlb

linux_cgroups_memory

linux_cgroups_network

linux_cgroups_pids

linux_cgroups_relative_blkio

linux_cgroups_relative_cpus

linux_cgroups_relative_devices

linux_cgroups_relative_hugetlb

linux_cgroups_relative_memory

linux_cgroups_relative_network

linux_cgroups_relative_pids

linux_devices

linux_masked_paths

linux_mount_label

linux_ns_itype

linux_ns_nopath

linux_ns_path

linux_ns_path_type

linux_process_apparmor_profile

linux_readonly_paths

linux_rootfs_propagation

linux_seccomp

linux_sysctl

linux_uid_mappings

misc_props

mounts

pidfile

poststart

poststart_fail

poststop

poststop_fail

prestart

prestart_fail

process

process_capabilities

process_capabilities_fail

process_oom_score_adj

process_rlimits

process_rlimits_fail

process_user

root_readonly_true

start

state

Currently the initial tests of container lifecycle depend on panics to indicate failure, maybe we can start by changing that to returning a result or something similar so we can get more information about the error? If that is a good idea, I'd like to try doing that.

What are your thoughts @utam0k @tsturzl ?

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 28, 2021

I'd be very interested in implementing the runtime integration tests for youki. I think it would be a great benefit for us to eventually build out cgv2 tests, since I think the testing there could be improved.

I agree that the tests output could be improved, and I'd be open to seeing how you're thinking to approach that @YJDoc2.

I think maybe breaking this out into a tracking issue like we've done for other things, and implementing each test from the oci-spec is a good way to start and break up the work. It can also provide some good issues for others to get involved with.

@utam0k
Copy link
Member Author

utam0k commented Jul 28, 2021

Of course it's a good improvement.

Currently the initial tests of container lifecycle depend on panics to indicate failure, maybe we can start by changing that to returning a result or something similar so we can get more information about the error? If that is a good idea, I'd like to try doing that.

@tsturzl @YJDoc2
I have made it an immediate priority to get rid of runtime-tools as a policy of youki. This was beneficial in the very early stages, but youki has outgrown that phase.
For the time being, I think the goal of this project is to make one test case into a flexible code design by using traits and so on.
In other words, it would be good to design the code in such a way that it is not difficult to add other test cases.
After that, I think it will be possible to deal with them in parallel as in the case of cgroup.
However, first of all, I think that achieving this first goal should be done by one person as much as possible, otherwise conflicts may occur.
Of course, I will support you, but if you are interested, would either of you like to take on the challenge? Alternatively, I'm willing to let two people I trust completely decide how to proceed with this project and the design principles.

@niwatoliver
Copy link
Contributor

I understand that you want to push forward with the test implementation as soon as possible.
I will leave it up to you guys to add the test cases, as I have some implementation speed issues.

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 29, 2021

Work has been a bit consuming lately, but I should hopefully have time starting in the middle of next month. I would be interested in taking this on and implementing a few vital pieces and maybe getting some feedback. Unless @YJDoc2 has some ideas here and is interested, or can start on it sooner. I've also been beginning to hack on #17 again, but I think this is generally more important and ultimately #17 would greatly benefit from this. I agree with the priority here.

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Jul 29, 2021

Hey, So I have been thinking and came up with two approaches for this:

  • Using a test trait
    This will define a test trait, which will have methods such as get_name() to get test's name, and test() which will run test and return a Result < ? , ? > . This will have to be registered to some TestController struct and then it can iterate over run each test and build the testanything testdata. For this each test will have to create an empty struct, and implement the trait on it. I think this will create a lot of empty structs for unnecessary reasons, as we are only interested in the test() implementation.

  • Using a static hashmap to store test functions
    This will define a lazy_static hashmap mapping test names to actual test functions which will have a fixed function signature, such as () -> TestBuilder etc. For each new test we need to add corresponding entry in this map. In main we can iterate over map, run the functions and use the returned TestBuilder (of testanything) to create a testsuite (of testanything). This way we can even pass test names as cmd arguments and filter specific tests. A drawback would be if we decide to eliminate testanything in future to use something of our own (as testanything mostly just proivdea a wrapper over println!, by conforming to TAP standards), we will have to change each function accordingly, but same would be true for trait implementation as well.

Do you think these could be useful with some changes, or should be try to do something else altogether @utam0k @tsturzl ?

I am a bit busy this week, so even if we decide on the idea, I'll start implementing this weekend or next week. Maybe we can come up with something better in meantime as well.

On a side note, I think we should hold creating the tracking issue of this until we have decided on this, and implemented lifecycle tests ; as otherwise contributors will start creating tests without having a format, and we will need to mend those later again to fit the format that we decide on.

@utam0k
Copy link
Member Author

utam0k commented Jul 29, 2021

@YJDoc2 @tsturzl
I'd like @tsturzl to prioritize #17, so I'd like to leave the integration testing to @YJDoc2 . What do you think?

Work has been a bit consuming lately, but I should hopefully have time starting in the middle of next month. I would be interested in taking this on and implementing a few vital pieces and maybe getting some feedback. Unless @YJDoc2 has some ideas here and is interested, or can start on it sooner. I've also been beginning to hack on #17 again, but I think this is generally more important and ultimately #17 would greatly benefit from this. I agree with the priority here.

This is the minimum feature that I would like to have, and if this is not possible with traits, then I suggest using hashmap.

This way we can even pass test names as cmd arguments and filter specific tests.

👍

On a side note, I think we should hold creating the tracking issue of this until we have decided on this, and implemented lifecycle tests ; as otherwise contributors will start creating tests without having a format, and we will need to mend those later again to fit the format that we decide on.

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Jul 29, 2021

I would like to work on this and let @tsturzl focus on #17 , hopefully I can create a good base for the cgroups v2 tests.

As for the implementation, I'm not saying it would not be possible with traits, we can make the test registering function take test name as well, but my problem with traits is that they will need empty structs to be implemented on, and for tests we would only be interested in the test function itself, so by using hashmap we would not need the extra boilerplate.

This is the minimum feature that I would like to have, and if this is not possible with traits, then I suggest using hashmap.

I'm waiting to hear @tsturzl 's thoughts on this, after that I'd start working of this.

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 29, 2021

@YJDoc2 I think the traits pattern is more familiar to some of the patterns already used in youki, eg the controller managers do dispatch in this way. I think the hashmap approach is simple, but seems less idiomatic and possibly like it could get messy. I think creating empty structs is mostly an issue with the code readability than the actual runtime. I think it'll also be more idiomatic Rust to use a trait. There is one solution I can think of for making the empty structs look cleaner, hide the empty struct creation with a macro and derive the test name and thus the struct's name from the function name using a procedural macro(might be hacky). I think perhaps one of the benefits for the hashmap is the ability to quickly find a given number of input tests names to run, however maintaining the order in which tests are invoked could be nice for readability.

I think either approach is fine, and perhaps the hashmap is a better way to start out, but eventually maybe the trait approach is going to be more extensible. For example you might eventually want something like a trait method which allows a test to check if it's runnable on that system, like a cgv2 controller might check to see that the subsystem is available on that system and then return a boolean, and then we can have 3 tests states like pass, fail, skipped. You could also eventually have setup and cleanup methods on a test, or even better you can just implement cleanup logic in the Drop trait of the struct and then actually store setup resources in the struct so it's not actually just empty. You could even have a struct represent a body of tests, and then have a reusable test type which takes a test function. I think the struct approach is just more extendable long term, but I do see immediate benefits in the second approach. It's possible even a hybrid of the 2 could turn out to be useful.

Maybe even something like this. A logical grouping of tests are an entry in a hashmap, the grouping is a struct that implements a "TestGroup" trait, the tests within the group are just a reusable test type which takes an anonymous function like Test::new("1 plus one test", || assert_eq!(1+1, 2));. This way tests withing a group run in order for readability, or even if they are dependent in some way. Setup resources can be shared if need be between tests by access via closure, and a Drop trait on the Test and the TestGroup can be used to ensure cleanup. This way you only define one struct per TestGroup and you have a reusable Test type you can use to create tests. Maybe that Test type can implement a trait Testable and you can even have multiple test types, like one that uses std::panic::catch_unwind to invoke the test function so you can use regular asserts, and another test type which allows you to return your own Result, you could get fancy and make a Test type which does something like run a test function and then automatically go in and check the value set in a cgroup file. Just rattling off a few things that come to mind, but I think an approach like this would be incredibly composable, extendable, and reusable.

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 29, 2021

trait TestGroup {
  fn run_tests() -> Result<()>
}

trait Testable {
  fn get_name(&self) -> String
  fn run_test(&self) -> Result<()>
}

struct AssertTest<F: FnMut() -> ()>{
  name: String,
  fn: F
};
impl AssertTest {
  fn new(name: &str, fn: F) -> AssertTest {
    AssertTest {name, fn}
  }
}
impl Testable for AssertTest {
  fn run_test(&self) -> Result<()> {
    std::panin::catch_unwind(self.fn);
  }
}

struct ResultTest<F: FnMut() -> Result<()>>{
  name: String,
  fn: F
};
impl ResultTest {
  fn new(name: &str, fn: F) -> ResultTest {
    ResultTest {name, fn}
  }
}
impl Testable for ResultTest {
  fn get_name(&self) -> String {
    self.name
  }
  fn run_test(&self) -> Result<()> {
    self.fn()
  }
}

struct SampleGroup;
impl TestGroup for SampleGroup {
  fn run_tests() -> Result<()> {
    AssertTest::new("1+ 1 = 2", || assert_eq!(1+1, 2)).run_test()?;
    ResultTest::new("someFn returns OK", || someFn()).run_test()?;
  }
}

Something loosely like this is appealing to me, you could collect tests for a group into a static array or even a vector and then run them, or you can even just invoke them inline like I did here.

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 29, 2021

Might even be worth having our own Test type which is from-able from a anyhow::Result. Something like a TestResult, and this has 3 states which are Ok(T), Err(E), Skip. Skip is good for cases where a test isn't runnable on a system, eg you don't have support for a given cgroup controller. The TestResult can just implement From for the result type we expect, so it's easy to just turn a anyhow::Result<()> into a TestResult for example.

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 29, 2021

You could even just have a TestGroup be an array of Testables inserted into a hashmap instead. If the given Testable's don't fit a specific usecase you can always make case specific Testable types as well, but for the most part I imagine you can just make reusable Test types with it. Sorry if this was a long rant, but these were some of the ideas I had for a composable and reusable test framework.

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Jul 30, 2021

Hey, these are some great ideas! Thanks for sharing them.
No it was very insightful , and will definitely make the test spec better. As this is such an important part, discussion is needed.

Sorry if this was a long rant, but these were some of the ideas I had for a composable and reusable test framework.

I agree that my issue with traits was more of readability and boilerplate, than usage, and traits would in fact be more idiomatic.

I think creating empty structs is mostly an issue with the code readability than the actual runtime.
I think the traits pattern is more familiar to some of the patterns already used in youki ...

The main reason for suggesting a hashmap was to be able to get the tests quickly from their names, but I agree it is less idiomatic, and might get messy to manage later. Although the constraint that the tests should be run in a consistent order , which hashmap will not guarantee, can be solved by using a BTreeMap, which maintains a fixed order, but still we cannot define a particular order we want, so using a vec might be better solution in long run if we need tests to be ran in a particular order only. ( though this will mean that we will need to iterate over all vec when only cmd specified tests are to be run.)

In my opinion, the suggestion of making a trait for group tests, even though elegant and useful in long term, might be too complex for implementing and using in the beginning, so my suggestion would be to start with only a Testable trait, and then as need will arise, introduce appropriate traits.

I might not be understanding what you wanted to say, but I do not agree that a test groups should share the setup resources ; using a common method to do setup and tear down is quite sensible, but using same setup across tests might not be a good idea, as a failing or panic-ing test might leave them in undefined state, and the next tests might also fail due to that.

You could also eventually have setup and cleanup methods on a test, or even better you can just implement cleanup logic in the Drop trait of the struct and then actually store setup resources in the struct so it's not actually just empty.

I think your point to use a macro to hide the implementation of test is great, and I have some ideas for that.

There is one solution I can think of for making the empty structs look cleaner, hide the empty struct creation with a macro and derive the test name and thus the struct's name from the function name using a procedural macro(might be hacky).

For the beginning, what do you think of this

enum TestResult<T,E>{
    Ok(T),
    Skip,
    Err(E)
};

#[bitflags]
#[repr(u8)]
enum TestGroup{
    NoGroup = 1<<0,
    CGroupV1 = 1<<1,
    CGroupV2 = 1<<2,
    TLBCheck = 1<<3 
}

trait IntegrationTest{
    pub fn name()->String;
    pub fn group()->BitFlags<TestGroup>;
    pub fn test()->TestResult<(),String>;
}

// to actually write a test

#[integration_test(test_group = CGroupV1|TLBCheck)]
fn my_integration_test()->Test<Result,String>{
    // do test...
}

// integration test will be a proc macro which will generate following
pub struct my_integration_test;
impl IntegrationTest for my_integration_test{
    pub fn name()->String{
        "my_integration_test".to_string()
    }
    pub fn group()->BitFlags<TestGroup>{
        TestGroup::CGroupV1|TestGroup::TLBCheck
    }

    pub fn test()->TestResult<(),String>{
        // do test
    }
};

// in main() we can register test something like :
...
test_manager.register(my_integration_test);
...

Where birflags are used from crate enumflags2, which allows bitflags to be set using rust's enums. the test_manager will be a controller struct, which will store tests internally , probably in a vec, and also store them group wise in a hashmap , so when running specific groups we can retrieve those specific tests quickly.

I specifically kept the functions in the trait static, instead of instance, because of the point I mentioned above that resources should not be shared, but if needed we can change that as required.

Using such traits, we can define custom grouping as well if certain logic is common across several tests using custom traits.

My current thoughts of cmd interface are something like this

# to run all tests, -p is path to the runtime
integration_test -p ./youki 
# to run specific tests
integration_test -p ./youki -t test1 test2 test3
# to run specific groups
integration_test -p ./youki -g group1 group2

What are your thoughts on this?

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 30, 2021

@YJDoc2 you're probably right with the fact that groups shouldn't share any resources, so the ability to do a drop trait there isn't all that useful. We can kinda maintain the order it a BTreeMap by making our own key type and doing hacky things, but they're just that, hacky things. Order of test execution is less of a hard requirement and more of a nice to have, a BTree might be good enough too since I'm mostly after just having the output look the same each time.

I'm kind of in favor of my later idea. I think having some predefined and reusable Test structs that implement some Testable trait might be better than the proc macro approach. Like you just have a Test struct and you pass a name, a function, and optionally some other args(depending on what the Testable type does). Then you're not creating a struct for each test your just creating an instance of one of the Testable types.

Enums for groups might work. I suppose I was thinking of a group as a granular unit similar to oci-spec test. Like the ability to just run the group of tests pertaining to say the cgroups v1 cpu subsystem. Then you can call an entire group or an individual test or set of tests from a group like 'test-cmd group1 group2::a group3::a,b,c' which runs all of group1, one test of group2, and 3 tests of group3.

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 30, 2021

Maybe in the morning I can write a more comprehensive example of what I'm thinking.

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Jul 30, 2021

Sure, I will also think some more on your as well as my approach in the meantime. Thanks!

@utam0k
Copy link
Member Author

utam0k commented Jul 30, 2021

@tsturzl @YJDoc2 The overall direction of this project is much better than I thought it would be. As long as we don't deviate too far from this direction, I'll leave the decision to you two. Excellent!

@tsturzl
Copy link
Collaborator

tsturzl commented Jul 30, 2021

@YJDoc2 This is a comprehensive example of what I'm thinking to combine parts from both our ideas based on our discussion thus far. This avoids having to define structs for each test all together, and therefore also avoids the complexity of making something like a proc macro, and I think has the most reusability and should be clean and relatively easy to start out. I don't think a lot of boiler plate is involved. I decided to go with BTreeMap to keep ordering, HashMap should work just fine too. I kept the concept of a test group because I think it's useful, and I just made it a reusable type so no need to define a new struct, it also adds a lot of reusable methods for groups which I think will be useful. I kept the idea of using lazy statics here so you can have a lazy static for each test group to define a singleton, and then at the top level there is a lazy static BTreeMap which holds all the TestGroups, this should give you O(l(og n) m) time for provided tests to run both for running entire groups or specific tests within groups. I think this design isn't too complicated, hard to implement, and I think it's relatively extensible. I think it's well worth the time to start out with good abstractions that can be built upon. I think the one major place for improvement might be obscuring the ugliness of creating the lazy statics using purpose built macros. I put the code in a gist in case you want to fork it and edit it, also it's just a lot to post in an comment.
https://gist.github.com/tsturzl/c7623bffddc6e7bb797b2c77394fd17e

@utam0k
Copy link
Member Author

utam0k commented Jul 31, 2021

lazy_static is also well known, and once_cell has been heard a lot lately. I'll leave the choice up to you, but just for reference.
https://docs.rs/crate/once_cell/1.8.0

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Jul 31, 2021

Hey @tsturzl I saw your code, and I agree with most of your code, but I still don't agree that TestGroup should be a structure 😅

I would instead suggest that we use bitflags to specify which group a test belongs to. This will allow a test to be part of multiple groups if needed, as well as give granular control over test to be run.

In the code you suggested, we will need to specify the tests as group1::test_1,test_2 etc. on cmd , that ends up giving names of tests anyways, (test_1,test_2); so we may as well just give names of the tests themselves , and specify the the groups separately as needed. I have updated your gist with my suggestion of bitflags, so please take a look : https://gist.github.com/YJDoc2/ad9f46c393e45819c8c7f853e6aec3d1
As far as lazy_static or once_cell , I think that would be better decided once started with implementation.

@tsturzl
Copy link
Collaborator

tsturzl commented Aug 2, 2021

I think bitflags for groupings is fine if that works better or looks cleaner. I guess I just see it as cleaner to have a group own the tests it runs versus the tests own which group them belong to; you end up specifying the group for every test you have rather than creating the test and then specifying group once for all the tests, it's just more repetition and kind of the inverse of how you'd probably logically think of the problem. You can create all the groups and then populate them later, and test groups can own a lookup structure for the tests they own. Like in my example a group has its own Map for quickly filtering lookups.

I think having granular groups is also important, that's exactly how the original tests are, and I think more often you'll want to run a group of tests pertaining to what you're working on. Like I want to run all the cgv2 memory controller tests because that's what I'm working on, maybe 2 tests are failing and I already know the group so saying 'cgv2_memory::test1,test2' is relatively easy and then the collision of test names isn't a worry by considering test names to be in a global namespace, because cgv1 and cgv2 might have the same test names, and if you start making more verbose test names like "cgv2_memory_max_limit", "cgv1_memory_max_limit" there isn't a ton of efficiency gain from just typing out a group "cgv2_memory::max_limit". In fact I'd argue that there are cases were filtering by group then test is more efficient since you can do "cgv2_memory::test1,test2'" instead of "cgv2_memory_test1 cgv2_memory_test2", which I think will be relatively common.

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Aug 3, 2021

Hey, So I have been thinking for last couple of days, and after reading your comment, I can see that the group method would be better 😅 Initially I was thinking that most of our run cases would be either all tests, or particular named tests and groups, but then I realized that either we would run all of our cases or a specific one which has issues, and with your argument about groups providing namespacing, I agree that tests as part of group rather than groups as a part of test would be a better strategy.

Sorry for such a long discussion over this 😓 I will now start implementing this framework as an individual crate inside our repo, similar to oci-spec and current rust implementation of integration tests. Thanks for all the help,discussion and comments :)

@YJDoc2
Copy link
Collaborator

YJDoc2 commented Aug 3, 2021

Also I was thinking, would it be possible and useful to set up a CI step in github actions once we start implementing this? The step would essentially compile only the integration tests, and run that against runc and/or some other runtime, to validate the tests themselves. This step is easy to manually do locally as well, and including in CI would just make sure that the tests we make are satisfied by "production" runtimes as well. I would also like to know @utam0k 's thoughts on this.

@tsturzl
Copy link
Collaborator

tsturzl commented Aug 4, 2021

@YJDoc2 no worries! I hope I wasn't too critical. I think having lazy_statics does simplify the design and I wasn't previously aware of that pattern in rust. I'm excited to see how it turns out. As far as having CI tests for the integration testing framework my opinion would be that we don't want to tie in the workflow actions for testing against runc into the youki repo, so I'd either say we should just omit it from CI or think about breaking out into another repo.

Per another conversation I think oci spec is breaking out to its own repo possibly now since it's also useful in other projects in the container group. I'd actually say that these integration tests could end up being useful for other projects, such as testing against crun which is also in the container group. My hunch would be it's a bit early to move this out into it's own repo, and with that I think it's probably best to leave it out of CI. However I think there might be a comfortable medium here. You could make an entirely new workflow for testing the integration suite against runc, and then have some other trigger (eg just a manual invocation). That way we can at least reference these test results easily in GitHub. It might not be as nice as having automatic tests run, but I don't know if we want to convalute youki CI with testing integration tests against runc.

That's just my opinion. I'm also interested in what @utam0k thinks, and perhaps that can start the bigger conversation of eventually growing this aspect of the project into it's own efforts to replace oci runtime spec all together with our own implementation that addresses some of the issues we've run into along with supporting things like cgroups v2

@utam0k
Copy link
Member Author

utam0k commented Aug 4, 2021

We believe that this integration test will be very useful for the field of container runtime. If it works well, I will consider separating them into different repositories, but I think it's too early to do that now, since managing separate repositories is more or less a burden.

Per another conversation I think oci spec is breaking out to its own repo possibly now since it's also useful in other projects in the container group.

I think it is a good idea to use runc to verify the correctness of the integration test itself. However, I also think it is better to be able to run them manually. Or, how about running it only when there is a change in the codes in the integration test directory?

@utam0k
Copy link
Member Author

utam0k commented Aug 4, 2021

This is ideal, it would be great if users could add tests in the form of plugins. For example, I think it would be a very good project if we could add tests with wasm. However this is for use outside of youki, so I think it should be optional.

@utam0k
Copy link
Member Author

utam0k commented Oct 24, 2021

This issue has played a role in the initial discussion about integration tests. The rest of the discussion about the integration test should be sufficient #361.
Special thanks @minakawa-daiki @YJDoc2 @tsturzl

@utam0k utam0k closed this as completed Oct 24, 2021
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

No branches or pull requests

4 participants