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

Added telemetry for usage of activateEnvInCurrentTerminal setting #8654

Merged
merged 15 commits into from
Nov 25, 2019

Conversation

karrtikr
Copy link

@karrtikr karrtikr commented Nov 19, 2019

For #8004

The heart of the change is this file src/client/providers/terminalProvider.ts. I am just adding telemetry and passing in the active resource.

Other changes are related to #8654 (comment) which just involves refactoring the method getActiveResource().

  • Pull request represents a single change (i.e. not fixing disparate/unrelated things in a single PR)
  • Title summarizes what is changing
  • Has a news entry file (remember to thank yourself!)
  • Appropriate comments and documentation strings in the code
  • Has sufficient logging.
  • Has telemetry for enhancements.
  • Unit tests & system/integration tests are added/updated
  • [ ] Test plan is updated as appropriate
  • [ ] package-lock.json has been regenerated by running npm install (if dependencies have changed)
  • [ ] The wiki is updated with any design decisions/details.

@codecov-io
Copy link

codecov-io commented Nov 19, 2019

Codecov Report

Merging #8654 into master will increase coverage by 0.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #8654      +/-   ##
==========================================
+ Coverage   59.18%   59.19%   +0.01%     
==========================================
  Files         521      522       +1     
  Lines       23977    23987      +10     
  Branches     3873     3870       -3     
==========================================
+ Hits        14190    14200      +10     
- Misses       8870     8871       +1     
+ Partials      917      916       -1
Impacted Files Coverage Δ
src/client/telemetry/index.ts 86.86% <ø> (ø) ⬆️
src/client/common/application/activeResource.ts 100% <100%> (ø)
src/client/activation/serviceRegistry.ts 100% <100%> (ø) ⬆️
src/client/terminals/activation.ts 82.75% <100%> (+3.97%) ⬆️
src/client/providers/replProvider.ts 100% <100%> (ø) ⬆️
src/client/common/application/types.ts 100% <100%> (ø) ⬆️
src/client/providers/terminalProvider.ts 100% <100%> (ø) ⬆️
src/client/activation/activationManager.ts 72.72% <100%> (+4.15%) ⬆️
src/client/telemetry/constants.ts 100% <100%> (ø) ⬆️
src/client/testing/codeLenses/testFiles.ts 17.43% <0%> (-0.67%) ⬇️
... and 3 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 97d017c...201342e. Read the comment docs.

@@ -158,12 +160,15 @@ suite('Terminal Provider', () => {
let configService: TypeMoq.IMock<IConfigurationService>;
let terminalActivator: TypeMoq.IMock<ITerminalActivator>;
let terminal: TypeMoq.IMock<Terminal>;
// tslint:disable-next-line:no-any
let getActiveResource: sinon.SinonStub<any>;
Copy link
Member

Choose a reason for hiding this comment

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

For my info, why sinon? feels like typemoq could achieve the same.

Copy link
Author

Choose a reason for hiding this comment

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

Because I am trying to mock the methods of the class I am testing itself.
Typemoq can be used to mock methods of dependencies of a class just fine, but not the methods of the class I am testing. (I don't have mocked objects of the sort TypeMoq.IMock<InterfaceName> for the class I am testing)

@ericsnowcurrently @karthiknadig

Copy link
Member

Choose a reason for hiding this comment

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

The idea of mocking out a method of the class against which I'm testing is a little mind-melting. There must be a simpler way.

Copy link
Member

@ericsnowcurrently ericsnowcurrently left a comment

Choose a reason for hiding this comment

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

mostly LGTM

My suggestions are all about formatting and wording in comments. :)

src/client/telemetry/index.ts Outdated Show resolved Hide resolved
src/client/telemetry/index.ts Outdated Show resolved Hide resolved
src/client/telemetry/index.ts Outdated Show resolved Hide resolved
news/1 Enhancements/8004.md Outdated Show resolved Hide resolved
src/test/providers/terminal.unit.test.ts Show resolved Hide resolved
src/test/providers/terminal.unit.test.ts Outdated Show resolved Hide resolved
Copy link

@DonJayamanne DonJayamanne left a comment

Choose a reason for hiding this comment

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

Telemetry is being captured in the wrong place, only when extension is opened! (Rejecting PR because of this).
Terminal name can contain PII, also we don't need this (not to my knowledge). - optional if others think it's not PII (there's no guarantee it's not)

src/client/providers/terminalProvider.ts Outdated Show resolved Hide resolved
src/client/providers/terminalProvider.ts Outdated Show resolved Hide resolved
@luabud
Copy link
Member

luabud commented Nov 19, 2019

my bad folks, I should have clarified what kind of telemetry I was expecting. It's just to track usage (i.e. how many people have the setting set to true), just to help with decisions in the future in terms of maintenance. Let's drop the terminal name since we can't guarantee it won't ever collect PII.

@DonJayamanne
Copy link

(i.e. how many people have the setting set to true)

Then i'd track this feature usage as part of the extension load, instead of tracking activated terminals when they are opened, etc.

@karrtikr
Copy link
Author

I changed telemetry after consulting with @luabud . We want to track the usage of the setting (if it's present or not) and also the times when the setting is actually used to activate the terminal.

@karrtikr karrtikr requested review from DonJayamanne, karthiknadig and ericsnowcurrently and removed request for kimadeline November 20, 2019 00:27
@karrtikr karrtikr closed this Nov 20, 2019
@karrtikr karrtikr reopened this Nov 20, 2019
@karrtikr karrtikr closed this Nov 20, 2019
@karrtikr karrtikr reopened this Nov 20, 2019
Copy link

@DonJayamanne DonJayamanne left a comment

Choose a reason for hiding this comment

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

I'd still like to see the PR changed to tracking the setting as opposed to its usage.
It could be used elsewhere in the future.
This way its obvious, right now we're tracking a feature and not a setting. Hence looking at the code the telemetry isn't obvious.

Copy link
Member

@ericsnowcurrently ericsnowcurrently left a comment

Choose a reason for hiding this comment

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

The actual fix LGTM.

However, I have a bunch of comments related to the effort to factor out getting the "active" resource. I strongly recommend moving that to a separate PR.

@@ -169,3 +169,8 @@ export const IExtensionSingleActivationService = Symbol('IExtensionSingleActivat
export interface IExtensionSingleActivationService {
activate(): Promise<void>;
}

export const IActiveResourceService = Symbol('IActiveResourceService');
export interface IActiveResourceService {
Copy link
Member

Choose a reason for hiding this comment

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

Please add a doc comment explaining the purpose of this type.

Choose a reason for hiding this comment

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

Yes. Though I don't think we even need an interface for this.
We could just create the class and inject just the class.

Copy link
Author

@karrtikr karrtikr Nov 20, 2019

Choose a reason for hiding this comment

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

@DonJayamanne For the cases where serviceContainer is used,

this.activeResourceService = this.serviceContainer.get<IActiveResourceService>(IActiveResourceService);

we can't inject the class, can we? How do we initialize this.activeResourceService in these cases?

src/client/providers/terminalProvider.ts Outdated Show resolved Hide resolved
src/client/activation/activeResource.ts Outdated Show resolved Hide resolved
src/test/activation/activeResource.unit.test.ts Outdated Show resolved Hide resolved
src/test/activation/activeResource.unit.test.ts Outdated Show resolved Hide resolved
src/test/activation/activeResource.unit.test.ts Outdated Show resolved Hide resolved
src/test/activation/activeResource.unit.test.ts Outdated Show resolved Hide resolved
src/client/activation/activeResource.ts Outdated Show resolved Hide resolved
});

test('Return document uri if a saved document is currently opened', async () => {
const activeTextEditor = {
Copy link
Member

Choose a reason for hiding this comment

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

For a unit test I would expect use of mocks for both activeTextEditor and activeTextEditor.document. Then you would verify that isUntitled and uri were both used and that nothing else was. So I suppose the test would look more like this:

    test('Return document uri if a saved document is currently opened', async () => {
        const expected = Uri.parse('a');
        const activeTextEditor: TextEditor = mock(TextEditor);
        const document: TextDocument = mock(TextDocument);
        when(document.isUntitled).thenReturn(false);
        when(document.uri).thenReturn(expected);
        when(activeTextEditor.document).thenReturn(document);
        when(documentManager.activeTextEditor).thenReturn(activeTextEditor);
        //when(workspaceService.workspaceFolders).thenReturn([]);

        const activeResource = activeResourceService.getActiveResource();

        assert.deepEqual(activeResource, expected);
        verify(document.isUntitled).once();
        verify(document.uri).once();
        verify(activeTextEditor.document).once();
        verify(documentManager.activeTextEditor).atLeast(1);
        verify(workspaceService.workspaceFolders).never();
    });

The trick is ensuring that you verify everything properly. That is a lot easier with TypeMoq:

suite('Active resource service', () => {
    let document: TypeMoq.IMock<vscode.TextDocument>;
    let editor: TypeMoq.IMock<vscode.TextEditor>;
    let documentManager: TypeMoq.IMock<IDocumentManager>;
    let workspaceService: TypeMoq.IMock<IWorkspaceService>;
    let activeResourceService: ActiveResourceService;
    setup(() => {
        document = TypeMoq.Mock.ofType<vscode.TextDocument>(undefined, TypeMoq.MockBehavior.Strict);
        editor = TypeMoq.Mock.ofType<vscode.TextEditor>(undefined, TypeMoq.MockBehavior.Strict);
        documentManager = TypeMoq.Mock.ofType<IDocumentManager>(undefined, TypeMoq.MockBehavior.Strict);
        workspaceService = TypeMoq.Mock.ofType<IWorkspaceService>(undefined, TypeMoq.MockBehavior.Strict);
        activeResourceService = new ActiveResourceService(
            documentManager.object,
            workspaceService.object
        );
    });
    function verifyAll() {
        document.verifyAll();
        editor.verifyAll();
        documentManager.verifyAll();
        workspaceService.verifyAll();
    }

    test('Return document uri if a saved document is currently opened', async () => {
        const expected = Uri.parse('a');
        documentManager.setup(dm => dm.activeTextEditor)
            .returns(() => editor);
        editor.setup(e => e.document)
            .returns(() => document);
        document.setup(d => d.isUntitled)
            .returns(() => false);
        document.setup(d => d.uri)
            .returns(() => expected);

        const activeResource = activeResourceService.getActiveResource();

        assert.deepEqual(activeResource, expected);
        verifyAll();
    });

Choose a reason for hiding this comment

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

I still like ts-mokito :) and the old test was good enough for me.

Copy link
Member

Choose a reason for hiding this comment

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

I'm just worried that we aren't checking for unexpected behavior (spurious calls). Does ts-mokito offer a way to verify that only the calls you expect actually happened?

Copy link
Author

Choose a reason for hiding this comment

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

We can do the same in ts-mokito, but I am thinking that the old test was good enough.
Do we really need to verify every little aspect? Seems a bit too much.

Copy link
Author

Choose a reason for hiding this comment

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

@ericsnowcurrently I have some concerns that verifying every count can lead to high coupling. Until we have a team discussion regarding best testing practices, I would go with the existing approach. Please approve the PR if you find everything else okay.

Copy link
Member

Choose a reason for hiding this comment

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

That's fine. :)

@luabud
Copy link
Member

luabud commented Nov 20, 2019

@DonJayamanne

I'd still like to see the PR changed to tracking the setting as opposed to its usage.
It could be used elsewhere in the future.
This way its obvious, right now we're tracking a feature and not a setting. Hence looking at the code the telemetry isn't obvious.

I was aiming to track usage of the feature for the purpose of future decision making in terms of maintenance and feature work. I understand that if we change the behaviour of the feature and/or setting, we'll probably need to change the telemetry as well, but I don't think we're saving up so much time by tracking something else now. Of course we should always aim for extensible solutions but in this case it's telemetry being captured, not feature or bug fixing work. Does that make sense?

@DonJayamanne
Copy link

I'd still like to see the PR changed to tracking the setting as opposed to its usage.

@luabud not sure what u mean.
Here's your requirement (i.e. how many people have the setting set to true),
So my comments were based on the above requirement.

@DonJayamanne
Copy link

DonJayamanne commented Nov 20, 2019

The original requirement was (i.e. how many people have the setting set to true)
But now we're doing something else.
We're not tracking how many have the setting on, were tracking how many are using it... Different meaning.

Ie there's a disconnect between the requirement and the solution implementation..

@karrtikr
Copy link
Author

@DonJayamanne We're tracking both, Don. Please have a look at my earlier comment. The telemetry event is sent only if the setting is on, and even if the user is not actually using the setting.

Kartik Raj and others added 5 commits November 20, 2019 13:36
Co-Authored-By: Eric Snow <ericsnowcurrently@gmail.com>
Co-Authored-By: Eric Snow <ericsnowcurrently@gmail.com>
@karrtikr karrtikr dismissed ericsnowcurrently’s stale review November 22, 2019 19:18

Just waiting for your review

Copy link
Member

@ericsnowcurrently ericsnowcurrently left a comment

Choose a reason for hiding this comment

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

LGTM

Honestly, this would have landed a lot sooner if the ActiveResourceService stuff had been done in a separate PR. :)

@karrtikr karrtikr merged commit 68ef910 into microsoft:master Nov 25, 2019
@karrtikr karrtikr deleted the activateEnvInCurrentTerminal branch November 25, 2019 18:31
@lock lock bot locked as resolved and limited conversation to collaborators Dec 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants