Closed (fixed)
Project:
DrupalCI: Test Runner
Component:
Testrunner Codebase
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
31 Dec 2015 at 01:42 UTC
Updated:
11 Nov 2016 at 01:54 UTC
Jump to comment: Most recent
drupalci relies on a static Output class to manage telling things to the user.
There are a number of problems with this:
Output with calls to the injected output.Output::error().symfony/console to 2.8 so we can use the new styles feature. This requires an upstream change to nickschuch/privatetravis, which has a hard version constraint on console which seems arbitrary.
Comments
Comment #2
mile23Comment #3
mile23Comment #4
mile23Asked Nick to bump up the console version: https://github.com/nickschuch/PrivateTravis/issues/35
Comment #5
jthorson commentedPrivateTravis isn't currently used in the codebase - it may still be useful for travis.ci file compatibility in the future, but don't postpone on any PrivateTravis dependencies in the meantime.
Comment #6
jthorson commentedOh ... and a big +1 to the style features!!!
Comment #7
mile23OK, so if privatetravis isn't really a dependency, then lets pull it from composer.json.
Comment #8
jthorson commentedWork pushed to 2642636-introduce-logger branch.
Comment #9
jthorson commentedSo far:
- Added LoggerProvider (using standard Console logger)
- Converted Build, Run, Pull, Status, DockerRemove and DrupalCICommandBase to use logger
Comment #11
mile23Before we get too far down this road, let's add some tests so we're sure we're not leaving a trail of spare parts: #2676854: [meta] Write functional tests to prevent regressions
Comment #12
jthorson commentedThat's a hell of a catch-22 ... We can't write effective tests until we decouple the code, and we can't decouple the code until we have tests.
I'm not really interested in writing tests for coverage of things that we're trying to rip out. This work starts to give us the decoupling needed to write effective tests ... and while I agree that having tests would be ideal, that task becomes much easier AFTER this work goes in.
For what it's worth, I perform a full end-to-end test run as a functional test before ever posting my work here ... and I'm growing more than a little frustrated with the combination of "We need to restructure because we can't build effective tests" and "We can't change until the tests are written" messages I keep hearing.
Comment #13
MixologicFull 'end-to-end' test is inadequate to establish that changes do not introduce functional regressions, as it only exercises a single path through the system. What we're aiming to have is a real 'end-to-end' test that excerises all the edge cases in the system, in an automated fashion.
Right now, we aren't planning on ripping out any functionality, we're planning on restructuring code and refactoring things to reduce coupling, and improve maintainability, and additionally, add functionality. But what the code actually *does* still needs to work, so we need to set up the way we're going to prove that it does.
The *only* major refactoring we'd really want to do right now is something that can get us multiple separate jobs (i.e. run simpletest and run phantomjs as part of the same run).
So, given that, if we start building tests around what drupalCI currently does, we can continue to prove that it does what it needs to do, thus giving us confidence that we can accept changes moving forward. Certainly some tests will break if we change what we're doing, and they are supposed to.
And to be clear, we're not talking about writing unit tests for granular classes, we're talking about writing functional tests that prove that given a particular configuration, drupalci can effectively run tests and produce expected output.
Comment #14
jthorson commentedSo ... essentially, what you're saying is that, given a particular configuration, we want to ensure that we can run tests and produce expected output ... which ...
As I said ... it's really quite difficult rationalizing the conflicting messages. :)
Comment #15
dawehnerWell the point of end-to-end tests are that you are able to cover the basic usecase of a system. By definition they don't cover all edge cases, but they are really not the point of it. I really don't see why a end-to-end test would be problematic. It helps to cover really problematic regressions quickly.
Comment #16
jthorson commentedTo be clear, I'm not arguing against implementing automated end-to-end tests ... my point is that, in the absence of such a test existing today, we should not be blocking code which simplifies the the overall testing effort and provides us the decoupling that we're looking for, based solely on the argument that "We might introduce regressions".
It takes about 45 seconds to manually execute an end-to-end simpletest test run (i.e. on a single test group), which gives us the same level of test coverage and same assurance that we have not introduced any regressions as we would get from an automated functional end-to-end test based on the same inputs. I've been hearing "We need more tests" for six months now, and they haven't been materialzing ... this mantra is stifling innovation and putting a significant drag on the addition of new features into the project. Code (such as support for testing on minor php versions) has sat in the queue for 6 months with no review, because we're being told "It's not worth reviewing until we have tests." Yes ... automated testing would be ideal. No ... we should not stall all further progress on the codebase based on 'we need tests first'. Instead, we should press ahead with the refactoring, and add the desired testing in parallel with those efforts ... The amount of time saved by having those tests available in advance is not justified relative to i) the amount of effort required to add them now relative to the effort to add them after the code is restructured, ii) the amount of rework those tests will require after the refactoring, iii) a minimal gap in coverage between the proposed automated tests and manual end-to-end test runs, and iv) the drag on new feature functionality we are creating in the meantime.
The above is why I'm advocating for the strategy outlined in #2678462: "Queued Code" Cleanup and Test Development Strategy.
Comment #17
mile23Rebased from dev now that #2679673: Create minimal functional tests of command output to test Output refactoring is in.
There are a couple fails in the tests:
They seem to be related to doing the right thing, fundamentally. So there you go.
Comment #20
jthorson commentedTests fixed.
Comment #22
mile23I'm not sure this is the right pattern, because all output will now say
[info]or[notice]or whatever next to it. It might be an aesthetic choice, but yah.After a little brittle time with
RunCommandTest, I changed it to load the blank config and added a @todo about #2683013: Better functional test frameworkComment #23
mile23Doing some work on this...
Comment #24
mile23Added branch 2642636-remove-static-output which is different from 2642636-introduce-logger.
It just injects whatever output is present into each item.
It changes only the environment build step, because I was interested in reading that one. :-)
It adds tests to check the output either way.
I modified Output::error() to accept an output object, with a @todo about changing that later.
Basically: I think we shouldn't use the logger for console output. We can tee it to a file with our own implementation of OutputInterface at some point, or just let Jenkins pipe STDOUT wherever it wants to go.
Comment #25
jthorson commentedSo this reads as an argument that we shouldn't use logger simply because it's possible to do something else. Can you elaborate with reasons to not use logger, specifically?
The reason I went with logger were:
if (Output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE)check,Comment #29
mile23Other than the two reasons I already gave?
Calling
$this->logger->whatever()means we can't useOutputInterface. If we want styles and interaction we're stuck. And we want those things.Instead, inject
$outputinto all places that need it. Then any$outputobject can tee to the log or just log or whatever.Also,
[info] Hi there.looks awful.Comment #30
jthorson commentedOkay ... for the style guides, we can get the same value using Monolog's OutputFormatter, but I'll cede to your point that the logger would complicate interaction and the use of the various Question console helpers.
For me, the biggest goal was to eliminate the need to wrap each line of output in a verbosity check to support differentiated verbosity level output ... With this approach, we could achieve the same by extending SymfonyStyle to add an optional 'verbosityLevel' argument and associated verbosity level check inside each of the appropriate output methods; which should eliminate a lot of verbose (pun intended) code ... Thoughts?
And the other logger benefits I identified above could be realized by injecting a logger service either inside or parallel to the SymfonyStyle $io component at some point in the future.
Comment #31
MixologicThis: http://symfony.com/doc/current/cookbook/logging/monolog_console.html sounds like what jthorson is describing, with alternate pointers to the PSR3 logging method (http://symfony.com/doc/2.8/components/console/logger.html).
So, what this comes back to is doing one thing at a time, and not trying to do multiple things at once. The immediate goal is to get rid of the static output class and replace it with something sane, and built in.
We aren't exactly dying for verbosity control, but it woudn't hurt to have that feature either. New features, however, should have an agreed upon strategy before implementing - even in this case we've got a couple of choices, (monolog vs psr3) and have a lot of decisions to make regarding what levels each output needs to be set at. None of that discussion has happened, and none of it should hold up the goal of this issue when it does.
My thoughts is that we move forward with Mile23's switchout, open up a followup issue for the verbosity feature, and lean towards the monolog implementation vs the psr3 implementation given the formatting flexibility it gives us.
Comment #32
jthorson commentedWith all due respect, those conversations HAVE happened ... they just happened before you assumed the gatekeeper role. Just because you weren't at the table at the time, please don't presume that there isn't a sound strategy behind my proposed changes.
Doing things one thing at a time is precisely why I implemented the PSR3 logger instead of going straight to Monolog ... this approach allows us to replace the static Output object with a lightweight alternative *for now*, in such a way that the move to Monolog *in the future* becomes a 'drop-in' replacement, as opposed to a new round of code refactoring. (Thus the value of using a 'standard' log interface ...)
EDIT: Re-reading this comment, it felt like it could be construed as reversing my stance in #30 ... For the sake of clarity, those comments hold and I'm on board with the approach as described.
Comment #33
MixologicComment #34
mile23Well, no, we can't. Or maybe we could, but then we'd be unfuzzling a thing we fuzzled when we could have not fuzzled it in the first place.
We'll also be able to add our own style guide, which will be an opportunity to add a convenient verbosity check.
The step here is to inject output. I'll assign it to myself and continue work on 2642636-remove-static-output
Comment #38
mile23The
Outputstatic class is still present so we can useOutput::error().Output::error()now takes an optional parameter ofOutputInterface, so an output object can be injected.All other usages of
Outputare deprecated for an injected output object.Comment #40
MixologicComment #43
mile23Moving away from the InjectableTrait idea, because injecting the services at the proper level is much better.
Comment #45
mile23Added a new branch called
2642636-inject-io.In this version we're making a
console.ioservice and injecting it everywhere. It replaces most usages of Output::writeln().console.ioends up being aDrupalCIStyleobject, which sublcassesSymfonyStylein order to add adrupalCIError()method. This way we can emulate the style ofOutput::error().Comment #46
MixologicThis fits into the great refactoring for sure.
Comment #47
MixologicOkay, I did sortof a boo boo. I merged this into dev, instead of the other way around. So after I fixed all of the merge conflicts, and adjusted everywhere else I needed to, and made things work with the FileHandlerTrait that was a plugin before, and moved some things around to support ContainerCommands as Build Objects, This is now passing tests, and shoehorned in.
I also went around cleaning up the 77 OPUT's I put everywhere. Not sure why I did that. There's still a few in DockerPullCommand that Im not quite sure I want to figure out or just eliminate entirely (passing progressbars to the init command)
Comment #48
Mixologic