File: memcached.rb

package info (click to toggle)
ruby-dalli 3.2.8-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 684 kB
  • sloc: ruby: 6,552; sh: 20; makefile: 4
file content (99 lines) | stat: -rw-r--r-- 3,615 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# frozen_string_literal: true

require 'socket'
require_relative '../utils/certificate_generator'
require_relative '../utils/memcached_manager'
require_relative '../utils/memcached_mock'

module Memcached
  module Helper
    # Forks the current process and starts a new mock Memcached server on
    # port 22122.
    #
    #     memcached_mock(lambda {|sock| socket.write('123') }) do
    #       assert_equal "PONG", Dalli::Client.new('localhost:22122').get('abc')
    #     end
    #
    def memcached_mock(prc, meth = :start, meth_args = [])
      return unless supports_fork?

      begin
        pid = fork_mock_process(prc, meth, meth_args)
        sleep 0.3 # Give time for the socket to start listening.
        yield
      ensure
        kill_process(pid)
      end
    end

    # Launches a memcached process with the specified arguments.  Takes
    # a block to which an initialized Dalli::Client and the port_or_socket
    # is passed.
    #
    # port_or_socket - If numeric or numeric string, treated as a TCP port
    #                  on localhost.  If not, treated as a UNIX domain socket
    # args - Command line args passed to the memcached invocation
    # client_options - Options passed to the Dalli::Client on initialization
    # terminate_process - whether to terminate the memcached process on
    #                     exiting the block
    def memcached(protocol, port_or_socket, args = '', client_options = {}, terminate_process: true)
      dc = MemcachedManager.start_and_flush_with_retry(port_or_socket, args, client_options.merge(protocol: protocol))
      yield dc, port_or_socket if block_given?
      memcached_kill(port_or_socket) if terminate_process
    end

    # Launches a memcached process using the memcached method in this module,
    # but sets terminate_process to false ensuring that the process persists
    # past execution of the block argument.
    # rubocop:disable Metrics/ParameterLists
    def memcached_persistent(protocol = :binary, port_or_socket = 21_345, args = '', client_options = {}, &block)
      memcached(protocol, port_or_socket, args, client_options, terminate_process: false, &block)
    end
    # rubocop:enable Metrics/ParameterLists

    # Launches a persistent memcached process, configured to use SSL
    def memcached_ssl_persistent(protocol = :binary, port_or_socket = rand(21_397..21_896), &block)
      memcached_persistent(protocol,
                           port_or_socket,
                           CertificateGenerator.ssl_args,
                           { ssl_context: CertificateGenerator.ssl_context },
                           &block)
    end

    # Kills the memcached process that was launched using this helper on hte
    # specified port_or_socket.
    def memcached_kill(port_or_socket)
      MemcachedManager.stop(port_or_socket)
    end

    # Launches a persistent memcached process, configured to use SASL authentication
    def memcached_sasl_persistent(port_or_socket = 21_398, &block)
      memcached_persistent(:binary, port_or_socket, '-S', sasl_credentials, &block)
    end

    # The SASL credentials used for the test SASL server
    def sasl_credentials
      { username: 'testuser', password: 'testtest' }
    end

    private

    def fork_mock_process(prc, meth, meth_args)
      fork do
        trap('TERM') { exit }
        MemcachedMock.send(meth, *meth_args) { |*args| prc.call(*args) }
      end
    end

    def kill_process(pid)
      return unless pid

      Process.kill('TERM', pid)
      Process.wait(pid)
    end

    def supports_fork?
      Process.respond_to?(:fork)
    end
  end
end