/srv/irclogs.ubuntu.com/2020/03/24/#smooth-operator.txt

Chipacagood morning!09:26
niemeyerMoin moin!09:34
Chipacajam: niemeyer: have you guys talked about the testing pr any more than what's on github?09:39
niemeyerWe did.. but I think we still misunderstood each other and need to sync again09:42
niemeyerThe enable events method with a charm instance was unexpected to me at least09:43
Chipacaniemeyer: I think reading the __init__ method, the way charm is passed in changes09:44
Chipacaniemeyer: ie in initialize(charm) instead of Harness(charm)09:44
Chipacabah, MyCharm*09:45
Chipacai think that's making things too granular ( → harder to use)09:46
Chipacaand would prefer just __init__() doing the initalization work (could just call _initialize)09:46
niemeyerI still don't get it.. wasn't the create_harness method receiving a charm type? Why did it change?09:47
ChipacaI think it was but I might misremember09:47
Chipacahttps://github.com/canonical/operator/pull/146/commits/c2639df120efe2c56235511c814e71644dd640d0 is where that changed09:52
Chipacaand I think on its own it makes sense09:52
Chipacathat is: don't pass in the charm class, then do all the setup you need, and then initialize09:53
Chipacathus initialize kicks off events09:53
ChipacaI don't think it makes sense in conjunction with explicit enable/disable methods09:53
Chipacaespecially with the default of enabled09:53
Chipacaniemeyer: this also explains why enable takes the charm :-)09:53
Chipacain fact I think I like the approach of build without the charm, set up, then initialize the charm to start handling events; it feels very natural09:54
Chipacaat this point enable/disable_events are handles for doing fancier stuff (but I don't see the need for passing in the charm to enable, beyond "disable sets it to None was the easiest way of disabling events"09:55
Chipaca)09:55
niemeyerChipaca: I don't see how it makes sense..09:57
niemeyerChipaca: The charm isn't created by the developer in practice anyway09:57
niemeyerSorry, created is not a good term here09:57
niemeyerI mean it's not instantiated09:57
Chipacaniemeyer: i assume the no-make-sense bit is enable_events taking a charm instance?09:58
niemeyerWas talking about the argument itself09:58
niemeyerBut yes, that's where the conversation started09:59
niemeyerAlso, disabling resetting it09:59
Chipacaniemeyer: sorry, which argument?09:59
* Chipaca now lost09:59
niemeyerChipaca: The conversation we're having just now?09:59
Chipacaniemeyer: ah :)09:59
Chipacai thought you meant argument to the method09:59
niemeyerAh, no, sorry09:59
Chipacaniemeyer: yes, agreed, having disable/enable fiddle with the charm on the handler is weird / wrong09:59
Chipacaniemeyer: but the constructor without the charm class, and then explicit initialize, feels alright to me10:01
Chipacaniemeyer: it means in most cases you won't need to poke at enable/disable at all10:01
Chipacaif we agree on that, then we can look at how to make enable/disable not fiddle with the charm instance10:02
niemeyerI had to jump into a call at 10, but we can keep going in a bit10:05
Chipacaif we don't, then the other coherent thing is to not have initialize, and just enable/disable, that makes the need to pass the charm instance in go away10:06
Chipacathe code to not pass in the charm instance to enable/disbale is probably the same in both cases, and it's not pretty but not terrible either (unless i miss something)10:07
Chipacabut it's all hidden from the dev, so that's alright10:07
Chipacathe passing it in is a wart exposed to the dev, or at least it feels like it --- if there was a non-warty reason i don't see it10:07
Chipacano probs, i have things i need to read :)10:08
* Chipaca goes read10:08
niemeyer> 10:01:28 niemeyer: but the constructor without the charm class, and then explicit initialize, feels alright to me10:36
niemeyerIf that's true I must be missing something about how we'll use it10:36
niemeyerWe went from "this really needs to return the two arguments because that's what we're testing" to "the charm can be created separately and needs to be fed manually by calling some method"10:37
Chipacaniemeyer: it's initialize(MyCharm), not initialize(charm), right?10:38
niemeyerWhat's "initialize"?10:38
Chipacaniemeyer: instantiate the charm and plug it in to the framework?10:39
niemeyerSorry, I'm completely lost10:39
Chipacaniemeyer: https://github.com/canonical/operator/pull/146/commits/c2639df120efe2c56235511c814e71644dd640d0#diff-6964ca15c08db5ba857f6517369815d9R7210:39
niemeyerYes, I don't get any of that10:40
niemeyerIn my mind it was "harness = Harness(MyCharm)"10:40
Chipacaniemeyer: also with some yaml, right?10:41
niemeyerOptionally I think, but yes10:42
Chipacaniemeyer: and that does a couple of things: creates a framework that has a model with a testing backend, and instantiates the charm class hooked into that framework10:45
niemeyerYeah, it does all the boring boilerplate10:45
Chipacaniemeyer: initialize() splits out the second of those two things into an explicit method10:45
niemeyerBecause....?10:45
Chipacaniemeyer: because then you can tweak the model by adding relationships and whatnot, without having the charm hooked up to it yet10:46
Chipacaie without handling events10:46
niemeyerChipaca: Which events?  There can't possibly be any events to consume at this stage, right?10:47
Chipacaniemeyer: if you do: harness.add_relation(...), and the charm was already plugged in, it'll get the relation_created (say)10:48
Chipacaniemeyer: or add_relation_unit() would trigger relation_joined10:48
Chipacaetc10:48
niemeyerChipaca: That's intended.. to disable that behavior you'd call disable_events()10:48
niemeyerWhich perhaps should really be called disable_hooks, actually, since we don't want to disable internal events I think10:49
niemeyerbut that's an aside10:49
Chipacaniemeyer: right, having initialize() means that the thing starts with events disabled, and then you hook things up and they're enabled, in a natural way10:50
Chipacaniemeyer: at that point we could probably not have enable/disable at all, unless we found some advanced scenarios where they made sense10:52
niemeyerChipaca: It sounds to me like you're trying to retrofit the design into what we have in the PR10:52
niemeyerChipaca: The PR includes initialize, disable_events, and enable_events10:52
Chipacaheh10:52
Chipacamaybe10:53
niemeyerChipaca: And __init__, which is a prefix of "initialize" :)10:53
niemeyerChipaca: So the rationale you just provided is at least not the reason why it ended up like this10:53
Chipacato be clear, I _don't_ like passing the charm into enable10:53
niemeyerChipaca: And when you call update_config, will we run hooks or not?10:54
Chipacaniemeyer: when?10:54
Chipaca:)10:54
Chipacaseriously: in which scenario (with initialize? without?), and at what point (after enable/disable/initialize/frob/...?)10:55
niemeyerYou pick it.. do you want to fire hooks every time after your preferred point of initialization?10:56
niemeyerCan you foresee reasons not to?10:56
niemeyerHow do you handle it?10:56
Chipacahah, 1 sec10:56
Chipacaniemeyer: jam already did https://github.com/jameinel/operator/pull/3/files fwiw10:56
niemeyerIt would be nice to have jam with us at some point.. is he working today?10:56
Chipacahe is, or at least, he just merged master10:57
niemeyerWhy are we both having this conversation without us?  Is this channel a group chat or not?10:57
niemeyerI don't care if we use IRC, or Telegram, or telnet.. but we need to have people communicating if we expect this thing to work at all10:58
ChipacaI shall enquire10:58
jamI am around, I just don't sit with IRC in my view10:59
niemeyerjam, Chipaca: I don't care about which chat you guys use, but you need notifications active on the channel where you team works10:59
ChipacaI should've pinged jam earlier in this, is all11:00
jamI think I was probably making coffee when you pinged earlier, my apologies.11:00
niemeyerChipaca: No, not really.. this is the team channel.. it won't work if you need to ping people to pay attention whenever there's a conversation11:01
jamniemeyer: Chipaca: so as I mentioned in my PR response, decoupling the charm being instantiated from the Harness felt like a nicer separation of concerns. Especially for code that wanted to test changes to the model without events, it felt much more natural to not have the charm created yet11:21
jam(especially, for test_model.py, but I realize that is a bit of a special case of testing the framework itself)11:22
jam*some* sort of helper function is currently necessary because of the need to have unique Class definitions, which I will be looking at next.11:23
niemeyerIsn't the charm the entire thing the harness is testing, with extreme coupling so that you can manipulate its fake backend model to arbitrary degrees?11:23
niemeyerIsn't every emit_foo() method going to be injecting events into that charm?11:23
niemeyerEvery other updating method effectively going to be invoking things into it?11:23
jamevents are definitely coupled to the charm instance, as that is the only way to generate hook events.11:25
niemeyerWhat is the harness doing that it *not* coupled to the charm?11:25
jamThough the fact that we've stated "we may not want to have events emitted yet" felt like a case of setting up the Model/Framework without a Charm, and then instantiating the charm once the setup was done felt quite natural11:25
jamAll of the state-of-the-model is underneath charm. Such that the charm can go look at it, but doesn't require a charm to exist for the model to be updated.11:26
Chipacato me, the question goes back to how we expect this to be used more11:29
niemeyerThat's fine.. it's what Chipaca was suggesting above. We can postpone the creation of the charm and have an explicit method for that. It doesn't change everything else we discussed, though:11:29
niemeyer- We shouldn't make people play puzzle on every test to assemble the harness11:30
niemeyer- There's no reason for disable_event/enable_event to take a charm and kill the internal charm instance11:30
niemeyer- We may need to stop emitting hooks and make that manual so that people can try to trigger particular cases11:30
niemeyer- The default case is supposed to be straightforward11:31
niemeyerHaving something like a harness.start() method would address Chipaca's suggestion.. but we still need to address everything else11:32
Chipacaniemeyer: what's the puzzle you refer to in the first point?11:32
niemeyerChipaca: "... to assemble the harness"?11:33
jamso the current proposed syntax if we rename 'initialize' to 'start' and change enable/disable to use a boolean would be:11:36
jamhttps://paste.ubuntu.com/p/s4QcKGX3Xr/11:36
jamniemeyer: Chipaca ^^11:36
Chipacasorry, having to check on the boys' home work11:36
Chipacaback now11:36
jamwe have to have the charm meta to initialize a Model11:37
niemeyerLet me quickly draft something11:37
* Chipaca waitws11:38
* Chipaca waits, also11:38
jamif you have a different syntax that feels more natural, having examples are good. I've had these in tests, etc, but I'm happy to pull them out explicitly and discuss them.11:38
niemeyerhttps://paste.ubuntu.com/p/XfjJ95NfB4/11:40
Chipacaniemeyer: could make the yaml an optional arg on the constructor11:44
Chipacainstead of having it as a method (because then you have to think about what happens if you call it after you've started or whatever)11:44
niemeyerChipaca: You could, but this is usually long string11:44
niemeyerChipaca: harness = Harness(Charm) feels solid11:45
niemeyerChipaca: You don't have to think if you don't allow it to take place11:45
jamniemeyer: so one thing that I was using this for testing is testing components that aren't themselves a charm. And we don't have a metadata.yaml for CharmBase11:45
niemeyerjam: I'm a bit lost.. CharmBase is the base class for charms.. charms have metadata.. ?11:48
jamniemeyer: if I'm testing MysqlClient, it doesn't have its own charm. it will be used by several charms, and does consume events.11:48
jamwe need 'name' from metadata.yaml11:49
Chipacai need to step out but will catch up when i return11:50
niemeyerjam: How does that change things in the context above?11:50
jamniemeyer: so if you just pass CharmBase, there isn't a metadata.yaml, even though it does have defined events11:51
niemeyerjam: We can just have a stock metadata.yaml, but that won't have any endpoints that will be useful for MysqlClient..11:51
niemeyerjam: The only reasonable answer I can tihnk of is you actually define a trivial test charm and metadata to test it.. but I'm not sure if you're thinking of specific issues?11:52
jamso I've been going with explicit metadata for each instantiation, which does have the nice property that you declare your needs right before you start testing them.11:54
jambut I can understand when testing a real charm, that ends up copying the metadata you've already had to declare11:54
jamniemeyer: does an optional __init__ parameter seem ok? I'm not sure about changing metadata late with set_meta()11:55
niemeyerjam: Both of these cases seem covered in the example paste I provided above.. so I'm still not entirely sure if you're trying to point something that I'm completely oblivious to11:55
niemeyerjam: What do you mean "late"?  Isn't the entire point of the start() method to enable a setup phase?11:55
jamniemeyer: so start() for *me* was to delay when the Charm was instantiated, but to still have a Model that you can populate. If you can't do anything before start() then there is no reason to decouple it from __init__11:57
niemeyerjam: Exactly.. that's what I'm saying as well11:58
jamModel can't be instantiated before Meta is finalized, as it needs it for things like "what relations will I know about". So you can't have 'set_meta' to set it without replacing the Model.11:58
jamniemeyer: so with the code that I proposed, you can perfectly populate Model with relation data, config data, etc, all without a Charm.11:59
niemeyerI see11:59
jamand then when you *do* create a Charm, it has access to a populated Model.11:59
niemeyerjam: Do you populate the model, or do you populate the backend?12:00
jamniemeyer: the backend.12:00
niemeyerjam: The backend needs meta?12:00
jamniemeyer: _ModelBackend doesn't need meta, but you pass in the backend to Model in its __init__ and Model does need both Backend and Meta.12:01
niemeyerjam: If you populate the backend, and it doesn't need meta, can we create the model at start time?12:01
jamniemeyer: and Framework which is a base for everything also needs Model, but that, again, could be constructed late.12:02
jamniemeyer: so yes, we could fix Meta, create Model and Framework and Charm during start12:02
jamand then have set_meta() refuse if Model has been created.12:03
niemeyerstart() is a bad name as we have a hook with that name.. begin(), bake(), setup()12:04
niemeyersetup is also a bad name as that's what we've been doing before we call the method12:05
niemeyer.begin() is likely the better choice of those, as it has the feeling of "alright, we're ready and will start doing things now"12:06
jaminitialize(Charm), instantiate(Charm), create(Charm), begin(Charm)12:07
jamcharm = harness.begin(Charm)12:07
jamdoesn't quite read naturally to me, but I could live with it. I do like it meaning the 'start of testing that I'm going to be doing'12:08
niemeyerharness = Harness(Charm)12:08
niemeyerharness.begin()12:08
niemeyer"harness = Harness(Charm)" is what we had agreed on the sprint, and still feels right to me12:08
jamok12:09
niemeyerWe can cover the reasons again once more, but let's do that in the call12:09
niemeyerI'm going to step out for lunch now12:09
jamnp12:10
* Chipaca running late13:31
jamChipaca: niemeyer: patch updated. I went with meta as an __init__ parameter instead of set_meta because we need it for a default unit_name. There could be other ways around that (having the user supply an optional unit_name might be better).15:22
jamI did implement the 'look for metadata.yaml if not supplied', and added a test for it.15:22
jamIt is a test that is 'impure' vs the rest of the tests. (Everything else is just python objects, but that involves manipulating the filesystem, and importlib stuff.)15:23
jamAnyway, EOD for me. Have a good afternoon/evening.15:23
niemeyerThanks, have a good one15:23
* Chipaca soft-EODs (need to pop back later to wrap up some things, but dinner now)18:33

Generated by irclog2html.py 2.7 by Marius Gedminas - find it at mg.pov.lt!