<commit_before># encoding: UTF-8
#
# Author:: <NAME> (<<EMAIL>>)
# Copyright:: Copyright (c) 2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'spec_helper'
require 'chef/mixin/shell_out'

describe Chef::Resource::User, :unix_only, :requires_root do

  include Chef::Mixin::ShellOut

  # User provider is platform-dependent, we need platform ohai data:
  OHAI_SYSTEM = Ohai::System.new
  OHAI_SYSTEM.require_plugin("os")
  OHAI_SYSTEM.require_plugin("platform")


  # Utility code for /etc/passwd interaction, avoid any caching of user records:
  PwEntry = Struct.new(:name, :passwd, :uid, :gid, :gecos, :home, :shell)

  class UserNotFound < StandardError; end

  def pw_entry
    passwd_file = File.open("/etc/passwd", "rb") {|f| f.read}
    matcher = /^#{Regexp.escape(username)}.+$/
    if passwd_entry = passwd_file.scan(matcher).first
      PwEntry.new(*passwd_entry.split(':'))
    else
      raise UserNotFound, "no entry matching #{matcher.inspect} found in /etc/passwd"
    end
  end

  def etc_shadow
    File.open("/etc/shadow") {|f| f.read }
  end


  before do
    # Silence shell_out live stream
    Chef::Log.level = :warn

    # Tests only implemented for a subset of platforms currently.
    user_provider = Chef::Platform.find_provider(OHAI_SYSTEM["platform"],
                                                 OHAI_SYSTEM["platform_version"],
                                                 :user)
    unless user_provider == Chef::Provider::User::Useradd
      pending "Only the useradd provider is supported at this time"
    end
  end

  after do
    begin
      pw_entry # will raise if the user doesn't exist
      shell_out!("userdel", "-f", "-r", username, :returns => [0,12])
    rescue UserNotFound
      # nothing to remove
    end
  end

  let(:node) do
    n = Chef::Node.new
    n.consume_external_attrs(OHAI_SYSTEM.data.dup, {})
    n
  end

  let(:events) do
    Chef::EventDispatch::Dispatcher.new
  end

  let(:run_context) do
    Chef::RunContext.new(node, {}, events)
  end

  let(:username) do
    "chef-functional-test"
  end

  let(:uid) { nil }
  let(:home) { nil }
  let(:manage_home) { false }
  let(:password) { <PASSWORD> }
  let(:system) { false }
  let(:comment) { nil }

  let(:user_resource) do
    r = Chef::Resource::User.new("TEST USER RESOURCE", run_context)
    r.username(username)
    r.uid(uid)
    r.home(home)
    r.comment(comment)
    r.manage_home(manage_home)
    r.password(password)
    r.system(system)
    r
  end

  let(:skip) { false }

  describe "action :create" do

    context "when the user does not exist beforehand" do
      before do
        if reason = skip
          pending(reason)
        end
        user_resource.run_action(:create)
        user_resource.should be_updated_by_last_action
      end


      it "ensures the user exists" do
        pw_entry.name.should == username
      end

      #  On Debian, the only constraints are that usernames must neither start
      #  with a dash ('-') nor plus ('+') nor tilde ('~') nor contain a colon
      #  (':'), a comma (','), or a whitespace (space: ' ', end of line: '\n',
      #  tabulation: '\t', etc.). Note that using a slash ('/') may break the
      #  default algorithm for the definition of the user's home directory.

      context "and the username contains a single quote" do
        let(:username) { "t'bilisi" }

        it "ensures the user exists" do
          pw_entry.name.should == username
        end
      end


      context "when uid is set" do
        # Should verify uid not in use...
        let(:uid) { 1999 }

        it "ensures the user has the given uid" do
          pw_entry.uid.should == "1999"
        end
      end

      context "when comment is set" do
        let(:comment) { "hello this is dog" }

        it "ensures the comment is set" do
          pw_entry.gecos.should == "hello this is dog"
        end

        context "in standard gecos format" do
          let(:comment) { "Bobo T. Clown,some building,555-555-5555,@boboclown" }

          it "ensures the comment is set" do
            pw_entry.gecos.should == comment<commit_msg>Skip test for username with quote where unsupported.<commit_after># encoding: UTF-8
#
# Author:: <NAME> (<<EMAIL>>)
# Copyright:: Copyright (c) 2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'spec_helper'
require 'chef/mixin/shell_out'

describe Chef::Resource::User, :unix_only, :requires_root do

  include Chef::Mixin::ShellOut

  # User provider is platform-dependent, we need platform ohai data:
  OHAI_SYSTEM = Ohai::System.new
  OHAI_SYSTEM.require_plugin("os")
  OHAI_SYSTEM.require_plugin("platform")


  # Utility code for /etc/passwd interaction, avoid any caching of user records:
  PwEntry = Struct.new(:name, :passwd, :uid, :gid, :gecos, :home, :shell)

  class UserNotFound < StandardError; end

  def pw_entry
    passwd_file = File.open("/etc/passwd", "rb") {|f| f.read}
    matcher = /^#{Regexp.escape(username)}.+$/
    if passwd_entry = passwd_file.scan(matcher).first
      PwEntry.new(*passwd_entry.split(':'))
    else
      raise UserNotFound, "no entry matching #{matcher.inspect} found in /etc/passwd"
    end
  end

  def etc_shadow
    File.open("/etc/shadow") {|f| f.read }
  end

  def supports_quote_in_username?
    OHAI_SYSTEM["platform_family"] == "debian"
  end

  before do
    # Silence shell_out live stream
    Chef::Log.level = :warn

    # Tests only implemented for a subset of platforms currently.
    user_provider = Chef::Platform.find_provider(OHAI_SYSTEM["platform"],
                                                 OHAI_SYSTEM["platform_version"],
                                                 :user)
    unless user_provider == Chef::Provider::User::Useradd
      pending "Only the useradd provider is supported at this time"
    end
  end

  after do
    begin
      pw_entry # will raise if the user doesn't exist
      shell_out!("userdel", "-f", "-r", username, :returns => [0,12])
    rescue UserNotFound
      # nothing to remove
    end
  end

  let(:node) do
    n = Chef::Node.new
    n.consume_external_attrs(OHAI_SYSTEM.data.dup, {})
    n
  end

  let(:events) do
    Chef::EventDispatch::Dispatcher.new
  end

  let(:run_context) do
    Chef::RunContext.new(node, {}, events)
  end

  let(:username) do
    "chef-functional-test"
  end

  let(:uid) { nil }
  let(:home) { nil }
  let(:manage_home) { false }
  let(:password) { <PASSWORD> }
  let(:system) { false }
  let(:comment) { nil }

  let(:user_resource) do
    r = Chef::Resource::User.new("TEST USER RESOURCE", run_context)
    r.username(username)
    r.uid(uid)
    r.home(home)
    r.comment(comment)
    r.manage_home(manage_home)
    r.password(password)
    r.system(system)
    r
  end

  let(:skip) { false }

  describe "action :create" do

    context "when the user does not exist beforehand" do
      before do
        if reason = skip
          pending(reason)
        end
        user_resource.run_action(:create)
        user_resource.should be_updated_by_last_action
      end


      it "ensures the user exists" do
        pw_entry.name.should == username
      end

      #  On Debian, the only constraints are that usernames must neither start
      #  with a dash ('-') nor plus ('+') nor tilde ('~') nor contain a colon
      #  (':'), a comma (','), or a whitespace (space: ' ', end of line: '\n',
      #  tabulation: '\t', etc.). Note that using a slash ('/') may break the
      #  default algorithm for the definition of the user's home directory.

      context "and the username contains a single quote" do
        let(:skip) do
          if supports_quote_in_username?
            false
          else
            "Platform #{OHAI_SYSTEM["platform"]} not expected to support username w/ quote"
          end
        end

        let(:username) { "t'bilisi" }

        it "ensures the user exists" do
          pw_entry.name.should == username
        end
      end


      context "when uid is set" do
        # Should verify uid not in use...
        let(:uid) { 1999 }

        it "ensures the user has the given uid" do
          pw_entry.uid.should == "1999"
        end
      end

      context "when comment is set" do
        let(:comment) { "hello this is dog" }

        it "ensures the comment is set" do
          pw_entry.gecos.should == "hello this is dog"
        end

        context "in standard gecos format" do
          let(:comment) { "<NAME>,some building,555-555-5555,@boboclown" }

          it "ensures the comment is set" do
            pw_entry.gecos.should == comment
{'fraction_non_alphanumeric': 0.10894660894660894, 'fraction_numerical': 0.006596578025149453, 'mean_word_length': 2.630003741114852, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5548057', 'n_tokens_mistral': 3072, 'n_tokens_neox': 2893, 'n_words': 948}