File: jruby_testutils.clj

package info (click to toggle)
jruby-utils-clojure 5.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 544 kB
  • sloc: java: 768; makefile: 22; sh: 21; xml: 10; ruby: 3
file content (153 lines) | stat: -rw-r--r-- 5,653 bytes parent folder | download | duplicates (2)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
(ns puppetlabs.services.jruby-pool-manager.jruby-testutils
  (:require [puppetlabs.services.jruby-pool-manager.jruby-core :as jruby-core]
            [puppetlabs.services.jruby-pool-manager.jruby-schemas :as jruby-schemas]
            [puppetlabs.services.jruby-pool-manager.impl.jruby-internal :as jruby-internal]
            [puppetlabs.services.jruby-pool-manager.jruby-pool-manager-service :as pool-manager]
            [puppetlabs.trapperkeeper.app :as tk-app]
            [clojure.tools.logging :as log]
            [schema.core :as schema]
            [puppetlabs.services.protocols.pool-manager :as pool-manager-protocol]
            [puppetlabs.trapperkeeper.testutils.bootstrap :as tk-bootstrap])
  (:import (clojure.lang IFn)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Constants

(def ruby-load-path [])
(def gem-home "./target/jruby-gem-home")

(def default-services
  [pool-manager/jruby-pool-manager-service])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; JRuby Test util functions

(schema/defn ^:always-validate
  jruby-config :- jruby-schemas/JRubyConfig
  "Create a JRubyConfig for testing. The optional map argument `options` may
  contain a map, which, if present, will be merged into the final JRubyConfig
  map.  (This function differs from `jruby-tk-config` in that it returns a map
  that complies with the JRubyConfig schema, which differs slightly from the raw
  format that would be read from config files on disk.)"
  ([]
   (jruby-core/initialize-config
    {:ruby-load-path ruby-load-path
     :gem-home gem-home}))
  ([options]
   (jruby-core/initialize-config
    (merge {:ruby-load-path ruby-load-path
            :gem-home gem-home
            :borrow-timeout 300000}
           options))))

(defn drain-pool
  "Drains the JRuby pool and returns each instance in a vector."
  [pool-context size]
  (mapv (fn [_] (jruby-core/borrow-from-pool pool-context :test [])) (range size)))

(defn fill-drained-pool
  "Returns a list of JRubyInstances back to their pool."
  [pool-context instance-list]
  (doseq [instance instance-list]
    (jruby-core/return-to-pool pool-context instance :test [])))

(schema/defn ^:always-validate
  drain-and-refill :- #{schema/Int}
  "Borrow all instances from a pool and then hand them back. Return a set
  (order is not important) of the instance ids borrowed/returned"
  [pool-context :- jruby-schemas/PoolContext]
  (let [instance-count (get-in pool-context [:config :max-active-instances])
        instances (drain-pool pool-context instance-count)
        ids (into #{} (map :id instances))]
    (fill-drained-pool pool-context instances)
    ids))

(defn reduce-over-jrubies!
  "Utility function; takes a JRuby pool and size, and a function f from integer
  to string.  For each JRubyInstance in the pool, f will be called, passing in
  an integer offset into the jruby array (0..size), and f is expected to return
  a string containing a script to run against the jruby instance.

  Returns a vector containing the results of executing the scripts against the
  JRubyInstances."
  [pool-context size f]
  (let [jrubies (drain-pool pool-context size)
        result  (reduce
                  (fn [acc jruby-offset]
                    (let [sc (:scripting-container (nth jrubies jruby-offset))
                          script (f jruby-offset)
                          result (.runScriptlet sc script)]
                      (conj acc result)))
                  []
                  (range size))]
    (fill-drained-pool pool-context jrubies)
    result))

(defn wait-for-jrubies-from-pool-context
  "Wait for all jrubies to land in the pool"
  [pool-context]
  (let [num-jrubies (-> pool-context
                        jruby-core/get-pool-state
                        :size)]
    (while (< (count (jruby-core/registered-instances pool-context))
              num-jrubies)
      (Thread/yield))))

(defn timed-await
  [agent]
  (await-for 240000 agent))

(schema/defn wait-for-predicate :- schema/Bool
  "Wait for some predicate to return true
  defaults to 20 iterations of 500 ms, ~10 seconds
  Returns true if f ever returns true, false otherwise"
  ([f :- IFn]
   (wait-for-predicate f 20 500))
  ([f :- IFn
    max-iterations :- schema/Int
    sleep-time :- schema/Int]
   (loop [count 0]
     (cond (f)
           true

           (>= count max-iterations)
           (do
             (log/debugf "Waiting for predicate failed after %s tries" max-iterations)
             false)

           :default
           (do
             (Thread/sleep sleep-time)
             (recur (inc count)))))))

(schema/defn wait-for-instances :- schema/Bool
  [pool :- jruby-schemas/pool-queue-type
   num-instances :- schema/Int]
  (wait-for-predicate
   #(= num-instances (jruby-core/free-instance-count pool))))

(schema/defn wait-for-pool-to-be-locked :- schema/Bool
  [pool :- jruby-schemas/pool-queue-type]
  (wait-for-predicate #(.isLocked pool)))

(defmacro with-pool-context
  [pool-context services config & body]
  `(tk-bootstrap/with-app-with-config
    app#
    ~services
    {}
    (let [pool-manager-service# (tk-app/get-service app# :PoolManagerService)
          ~pool-context (pool-manager-protocol/create-pool
                         pool-manager-service# ~config)]
      (try
        ~@body
        (finally
          (jruby-core/flush-pool-for-shutdown! ~pool-context))))))

(defmacro with-scripting-container
  [container config & body]
  `(let [~container (jruby-internal/create-scripting-container ~config)]
     (try
       ~@body
       (finally
         (.terminate ~container)))))