-
-
Notifications
You must be signed in to change notification settings - Fork 666
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
Is it possible to write my own decorator? #892
Comments
hey @markxnelson - one of Ginkgo's foundational assumptions is that your specs (i.e. the individual Rather than explore your use-case in terms of solutions (decorates/arbitrary sets of conditions/etc.) I'd love to explore the problem more deeply with you to help point you at possible solutions Ginkgo and Gomega can provide today. Can you say more about your setup and what behavior you're trying to test? It sounds like you're testing how your produce behaves after an upgrade. And that you have a few basic tests to run on the old version followed by some extensive tests of the product after the upgrade, which you'd like to parallelize. Is that right? Are there other tests in the suite as well? It would help to know about your k8s tenancy requirements. Can you have multiple instances of your product on the same k8s cluster at different version levels? Or do they each need a dedicated cluster? I can think of a number of approaches to solve for this use case using what's in the box today... but knowing a bit more would help. |
Hi @onsi - you are right, yes, I am trying to test the actual upgrade to make sure that upgrading works. So I install an old version, do a few tests to make sure it is all good, then perform an upgrade, then the bulk of my tests are checking that the upgrade did what I expected it to do, and so I do need a little bit of order and I want those last batch of tests to be parallelized. I was aware of the assumptions :) and I think that test independence is a great thing. We have a lot of tests we run, all with Ginkgo, and for almost all of them, those assumptions are totally fine. I just have a very small number of tests where I do need to do some things in a particular order, in order to test some feature. Upgrade is the prime example of that. Our product can currently only have one instance in a k8s cluster. We run tests on ephemeral clusters though, and on different variants and versions of k8s. The structure I outlined in the first post does actually work and do what I need, but I'm concerned that it will be difficult to maintain as people visiting the test code later might not have a good mental model of the sequence of events that I am kind of artificially constructing there, and it would be easy to make a mistake and invalidate the test. |
Thanks @markxnelson - make sense. Given that what I'd personally do in a situation like this (and this may be more about subjective style/preference than anything else) is actually make a new test suite (called Alternatively, if your var DescribeUpgraded = func(text string, body func()) {
Describe(text, Offset(1), func() {
BeforeEach { wait until the upgrade in the other spec finishes }
body()
})
} which would let you write DescribeUpgraded("magic happens", func() {
It {}
It {}
}) I could imagine some sort of support for custom decorators that basically get a chance to inject arbitrary nodes into a container node. Though I'd need to think through the design and implications a bit more before building it out. Last thought - one thing I'd worry about with the |
Thanks, I will have to read up on |
❤️ thanks for the kind words!
ooh... that's interesting. can you say more? Right now you have to mark individual specs/containers as |
Yeah, so by "safe" and "unsafe," I really mean whether they can share a cluster. For example, we have tests that test installing our product, upgrading our product, uninstalling our product. Those need to run in their own dedicated clusters because they are destructive. |
I had a random crazy thought - and this is probably not a smart thing to do, but ... What if I did something like make a func that takes a slice of
but with the It blocks, not just regular funcs ("assertions" in this snippet). I guess then I'd get some parallelism, but all in one process, and I assume it'd upset Ginkgo. |
yeah that wouldn't play well. the And then possibly some investment in getting it so you can run |
Yeah I think I am leaning towards something like that - a shared library of funcs to do those kinds of things. :) |
We currently have a scenario where we run all the parallel test cases (which gives us enough signal to understand what is wrong), and only run the serial ones if none of the parallel test cases has failed. We are now switching to using Serial, but can't find that ability. Is that possible? |
hey @dhiller I don't think this is easily doable right now. A couple of options you can use today:
ginkgo -p -label-filter="!serial"
if [ $? -eq 0 ]; then
ginkgo -label-filter="serial"
fi
On the Ginkgo side of things I think the way I'd want to approach this is to add a new |
Thanks for your insights and the fast answer! Yes, as you said, we don't want to use Regarding 2.: Yes, this is what our current setup based on bash does, but we'd really like to get rid of that quite complicated bash code, use Serial decorator and leave it up to the Ginkgo test runner to handle it. The reason for this is the problems we had with handling of multiple output files for Junit which we need to merge in a follow up step, and problems regarding duplication of test names and stuff. I'm currently working on this here, that's why I am asking. I am going to split the PR into parts to have the Serial decorator and changes on Ginkgo side ready anyway, and keep the logic as is until until you have support for the Thanks again and have a happy thanksgiving :) |
I had a thought that the generalization of this is something like a staged approach where you only want to run the next stage where the previous one has succeeded. But that of course is already present in CI systems like Jenkins, and not sure whether it makes sense to rebuild this for Ginkgo. |
Hey @onsi! While I was revisiting the topic after quite a while I've been looking into the codebase and I haven't seen anything regarding Do you still have plans to implement this? Thank you! |
hey @dhiller - yes, still have plans but have struggled to invest as much time as I'd like in Ginkgo the last few months. I haven't lost sight of it though! I'm also wanting to invest in better supporting the underlying usecase behind this thread: namely being able to better control parallelization and ordering of things in large complex integration suites. I have some ideas percolating and hope to have a draft proposal out.... eventually :/ |
I wanted to do this today, but not as away to change ordering but to inject common values into the context.Context that is passed to each test. In our case we want to insert idempotency keys, and request identifiers in almost every test. And I think, in general, testing contextual stuff with Ginkgo often involves adding a lot of withValue lines at the start of a test (also for user sessions, middleware stuff, etc). A way to hook into Ginkgo unilaterally to inject these values might be desired. As an example, this is what we do now (notice the "IDed" wrappers we need to include everywhere): var _ = Describe("user", func() {
var mdl model.Model
var tx pgx.Tx
BeforeEach(tests.EnsureIsolatedTx(&tx))
BeforeEach(tests.EnsureModel(fx.Populate(&mdl)))
It("should setup model", tests.IDed(func(ctx context.Context) {
}))
It("should create and list users", tests.IDed(func(ctx context.Context) {
}))
It("should create and list organizations", tests.IDed(func(ctx context.Context) {
}))
}) It would be nice if we could do something like this: var _ = Describe("user", tests.IDed, func() {
var mdl model.Model
var tx pgx.Tx
BeforeEach(tests.EnsureIsolatedTx(&tx))
BeforeEach(tests.EnsureModel(fx.Populate(&mdl)))
It("should setup model", func(ctx context.Context) {
})
It("should create and list users", func(ctx context.Context) {
})
It("should create and list organizations", func(ctx context.Context) {
})
}) this is the "IDed" function we use now
|
hey @advanderveer sorry for the delay - i've been out of pocket for a few weeks. A similar (not identical) set of questions was raised on this issue. I could imagine a generic transformer decorator of type All in all your proposal sounds interesting to me. Do you mind opening a new issue so we can discuss it in more detail? |
This sounds exciting, sorry for the delay in this, I've created the following issue: #1404 |
Hi, thanks for the great project!
I would like to write my own decorator, so I could do something like specifying the requirements for a particular node, and get control in my decorator handler code to "make right" before that node gets to execute. Is it possible to do something like this?
I know I could use a BeforeXX to do this kind of thing. I have some tests that have some timing/dependency requirements. I can do what I need with a structure like this:
This is a bit awkward/artificial - I have to run the two Describes in parallel, and the second one is really just waiting until the first one finished. This is important to me because in reality there are way more than two It nodes in there, and some of them take minutes to run, so I want to be able to run them in parallel. I cannot use one big describe, because once I decorate it with Ordered, everything in it is run in order. If it were possible to mark a node inside an ordered node as "parallel" that'd also solve my particular use case.
If I could provide my own decorators, I could do something like
This would let me centralize that "wait until the upgrade in the other spec finishes" code and reuse it in many tests, rather than needing to put it BeforeEach's all over the place.
I guess my meta-need is to be able to put a decoration on a node that I can use to specify some arbitrary set of conditions that must be met before that node starts executing. Sorry if this is a bit of a ramble, hope to hear back from you with your thoughts.
By the way, the slack link on the main README does not work, it just takes you to a page that asks for the slack workspace name.
The text was updated successfully, but these errors were encountered: