{"action":"created","issue":{"url":"https://api.github.com/repos/jhedstrom/drupalextension/issues/328","repository_url":"https://api.github.com/repos/jhedstrom/drupalextension","labels_url":"https://api.github.com/repos/jhedstrom/drupalextension/issues/328/labels{/name}","comments_url":"https://api.github.com/repos/jhedstrom/drupalextension/issues/328/comments","events_url":"https://api.github.com/repos/jhedstrom/drupalextension/issues/328/events","html_url":"https://github.com/jhedstrom/drupalextension/issues/328","id":192800098,"number":328,"title":"BUG: rare interference with pathauto  ","user":{"login":"ybabel","id":1323282,"avatar_url":"https://avatars.githubusercontent.com/u/1323282?v=3","gravatar_id":"","url":"https://api.github.com/users/ybabel","html_url":"https://github.com/ybabel","followers_url":"https://api.github.com/users/ybabel/followers","following_url":"https://api.github.com/users/ybabel/following{/other_user}","gists_url":"https://api.github.com/users/ybabel/gists{/gist_id}","starred_url":"https://api.github.com/users/ybabel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ybabel/subscriptions","organizations_url":"https://api.github.com/users/ybabel/orgs","repos_url":"https://api.github.com/users/ybabel/repos","events_url":"https://api.github.com/users/ybabel/events{/privacy}","received_events_url":"https://api.github.com/users/ybabel/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2016-12-01T09:57:56Z","updated_at":"2016-12-01T10:56:05Z","closed_at":null,"body":"Nasty bug I came across.\r\n\r\nWhen I activate \"blog\" module and \"pathauto\" then the \"Pattern for blog page paths\" : \"blogs/[user:name]\" trigger a hook that calls \"user_access\" and build it's static permission cache **before** it's roles are created by behat. So then, none of it's roles (other than authenticated) are affected.\r\n\r\nCode to test, on a fresh install, with no content, no user, just blog and pathauto activated\r\nI created 1 roles : expert that can use advanced search\r\n```\r\n@api @watchdog\r\nFeature: Behat roles bug \r\n\r\n  Scenario: \"expert\" role can use advanced search, \"business\" does not\r\n\r\n    Given users:\r\n    | name    | mail                            | roles    |\r\n    | expert1 | emindhub.test+expert1@gmail.com | expert   |\r\n    #When I flush static permissions\r\n    Then the user expert1 has \"use advanced search\" permission\r\n      And the user expert1 don't have \"create article content\" permission\r\n```\r\n\r\nNow the FeatureContext that comes with it to test  (maybe there are some uses unneeded) : \r\n```\r\n<?php\r\n\r\nuse Drupal\\DrupalExtension\\Context\\RawDrupalContext,\r\n    Drupal\\DrupalExtension\\Context\\DrupalContext;\r\nuse Behat\\Behat\\Context\\SnippetAcceptingContext,\r\n    Behat\\Behat\\Context\\ClosuredContextInterface,\r\n    Behat\\Behat\\Context\\TranslatedContextInterface,\r\n    Behat\\Behat\\Context\\BehatContext,\r\n    Behat\\Behat\\Exception\\PendingException;\r\nuse Behat\\MinkExtension\\Context\\MinkContext;\r\nuse Behat\\Behat\\Hook\\Scope\\BeforeScenarioScope,\r\n    Behat\\Behat\\Hook\\Scope\\AfterStepScope;\r\nuse Behat\\Gherkin\\Node\\PyStringNode,\r\n    Behat\\Gherkin\\Node\\TableNode;\r\n\r\n/**\r\n * Defines application features from the specific context.\r\n */\r\nclass FeatureContext extends DrupalContext {\r\n\r\n  /**\r\n   * @Then /^I flush static permissions$/\r\n   */\r\n  public function IFlushStaticPerm() {\r\n    drupal_static_reset('user_access'); // use it to bypass the bug\r\n  }\r\n\r\n  /**\r\n   * @Then the user :name has :perm permission\r\n   */\r\n  public function theUserHasPermission($name, $perm) {\r\n    if (!isset($this->users[$name])) {\r\n      throw new \\Exception(sprintf('No user with %s name is registered with the driver.', $name));\r\n    }\r\n    $user = user_load($this->users[$name]->uid);\r\n    print (\"user uid : '\".$this->users[$name]->uid.\"' user name : '\".$this->users[$name]->name.\"'\");\r\n    if (! user_access($perm, $user))\r\n      throw new \\Exception('User does not have the required permission');\r\n  }\r\n\r\n  /**\r\n   * @Then the user :name don't have :perm permission\r\n   */\r\n  public function theUserDontHavePermission($name, $perm) {\r\n    if (!isset($this->users[$name])) {\r\n      throw new \\Exception(sprintf('No user with %s name is registered with the driver.', $name));\r\n    }\r\n    $user = user_load($this->users[$name]->uid);\r\n    print (\"user uid : '\".$this->users[$name]->uid.\"' user name : '\".$this->users[$name]->name.\"'\");\r\n    if (user_access($perm, $user))\r\n      throw new \\Exception('User should not have the required permission');\r\n  }\r\n\r\n\r\n}\r\n```\r\n\r\nMinimal behat config : \r\n```\r\ndefault:\r\n  suites:\r\n    default:\r\n      contexts:\r\n        - Drupal\\DrupalExtension\\Context\\MinkContext\r\n        - Drupal\\DrupalExtension\\Context\\MessageContext\r\n        - FeatureContext\r\n\r\n  extensions:\r\n    Behat\\MinkExtension:\r\n      goutte: ~\r\n      base_url: http:/local/drupal\r\n    Drupal\\DrupalExtension:\r\n      blackbox: ~\r\n      api_driver: 'drupal'\r\n      drush:\r\n        alias: 'local'\r\n      drupal:\r\n        drupal_root: ~\r\n```\r\n\r\nuser_access code with one line added to ease debug : \r\n```\r\nfunction user_access($string, $account = NULL) {\r\n  global $user;\r\n\r\n  if (!isset($account)) {\r\n    $account = $user;\r\n  }\r\n\r\n  // User #1 has all privileges:\r\n  if ($account->uid == 1) {\r\n    return TRUE;\r\n  }\r\n\r\n  // To reduce the number of SQL queries, we cache the user's permissions\r\n  // in a static variable.\r\n  // Use the advanced drupal_static() pattern, since this is called very often.\r\n  static $drupal_static_fast;\r\n  if (!isset($drupal_static_fast)) {\r\n    $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);\r\n  }\r\n  $perm = &$drupal_static_fast['perm'];\r\n  if (!isset($perm[$account->uid])) {\r\nprint (\"build static permissions '\".$string.\"' for user: \".$account->uid.\"\\n\"); // CAT KILLER\r\n\r\n    $role_permissions = user_role_permissions($account->roles);\r\n\r\n    $perms = array();\r\n    foreach ($role_permissions as $one_role) {\r\n      $perms += $one_role;\r\n    }\r\n    $perm[$account->uid] = $perms;\r\n  }\r\n\r\n  return isset($perm[$account->uid][$string]);\r\n}\r\n\r\n```\r\n\r\nCode in behat to change (maybe ?) : vendor/drupal/drupal-extension/src/Drupal/DrupalExtension/Context/DrupalContext.php\r\nI commented where the problem occurs\r\n```\r\n  public function createUsers(TableNode $usersTable) {\r\n    foreach ($usersTable->getHash() as $userHash) {\r\n\r\n      // Split out roles to process after user is created.\r\n      $roles = array();\r\n      if (isset($userHash['roles'])) {\r\n        $roles = explode(',', $userHash['roles']);\r\n        $roles = array_filter(array_map('trim', $roles));\r\n        unset($userHash['roles']);\r\n      }\r\n\r\n      $user = (object) $userHash;\r\n      // Set a password.\r\n      if (!isset($user->pass)) {\r\n        $user->pass = $this->getRandom()->name();\r\n      }\r\n      $this->userCreate($user);\r\n\r\n// ============= HERE =================\r\n// pathauto hook user creatation, then if blog is activated\r\n// it uses \"node_access\" that calls \"user_access\"\r\n// that build static permission cache TO SOON\r\n\r\n      // Assign roles.\r\n      foreach ($roles as $role) {\r\n        $this->getDriver()->userAddRole($user, $role);\r\n      }\r\n    }\r\n  }\r\n```\r\n\r\nI don't know what shoud be the best solution ... \r\nFlush static perm after adding roles ?"},"comment":{"url":"https://api.github.com/repos/jhedstrom/drupalextension/issues/comments/264141706","html_url":"https://github.com/jhedstrom/drupalextension/issues/328#issuecomment-264141706","issue_url":"https://api.github.com/repos/jhedstrom/drupalextension/issues/328","id":264141706,"user":{"login":"pfrenssen","id":442924,"avatar_url":"https://avatars.githubusercontent.com/u/442924?v=3","gravatar_id":"","url":"https://api.github.com/users/pfrenssen","html_url":"https://github.com/pfrenssen","followers_url":"https://api.github.com/users/pfrenssen/followers","following_url":"https://api.github.com/users/pfrenssen/following{/other_user}","gists_url":"https://api.github.com/users/pfrenssen/gists{/gist_id}","starred_url":"https://api.github.com/users/pfrenssen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pfrenssen/subscriptions","organizations_url":"https://api.github.com/users/pfrenssen/orgs","repos_url":"https://api.github.com/users/pfrenssen/repos","events_url":"https://api.github.com/users/pfrenssen/events{/privacy}","received_events_url":"https://api.github.com/users/pfrenssen/received_events","type":"User","site_admin":false},"created_at":"2016-12-01T10:56:05Z","updated_at":"2016-12-01T10:56:05Z","body":"I think the bug is in your step definition. You shouldn't rely on the statically cached data in there.\r\n\r\nTry something like this (untested):\r\n\r\n```\r\n  public function assertUserHasPermission($name, $perm) {\r\n    if (!isset($this->users[$name])) {\r\n      throw new \\Exception(sprintf('No user with %s name is registered with the driver.', $name));\r\n    }\r\n    // Use `$reset = TRUE` here to always load a fresh user object from the DB.\r\n    $user = user_load($this->users[$name]->uid, TRUE);\r\n    // Clear the static cache of `user_access()` before testing it.\r\n    drupal_static_reset('user_access');\r\n    if (! user_access($perm, $user))\r\n      throw new \\Exception('User does not have the required permission');\r\n  }\r\n```"}}
{"actor":{"display_login":"pfrenssen"}}