Skip to content

Test HandleVnodeOperation#952

Merged
jeschu1 merged 11 commits intomicrosoft:masterfrom
jeschu1:handevnodeop
Apr 1, 2019
Merged

Test HandleVnodeOperation#952
jeschu1 merged 11 commits intomicrosoft:masterfrom
jeschu1:handevnodeop

Conversation

@jeschu1
Copy link
Member

@jeschu1 jeschu1 commented Mar 21, 2019

This incorporates

  • Updates by @pmj to allow parameter testing
  • Tests for HandleVnodeOperation

Also highlighting two areas we should unit test in the future

  • CurrentProcessWasSpawnedByRegularUser
  • UseMainForkIfNamedStream

@jeschu1 jeschu1 added the WIP label Mar 21, 2019
@jeschu1 jeschu1 requested review from pmj and wilbaker March 21, 2019 18:35
_,
_,
_,
_,
Copy link
Member Author

Choose a reason for hiding this comment

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

@pmj I asked this on IM but if I stick
reinterpret_cast<int*>(KAUTH_RESULT_DEFER),
in this parameter I get a failure. I'm guessing ref compare instead of value compare.
How do you think we should handle this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Are you trying to check the input value or simulate setting the output parameter?

Neither is currently supported, and I'm not sure what syntax would really work for this type of thing. The best I can think of is to put the check or output parameter setting straight in the mock function itself.

Copy link
Member Author

Choose a reason for hiding this comment

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

@pmj that makes sense. I'm not sure we need the to test for that value explicitly since we validated the message was sent. What do you think?
We can certainly test it in the mock if absolutely necessary.

@jeschu1
Copy link
Member Author

jeschu1 commented Mar 21, 2019

/azp run GitHub VFSForGit Mac Functional Tests

@azure-pipelines
Copy link

No pipelines are associated with this pull request.

@jeschu1 jeschu1 force-pushed the handevnodeop branch 2 times, most recently from 055ddf9 to 0b3e215 Compare March 22, 2019 17:35
Copy link
Member

@wilbaker wilbaker left a comment

Choose a reason for hiding this comment

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

Overall this is looking great!

Thanks @pmj and @jeschu1 for all the work to get the unit tests to this point 😃

@jeschu1 I've left some comments/questions, almost all of which are minor.


int proc_rele(proc_t p)
{
return 1;
Copy link
Member

Choose a reason for hiding this comment

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

Why did you decide to return 1 here for proc_rele?

Copy link
Member Author

Choose a reason for hiding this comment

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

Any number will actually due since we don't test the result in code.
The results here will seem a bit odd, but hopefully make a lot more sense when we unit tests CurrentProcessWasSpawnedByRegularUser.

struct PlaceholderValue
{};

extern PlaceholderValue _;
Copy link
Member

Choose a reason for hiding this comment

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

Could you add a comment here describing what PlaceholderValue and _ are for and when to use them?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, that commit was thrown together as quickly as possible so that @jeschu1 had something to work with, I think there are a few things there that could be improved. I'll try and get that done soon.

Copy link
Member Author

Choose a reason for hiding this comment

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

If you get pressed for time @pmj I can do it

Copy link
Member Author

Choose a reason for hiding this comment

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

Comment added :-)

Copy link
Member

Choose a reason for hiding this comment

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

Apologies for bringing this up again, but could you add a few more details (and possibly rename PlaceholderValue)? Someone new to the code might think that PlaceholderValue is related to file placeholders based on its name.

Maybe something like:

namespace KextMock
{
    struct ParameterPlaceholderValue
    {};

    // Matches with any parameter value
    // ParameterPlaceholderValue can be used:
    //   - When calling kext functions, for parameters values that do not matter to the test
    //   - When checking if a function was called (i.e. DidCallFunction).  ParameterPlaceholderValue is 
    //     a match for all parameter values.
    extern ParameterPlaceholderValue _;

Copy link
Member Author

Choose a reason for hiding this comment

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

Updating with suggested comment

}
}

-(void) testWriteFile {
Copy link
Member

Choose a reason for hiding this comment

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

Minor naming suggestion:

If the some of the more generic test names were slightly more detailed it might make it easier to find test(s) of interest when looking for specific coverage:

Examples

  • testWriteFile -> testWriteDataVnodeOpEmptyFile
  • testWriteFileFull -> testWriteDataVnodeOpFullFile

What got me thinking about this was when I read the implementation of testWriteFileFull I was surprised to see that it wasn't checking that the MessageType_KtoU_NotifyFileModified message was sent. After realizing that these first tests were only for vnode operations it made sense, but it got me wondering if the test names should include VnodeOp or FileOp (or perhaps the tests should be in different classes?).

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a good point. I haven't fully decided on seperate files or the same files for both types. My plan is to revisit decision when I go full force on FileOp tests (seperate PR). Hence for now I'd like to punt the naming to a future (but not distance future PR).

_,
_,
_));
}
Copy link
Member

Choose a reason for hiding this comment

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

Could we check nextCallSequenceNumber to ensure that the above callback was the only callback called (and that it was only called once)?

}

- (void) testOpenInVirtualizationRoot {
// A file that is already in the virtual root, should not recieve a creation request
Copy link
Member

Choose a reason for hiding this comment

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

This comment doesn't quite match the code (now that we have the more generic XCTAssertFalse(MockCalls::DidCallFunction(ProviderMessaging_TrySendRequestAndWaitForResponse)) check), maybe update it to something like:

// KAUTH_FILEOP_OPEN  should not trigger any callbacks for files that are already flagged as in the virtualization root.

Copy link
Member

Choose a reason for hiding this comment

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

I see this comment was marked as resolved, but it looks like the comment was not updated.

Copy link
Member Author

Choose a reason for hiding this comment

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

Cause I put the comment on the wrong place. I'm updated with 2 superior comments.

Copy link
Contributor

@pmj pmj left a comment

Choose a reason for hiding this comment

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

Regarding the question about kauthResult and kauthError parameters when mocking ProviderMessaging_TrySendRequestAndWaitForResponse:

I've just checked the "real" implementation, and it seems kauthResult is effectively an output parameter, so the mock version should definitely write to it. kauthError is in/out, only some code paths write to it, and it can be assumed the caller already initialised it.

Copy link
Member

@wilbaker wilbaker left a comment

Choose a reason for hiding this comment

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

Approved with suggestions

struct PlaceholderValue
{};

extern PlaceholderValue _;
Copy link
Member

Choose a reason for hiding this comment

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

Apologies for bringing this up again, but could you add a few more details (and possibly rename PlaceholderValue)? Someone new to the code might think that PlaceholderValue is related to file placeholders based on its name.

Maybe something like:

namespace KextMock
{
    struct ParameterPlaceholderValue
    {};

    // Matches with any parameter value
    // ParameterPlaceholderValue can be used:
    //   - When calling kext functions, for parameters values that do not matter to the test
    //   - When checking if a function was called (i.e. DidCallFunction).  ParameterPlaceholderValue is 
    //     a match for all parameter values.
    extern ParameterPlaceholderValue _;

}

- (void) testOpenInVirtualizationRoot {
// A file that is already in the virtual root, should not recieve a creation request
Copy link
Member

Choose a reason for hiding this comment

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

I see this comment was marked as resolved, but it looks like the comment was not updated.

_,
_,
nullptr));
XCTAssertTrue(
Copy link
Member

Choose a reason for hiding this comment

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

If the callSequenceNumber work is planned for a follow up PR, could you file a work item for it?


// Allow any value to match
// Matches with any parameter value
// ParameterPlaceholderValue can be used:
Copy link
Member

Choose a reason for hiding this comment

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

Unless you're renaming the class to ParameterPlaceholderValue all of the ParameterPlaceholderValue in the comment should be replaced with PlaceholderValue.

{
int callCount = 0;
std::pair<typename RecordedCallMap::const_iterator, typename RecordedCallMap::const_iterator> foundCalls = this->recordedCalls.equal_range(function);
for (typename RecordedCallMap::const_iterator foundCall = foundCalls.first; foundCall != foundCalls.second; ++foundCall)
Copy link
Member

Choose a reason for hiding this comment

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

Rather than writing the loop yourself you can use std::distance to get the count:

return distance(foundCalls.first, foundCalls.second);

int SpecificFunctionCallRecorder<R, ARGS...>::CallCount(FunctionPointerType function)
{
int callCount = 0;
std::pair<typename RecordedCallMap::const_iterator, typename RecordedCallMap::const_iterator> foundCalls = this->recordedCalls.equal_range(function);
Copy link
Contributor

Choose a reason for hiding this comment

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

I know some of my code has declarations like this as well, but I'm thinking it's less readable than auto at this point. We don't have to go for auto, there are a few in-between options which I think would also be preferable over the status quo:

  • I think the latest C++ standard allows partial type declarations, so in this case, I believe std::pair foundCalls = …; should work. This at least makes it obvious we're getting a pair - and pretty much all operations on STL containers return iterators in some form, so not spelling those out in detail seems sensible.
  • Locally Typedef'ing the iterator type to something much shorter.

Copy link
Member

Choose a reason for hiding this comment

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

I think the latest C++ standard allows partial type declarations, so in this case, I believe std::pair foundCalls = …; should work. This at least makes it obvious we're getting a pair - and pretty much all operations on STL containers return iterators in some form, so not spelling those out in detail seems sensible.

Cool I did not know about this feature 👍

I know some of my code has declarations like this as well, but I'm thinking it's less readable than auto at this point.

I agree on this point, and template programming is one spot where things can get messy without auto.

If the above approach does not work out I'm good with using auto here with some descriptive variable names.

@jeschu1 jeschu1 removed the WIP label Apr 1, 2019
@jeschu1 jeschu1 merged commit 26a5503 into microsoft:master Apr 1, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants