Skip to content
This repository has been archived by the owner on May 24, 2022. It is now read-only.

[test_runner] Prepare support for cleanup steps #118

Closed
wants to merge 1 commit into from
Closed

[test_runner] Prepare support for cleanup steps #118

wants to merge 1 commit into from

Conversation

marcoguerri
Copy link
Contributor

@marcoguerri marcoguerri commented Jun 15, 2020

This PR goes into two directions:

  1. Adds support for the concept of cleanup steps. The syntax to define cleanup steps is the same the one for test steps. The concept of TestStep has been renamed into generic Step, as it now can represent both a test step and a cleanup step.
  2. Fixed the handling of steps descriptor, which I think has several problems:
    • The TestDescriptors which was added to Request object in my opinion in not at the right level of abstraction. TestDescriptors should be inside the JobDescriptor, which is also included in the Request object.
    • One of the reasons to persist TestDescriptors into the database is obviously because we want to be able to rebuild the status of the job, even if the test description underneath has changed. But the PR that introduced the changes to persist TestDescriptors in the database, did not add support for actually re-reading those descriptors when calculating job status. So the result is that when the status is calculated, we fetch again the description from the original source (which might have changed meanwhile)

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 15, 2020
@marcoguerri
Copy link
Contributor Author

marcoguerri commented Jun 15, 2020

The Request object before this PR would look as follows:
Request

In my opinion TestDescriptors should not live as first level field in the Request object, but it should be instead part of the JobDescriptor. The description of the steps is not necessarily part of the initial JobDescriptor submitted by the user, whose deserialization looks follows:

Descriptor

(note that TestDescriptor does not contain the JSON text which defines the steps, but only the references to target manager + parameters and test fetcher + parameters).

In this PR, I introduced the concept of ExtendedDescriptor, which looks as follows:
ExtendedDescriptor

Basically it's a Job descriptor extended with the information of steps descriptors, for all tests. The Request object then embeds an ExtendedDescriptor, which is then persisted in the database.

NewRequest.

Similar issue as above was affecting also the Job object
Job

Among several other fields, the Job object would embed TestDescriptors. Also in this case I think the TestDescriptors should have been referenced separately from the larger job description, so now the Job object contains a reference to an extended description, i.e.:
NewJobDescriptor

Together with these changes, we now have two constructors for Job objects:

  • NewJobFromDescriptor, which builds a Job object and fetches the descriptions of the steps via the TestFetcher
  • NewJobFromExtendedDescriptor, which builds a Job object by using a description of the steps given in input. This is the constructor used when requesting status: the extended descriptor is extracted from the database and used as is.

WARNING: one problem of this approach is that it breaks the backwards compatibility of Status requests. Let me know if you have concerns about this. My plan would be to migrate previous jobs to this extended description in the db.

@codecov
Copy link

codecov bot commented Jun 15, 2020

Codecov Report

Merging #118 (a3b0414) into master (bf421f7) will decrease coverage by 0.49%.
The diff coverage is 62.32%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #118      +/-   ##
==========================================
- Coverage   61.50%   61.01%   -0.50%     
==========================================
  Files          82       85       +3     
  Lines        3920     3937      +17     
==========================================
- Hits         2411     2402       -9     
- Misses       1219     1244      +25     
- Partials      290      291       +1     
Flag Coverage Δ
integration 58.12% <61.97%> (-0.64%) ⬇️
integration_storage 100.00% <ø> (ø)
unittests 27.61% <14.10%> (+0.44%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
cmds/plugins/plugins.go 0.00% <0.00%> (ø)
pkg/cerrors/cerrors.go 33.33% <ø> (-33.34%) ⬇️
pkg/jobmanager/jobmanager.go 62.16% <ø> (+6.65%) ⬆️
pkg/jobmanager/status.go 0.00% <0.00%> (ø)
pkg/pluginregistry/errors.go 0.00% <0.00%> (-100.00%) ⬇️
pkg/target/target.go 25.00% <ø> (ø)
pkg/test/step.go 66.66% <ø> (ø)
plugins/targetlocker/noop/noop.go 81.81% <ø> (ø)
plugins/testfetchers/uri/uri.go 1.78% <0.00%> (-0.18%) ⬇️
plugins/teststeps/cmd/cmd.go 40.90% <ø> (ø)
... and 45 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bf421f7...a3b0414. Read the comment docs.

Copy link
Contributor

@xaionaro xaionaro left a comment

Choose a reason for hiding this comment

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

Related to 6cd7140, only

LGTM

return runReporterBundles, finalReporterBundles, nil
}

func newBundlesFromSteps(descriptors []test.StepDescriptor, registry *pluginregistry.PluginRegistry) ([]test.StepBundle, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a thought: may be newStepBundles is a more consistent name here? And the function below may be should be named something like newStepBundlesPair?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mh... the intention of this naming was to highlight that the bundles here are created from descriptors passed directly as part of the signature of the function, rather than fetched inside the function. I feel this information is lost with the naming suggested?

Copy link
Contributor

@xaionaro xaionaro Jul 30, 2020

Choose a reason for hiding this comment

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

Nah, it is clear from naming that it will construct bundles based on given steps. OK, makes sense. Though there's no such hint in the function below.

if err := td.Validate(); err != nil {
return nil, fmt.Errorf("could not validate test descriptor: %w", err)
}
bundlTargetManager, err := registry.NewTargetManagerBundle(&td)
Copy link
Contributor

Choose a reason for hiding this comment

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

A typo: bundlbundle

TestStepLabel string
Parameters TestStepParameters
// StepsDescriptors bundles together Test and Cleanup descriptions
type StepsDescriptors struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

All this entities are mixing-up in my head :)
If I understand correctly we usually use term Descriptor for serialized values. It confuses me a little-bit.

I need to draw a chart of these entities.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, the intention since the introduction of these terms has been to use Descriptor as something that results from a deserialization, and Bundle as a collection of instances coming from instantiating objects based on the Descriptor.

pkg/jobmanager/job.go Show resolved Hide resolved
pkg/jobmanager/job.go Show resolved Hide resolved
@marcoguerri
Copy link
Contributor Author

Re-basing, then addressing all comments.

pkg/test/step.go Outdated
Cleanup []StepDescriptor
}

// StepBundle contains the instantiation
Copy link
Contributor

Choose a reason for hiding this comment

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

Instantiation of what? I don't think I have understood what a bundle is yet :D

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh is this the golang datastructure version of StepDescriptor?

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 often pass out while writing comments. So, a Descriptor object is something on which we deserialize raw JSON. From a Descriptor, we build a Bundle, which holds the instances (e.g. of the Step) that were built from the Descriptor. I came up with this naming, but now I am not very happy about this naming, so I am definitely open for changing this (so for all the alternatives which came to mind are worse :/)

pkg/job/job.go Show resolved Hide resolved
@dimkup
Copy link
Contributor

dimkup commented Jul 30, 2020

As far as I understood, StepDescriptor ([]test.StepsDescriptor) is actually, khm, part of job's state. Could it be named as <Cached|Resolved|Fetched|Prepared.. etc>StepDescriptor, just to reflect that it's an execution artefact, not input data?

Also it would be handy to allow to read Events at least for Cleanup steps. (ie pass ev testevent.EmitterFetcher as a parameter to Run) I understand that it's pretty invasive and backward compatibility breaking change, but probably it's better to group such changes together.)

@marcoguerri
Copy link
Contributor Author

marcoguerri commented Jul 31, 2020

@dimkup , you comment seems to be going in the same direction as @xaionaro comment (with respect to s/NewJobFromExtendedDescriptor/RestoreJobFromExtendedDescriptor. It could actually be input data. When the job is first submitted, []test.StepsDescriptor is the result of the output of the TestFetcher plugin. Then it is also serialized in the db and when resuming jobs, the fetched version will be used. In my opinion this design is relatively easy to reason around, I don't feel the strong need for a renaming.

As for reading events, yeah, it would be probably necessary, though it needs more thinking. The idea of allowing test steps to read events was originally there, though it was reflected only on the Resume signature (Resume(cancel, pause <-chan struct{}, ch StepChannels, params StepParameters, ev testevent.EmitterFetcher), which none of the steps implement yet. This could be ported also to Run, but it wouldn't serve the purpose that you probably have in mind. Every emitter has metadata which allows fetching events that only the same step emitted (one of the purposes was to keep track of state for Resume, hence the read capabilities in the Resume signature). I think we did not want for a Step to be able to read any event, because that might lead into message passing behaviors between steps which might be abused and result in test flows very difficult to follow/debug.

@marcoguerri
Copy link
Contributor Author

We discussed that before landing this, we want to have a tool which allows for schema migration ready, and start versioning the db schema. It's going to take a while longer to get there. I am targeting next week to make it happen, as I really want to get it done with this stack of PRs). For the moment, I'll put this on hold.

@marcoguerri
Copy link
Contributor Author

Resuming and rebasing this, after #154 was merged.

@marcoguerri
Copy link
Contributor Author

marcoguerri commented Dec 21, 2020

Being superseded by #208, there are still some relevant changes in this PR which I will port to a different PR.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants