File: bootstrap_test.clj

package info (click to toggle)
trapperkeeper-clojure 4.0.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 964 kB
  • sloc: sh: 189; xml: 73; makefile: 25; java: 5
file content (456 lines) | stat: -rw-r--r-- 25,633 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
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
(ns puppetlabs.trapperkeeper.bootstrap-test
  (:require [clojure.java.io :as io]
            [clojure.string :as string]
            [clojure.test :refer :all]
            [me.raynes.fs :as fs]
            [puppetlabs.kitchensink.classpath :refer [with-additional-classpath-entries]]
            [puppetlabs.kitchensink.core :refer [without-ns]]
            [puppetlabs.trapperkeeper.app :refer [get-service]]
            [puppetlabs.trapperkeeper.bootstrap :as bootstrap]
            [puppetlabs.trapperkeeper.examples.bootstrapping.test-services :refer [hello-world test-fn test-fn-three test-fn-two]]
            [puppetlabs.trapperkeeper.logging :refer [reset-logging]]
            [puppetlabs.trapperkeeper.services :refer [service-map]]
            [puppetlabs.trapperkeeper.testutils.bootstrap :refer [bootstrap-with-empty-config parse-and-bootstrap]]
            [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]]
            [schema.test :as schema-test]
            [slingshot.slingshot :refer [try+]]))

(use-fixtures
 :once
 schema-test/validate-schemas
 ;; Without this, "lein test NAMESPACE" and :only invocations may fail.
 (fn [f] (reset-logging) (f)))

(deftest bootstrapping
  (testing "Valid bootstrap configurations"
    (let [bootstrap-config "./dev-resources/bootstrapping/cli/bootstrap.cfg"
          app (parse-and-bootstrap bootstrap-config)]

      (testing "Can load a service based on a valid bootstrap config string"
        (let [test-svc (get-service app :TestService)
              hello-world-svc (get-service app :HelloWorldService)]
          (is (= (test-fn test-svc) :cli))
          (is (= (hello-world hello-world-svc) "hello world"))))

      (with-additional-classpath-entries ["./dev-resources/bootstrapping/classpath"]
        (testing "Looks for bootstrap config on classpath (dev-resources)"
          (with-test-logging
            (let [app (bootstrap-with-empty-config)
                  test-svc (get-service app :TestService)
                  hello-world-svc (get-service app :HelloWorldService)]
              (is (logged?
                   #"Loading bootstrap config from classpath: 'file:/.*dev-resources/bootstrapping/classpath/bootstrap.cfg'"
                   :debug))
              (is (= (test-fn test-svc) :classpath))
              (is (= (hello-world hello-world-svc) "hello world")))))

        (testing "Gives precedence to bootstrap config in cwd"
          (let [cwd-config (io/file (System/getProperty "user.dir") "bootstrap.cfg")
                test-config (io/file "./dev-resources/bootstrapping/cwd/bootstrap.cfg")]
            ;; This test used to set the user.dir property to the dev-resources dir above,
            ;; however in Java 11 it is illegal to set user.dir at runtime.
            (is (not (.exists cwd-config))
                "A bootstrap config file exists in the cwd, cannot reliably test cwd bootstrap loading!")
            (try
              (io/copy test-config cwd-config)
              (with-test-logging
                (let [app (bootstrap-with-empty-config)
                      test-svc (get-service app :TestService)
                      hello-world-svc (get-service app :HelloWorldService)]
                  (is (logged?
                       #"Loading bootstrap config from current working directory: '.*/bootstrap.cfg'"
                       :debug))
                  (is (= (test-fn test-svc) :cwd))
                  (is (= (hello-world hello-world-svc) "hello world"))))
              (finally (io/delete-file cwd-config)))))

        (testing "Gives precedence to bootstrap config specified as CLI arg"
          (with-test-logging
            (let [bootstrap-path "./dev-resources/bootstrapping/cli/bootstrap.cfg"
                  app (bootstrap-with-empty-config ["--bootstrap-config" bootstrap-path])
                  test-svc (get-service app :TestService)
                  hello-world-svc (get-service app :HelloWorldService)]
              (is (logged?
                   (format "Loading bootstrap configs:\n%s" bootstrap-path)
                   :debug))
              (is (= (test-fn test-svc) :cli))
              (is (= (hello-world hello-world-svc) "hello world")))))))

    (testing "Invalid bootstrap configurations"
      (testing "Bootstrap config path specified on CLI does not exist"
        (let [cfg-path "./dev-resources/bootstrapping/cli/non-existent-bootstrap.cfg"]
          (is (thrown-with-msg?
               IllegalArgumentException
               #"Specified bootstrap config file does not exist: '.*non-existent-bootstrap.cfg'"
               (bootstrap-with-empty-config ["--bootstrap-config" cfg-path])))))

      (testing "No bootstrap config found"
        (is (thrown-with-msg?
             IllegalStateException
             #"Unable to find bootstrap.cfg file via --bootstrap-config command line argument, current working directory, or on classpath"
             (bootstrap-with-empty-config)))
        (let [got-expected-exception (atom false)]
          (try+
            (bootstrap-with-empty-config ["--bootstrap-config" nil])
            (catch map? m
              (is (contains? m :kind))
              (is (= :cli-error (without-ns (:kind m))))
              (is (= :puppetlabs.kitchensink.core/cli-error (:kind m)))
              (is (contains? m :msg))
              (is (re-find
                   #"Missing required argument for.*--bootstrap-config"
                   (m :msg)))
              (reset! got-expected-exception true)))
          (is (true? @got-expected-exception))))

      (testing "Bad line in bootstrap config file"
        (let [bootstrap-config "./dev-resources/bootstrapping/cli/invalid_entry_bootstrap.cfg"]
          (is (thrown-with-msg?
               IllegalArgumentException
               #"(?is)Invalid line in bootstrap.*This is not a legit line"
               (parse-and-bootstrap bootstrap-config)))))

      (testing "Invalid service graph"
        (let [bootstrap-config "./dev-resources/bootstrapping/cli/invalid_service_graph_bootstrap.cfg"]
          (is (thrown-with-msg?
               IllegalArgumentException
               #"Invalid service definition;"
               (parse-and-bootstrap bootstrap-config)))))))

  (testing "comments allowed in bootstrap config file"
    (let [bootstrap-config "./dev-resources/bootstrapping/cli/bootstrap_with_comments.cfg"
          service-maps (->> bootstrap-config
                            bootstrap/parse-bootstrap-config!
                            (map service-map))]
      (is (= (count service-maps) 2))
      (is (contains? (first service-maps) :HelloWorldService))
      (is (contains? (second service-maps) :TestService)))))

(deftest empty-bootstrap
  (testing "Empty bootstrap causes error"
    (testing "single bootstrap file"
      (let [bootstrap-config "./dev-resources/bootstrapping/cli/empty_bootstrap.cfg"]
        (is (thrown-with-msg?
             Exception
             (re-pattern (str "No entries found in any supplied bootstrap file\\(s\\):\n"
                              "./dev-resources/bootstrapping/cli/empty_bootstrap.cfg"))
             (bootstrap/parse-bootstrap-config! bootstrap-config)))))

    (testing "multiple bootstrap files"
      (let [bootstraps ["./dev-resources/bootstrapping/cli/split_bootstraps/empty/empty1.cfg"
                        "./dev-resources/bootstrapping/cli/split_bootstraps/empty/empty2.cfg"]]
        (is (thrown-with-msg?
             Exception
             (re-pattern (str "No entries found in any supplied bootstrap file\\(s\\):\n"
                              (string/join "\n" bootstraps)))
             (bootstrap/parse-bootstrap-configs! bootstraps)))))))

(deftest multiple-bootstrap-files
  (testing "Multiple bootstrap files can be specified directly on the command line"
    (with-test-logging
      (let [bootstrap-one "./dev-resources/bootstrapping/cli/split_bootstraps/one/bootstrap_one.cfg"
            bootstrap-two "./dev-resources/bootstrapping/cli/split_bootstraps/two/bootstrap_two.cfg"
            bootstrap-path (format "%s,%s" bootstrap-one bootstrap-two)
            app (bootstrap-with-empty-config ["--bootstrap-config" bootstrap-path])
            test-svc (get-service app :TestService)
            test-svc-two (get-service app :TestServiceTwo)
            test-svc-three (get-service app :TestServiceThree)
            hello-world-svc (get-service app :HelloWorldService)]
        (is (logged?
             (format "Loading bootstrap configs:\n%s\n%s"
                     bootstrap-one
                     bootstrap-two)
             :debug))
        (is (= (test-fn test-svc) :cli))
        (is (= (test-fn-two test-svc-two) :two))
        (is (= (test-fn-three test-svc-three) :three))
        (is (= (hello-world hello-world-svc) "hello world")))))
  (testing "A path containing multiple .cfg files can be specified on the command line"
    (with-test-logging
      (let [bootstrap-path "./dev-resources/bootstrapping/cli/split_bootstraps/both/"
            app (bootstrap-with-empty-config ["--bootstrap-config" bootstrap-path])
            test-svc (get-service app :TestService)
            test-svc-two (get-service app :TestServiceTwo)
            test-svc-three (get-service app :TestServiceThree)
            hello-world-svc (get-service app :HelloWorldService)]
        (is (logged?
             ; We can't know what order it will find the files on disk, so just
             ; look for a partial match with the path we gave TK.
             (re-pattern (format "Loading bootstrap configs:\n%s"
                                 (fs/absolute bootstrap-path)))
             :debug))
        (is (= (test-fn test-svc) :cli))
        (is (= (test-fn-two test-svc-two) :two))
        (is (= (test-fn-three test-svc-three) :three))
        (is (= (hello-world hello-world-svc) "hello world")))))
  (testing "A path containing both a file and a folder can be specified on the command line"
    (with-test-logging
      (let [bootstrap-one-dir "./dev-resources/bootstrapping/cli/split_bootstraps/one/"
            bootstrap-one "./dev-resources/bootstrapping/cli/split_bootstraps/one/bootstrap_one.cfg"
            bootstrap-two "./dev-resources/bootstrapping/cli/split_bootstraps/two/bootstrap_two.cfg"
            bootstrap-path (format "%s,%s" bootstrap-one-dir bootstrap-two)
            app (bootstrap-with-empty-config ["--bootstrap-config" bootstrap-path])
            test-svc (get-service app :TestService)
            test-svc-two (get-service app :TestServiceTwo)
            test-svc-three (get-service app :TestServiceThree)
            hello-world-svc (get-service app :HelloWorldService)]
        (is (logged?
             (format "Loading bootstrap configs:\n%s\n%s"
                     (fs/absolute bootstrap-one)
                     bootstrap-two)
             :debug))
        (is (= (test-fn test-svc) :cli))
        (is (= (test-fn-two test-svc-two) :two))
        (is (= (test-fn-three test-svc-three) :three))
        (is (= (hello-world hello-world-svc) "hello world"))))))

(deftest bootstrap-path-with-spaces
  (testing "Ensure that a bootstrap config can be loaded with a path that contains spaces"
    (with-test-logging
      (let [bootstrap-path "./dev-resources/bootstrapping/cli/path with spaces/bootstrap.cfg"
            app (bootstrap-with-empty-config
                 ["--bootstrap-config" bootstrap-path])
            test-svc (get-service app :TestService)
            hello-world-svc (get-service app :HelloWorldService)]
        (is (logged?
             (format "Loading bootstrap configs:\n%s" bootstrap-path)
             :debug))
        (is (= (test-fn test-svc) :cli))
        (is (= (hello-world hello-world-svc) "hello world")))))
  (testing "Multiple bootstrap files can be specified with spaces in the names"
    (with-test-logging
      (let [bootstrap-one "./dev-resources/bootstrapping/cli/split_bootstraps/spaces/bootstrap with spaces one.cfg"
            bootstrap-two "./dev-resources/bootstrapping/cli/split_bootstraps/spaces/bootstrap with spaces two.cfg"
            bootstrap-path (format "%s,%s" bootstrap-one bootstrap-two)
            app (bootstrap-with-empty-config ["--bootstrap-config" bootstrap-path])
            test-svc (get-service app :TestService)
            test-svc-two (get-service app :TestServiceTwo)
            test-svc-three (get-service app :TestServiceThree)
            hello-world-svc (get-service app :HelloWorldService)]
        (is (logged?
             (format "Loading bootstrap configs:\n%s\n%s"
                     bootstrap-one
                     bootstrap-two)
             :debug))
        (is (= (test-fn test-svc) :cli))
        (is (= (test-fn-two test-svc-two) :two))
        (is (= (test-fn-three test-svc-three) :three))
        (is (= (hello-world hello-world-svc) "hello world"))))))

(deftest duplicate-service-entries
  (testing "duplicate bootstrap entries are allowed"
    (let [bootstrap-path "./dev-resources/bootstrapping/cli/duplicate_entries.cfg"
          app (bootstrap-with-empty-config
               ["--bootstrap-config" bootstrap-path])
          hello-world-svc (get-service app :HelloWorldService)]
      (is (= (hello-world hello-world-svc) "hello world")))))

(deftest duplicate-service-definitions
  (testing "Duplicate service definitions causes error with filename and line numbers"
    (let [bootstraps ["./dev-resources/bootstrapping/cli/duplicate_services/duplicates.cfg"]]
      (is (thrown-with-msg?
           IllegalArgumentException
           (re-pattern (str "Duplicate implementations found for service protocol ':TestService':\n"
                            ".*/duplicates.cfg:2\n"
                            "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/cli-test-service\n"
                            ".*/duplicates.cfg:3\n"
                            "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/foo-test-service\n"
                            "Duplicate implementations.*\n"
                            ".*/duplicates.cfg:5\n"
                            ".*test-service-two\n"
                            ".*/duplicates.cfg:6\n"
                            ".*test-service-two-duplicate"))
           (bootstrap/parse-bootstrap-configs! bootstraps))))
    (testing "Duplicate service definitions between two files throws error"
      (let [bootstraps ["./dev-resources/bootstrapping/cli/duplicate_services/split_one.cfg"
                        "./dev-resources/bootstrapping/cli/duplicate_services/split_two.cfg"]]
        (is (thrown-with-msg?
             IllegalArgumentException
             (re-pattern (str "Duplicate implementations found for service protocol ':TestService':\n"
                              ".*/split_one.cfg:2\n"
                              "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/foo-test-service\n"
                              ".*/split_two.cfg:2\n"
                              "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/cli-test-service\n"
                              "Duplicate implementations.*\n"
                              ".*/split_one.cfg:4\n"
                              ".*test-service-two-duplicate\n"
                              ".*/split_two.cfg:4\n"
                              ".*test-service-two"))
             (bootstrap/parse-bootstrap-configs! bootstraps)))))))

(deftest config-file-in-jar
  (testing "Bootstrapping via a config file contained in a .jar as command line option"
    (let [jar (io/file "./dev-resources/bootstrapping/jar/this-jar-contains-a-bootstrap-config-file.jar")
          bootstrap-url (str "jar:file:///" (.getAbsolutePath jar) "!/bootstrap.cfg")]
      ;; just test that this bootstrap config file can be read successfully
      ;; (ie, this does not throw an exception)
      (bootstrap-with-empty-config ["--bootstrap-config" bootstrap-url]))))

(deftest config-from-classpath-test
  (testing "can locate bootstrap file on the classpath"
    (let [bootstrap-file "./dev-resources/bootstrapping/classpath/bootstrap.cfg"
          bootstrap-uri (str "file:" (.getCanonicalPath (io/file bootstrap-file)))]
      (with-additional-classpath-entries
       ["./dev-resources/bootstrapping/classpath/"]
       (let [found-bootstraps (bootstrap/config-from-classpath)]
         (is (= 1 (count found-bootstraps)))
         (is (= bootstrap-uri (first found-bootstraps)))))))

  (testing "can locate bootstrap file contained in a .jar on the classpath"
    (let [jar "./dev-resources/bootstrapping/jar/this-jar-contains-a-bootstrap-config-file.jar"
          jar-uri (str "file:" (.getAbsolutePath (io/file jar)))
          expected-resource-uri (format "jar:%s!/bootstrap.cfg" jar-uri)]
      (with-additional-classpath-entries
       ["./dev-resources/bootstrapping/jar/this-jar-contains-a-bootstrap-config-file.jar"]
       (let [found-bootstraps (bootstrap/config-from-classpath)]
         (is (= 1 (count found-bootstraps)))
         (is (= expected-resource-uri (first found-bootstraps))))))))

(deftest parse-bootstrap-config-test
  (testing "Missing service namespace logs warning"
    (with-test-logging
      (let [bootstrap-config "./dev-resources/bootstrapping/cli/fake_namespace_bootstrap.cfg"]
        (bootstrap/parse-bootstrap-config! bootstrap-config)
        (is (logged?
             (str "Unable to load service 'non-existent-service/test-service' from "
                  "./dev-resources/bootstrapping/cli/fake_namespace_bootstrap.cfg:3")
             :warn)))))

  (testing "Missing service definition logs warning"
    (with-test-logging
      (let [bootstrap-config "./dev-resources/bootstrapping/cli/missing_definition_bootstrap.cfg"]
        (bootstrap/parse-bootstrap-config! bootstrap-config)
        (is (logged?
             (str "Unable to load service "
                  "'puppetlabs.trapperkeeper.examples.bootstrapping.test-services/non-existent-service' "
                  "from ./dev-resources/bootstrapping/cli/missing_definition_bootstrap.cfg:3")
             :warn)))))

  (testing "errors are thrown with line number and file"
    ; Load a bootstrap with a bad service graph to generate an error
    (let [bootstrap "./dev-resources/bootstrapping/cli/invalid_service_graph_bootstrap.cfg"]
      (is (thrown-with-msg?
           IllegalArgumentException
           (re-pattern (str "Problem loading service "
                            "'puppetlabs.trapperkeeper.examples.bootstrapping.test-services/invalid-service-graph-service' "
                            "from ./dev-resources/bootstrapping/cli/invalid_service_graph_bootstrap.cfg:1:\n"
                            "Invalid service definition"))
           (bootstrap/parse-bootstrap-config! bootstrap))))))

(deftest get-annotated-bootstrap-entries-test
  (testing "file with comments"
    (let [bootstraps ["./dev-resources/bootstrapping/cli/bootstrap_with_comments.cfg"]
          entries (bootstrap/get-annotated-bootstrap-entries bootstraps)]
        (is (= [{:bootstrap-file "./dev-resources/bootstrapping/cli/bootstrap_with_comments.cfg"
                 :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/hello-world-service"
                 :line-number 2}
                {:bootstrap-file "./dev-resources/bootstrapping/cli/bootstrap_with_comments.cfg"
                 :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/foo-test-service"
                 :line-number 5}]
               entries))))
  (testing "multiple bootstrap files"
    (let [bootstraps ["./dev-resources/bootstrapping/cli/split_bootstraps/both/bootstrap_one.cfg"
                      "./dev-resources/bootstrapping/cli/split_bootstraps/both/bootstrap_two.cfg"]
          entries (bootstrap/get-annotated-bootstrap-entries bootstraps)]
        (is (= [{:bootstrap-file "./dev-resources/bootstrapping/cli/split_bootstraps/both/bootstrap_one.cfg"
                 :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/cli-test-service"
                 :line-number 1}
                {:bootstrap-file "./dev-resources/bootstrapping/cli/split_bootstraps/both/bootstrap_one.cfg"
                 :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/hello-world-service"
                 :line-number 2}
                {:bootstrap-file "./dev-resources/bootstrapping/cli/split_bootstraps/both/bootstrap_two.cfg"
                 :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/test-service-two"
                 :line-number 1}
                {:bootstrap-file "./dev-resources/bootstrapping/cli/split_bootstraps/both/bootstrap_two.cfg"
                 :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/test-service-three"
                 :line-number 2}]
               entries)))))

(deftest find-duplicates-test
  (testing "correct duplicates found"
    (let [items [{:important-key :one
                  :other-key 2}
                 {:important-key :one
                  :other-key 3}
                 {:important-key :two
                  :other-key 4}
                 {:important-key :three
                  :other-key 5}]]
      ; List of key value pairs
      (is (= {:one [{:important-key :one
                     :other-key 2}
                    {:important-key :one
                     :other-key 3}]}
             (bootstrap/find-duplicates items :important-key))))))

(deftest check-duplicate-service-implementations!-test
  (testing "no duplicate service implementations does not throw error"
    (let [configs ["./dev-resources/bootstrapping/cli/bootstrap.cfg"]
          bootstrap-entries (bootstrap/get-annotated-bootstrap-entries configs)
          resolved-services (bootstrap/resolve-services! bootstrap-entries)]
      (bootstrap/check-duplicate-service-implementations! resolved-services bootstrap-entries)))
  (testing "duplicate service implementations throws error"
    (let [configs ["./dev-resources/bootstrapping/cli/duplicate_services/duplicates.cfg"]
          bootstrap-entries (bootstrap/get-annotated-bootstrap-entries configs)
          resolved-services (bootstrap/resolve-services! bootstrap-entries)]
      (is (thrown-with-msg?
           IllegalArgumentException
           #"Duplicate implementations found for service protocol ':TestService'"
           (bootstrap/check-duplicate-service-implementations!
            resolved-services
            bootstrap-entries))))))

(deftest remove-duplicate-entries-test
  (testing "single bootstrap with all duplicates"
    (testing "only the first duplicate found is kept"
      (let [configs ["./dev-resources/bootstrapping/cli/duplicate_entries.cfg"]
            bootstrap-entries (bootstrap/get-annotated-bootstrap-entries configs)]
        (is (= [{:bootstrap-file "./dev-resources/bootstrapping/cli/duplicate_entries.cfg"
                 :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/hello-world-service"
                 :line-number 1}]
               (bootstrap/remove-duplicate-entries bootstrap-entries))))))
  (testing "two copies of the same set of services"
    (let [configs ["./dev-resources/bootstrapping/cli/bootstrap.cfg"
                   "./dev-resources/bootstrapping/cli/bootstrap.cfg"]
          bootstrap-entries (bootstrap/get-annotated-bootstrap-entries configs)]
      (is (= [{:bootstrap-file "./dev-resources/bootstrapping/cli/bootstrap.cfg"
               :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/cli-test-service"
               :line-number 1}
              {:bootstrap-file "./dev-resources/bootstrapping/cli/bootstrap.cfg"
               :entry "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/hello-world-service"
               :line-number 2}]
             (bootstrap/remove-duplicate-entries bootstrap-entries))))))

(deftest read-config-test
  (testing "basic config"
    (let [config "./dev-resources/bootstrapping/cli/bootstrap.cfg"]
      (is (= ["puppetlabs.trapperkeeper.examples.bootstrapping.test-services/cli-test-service"
              "puppetlabs.trapperkeeper.examples.bootstrapping.test-services/hello-world-service"]
             (bootstrap/read-config config)))))
  (testing "jar uri"
    (let [jar "./dev-resources/bootstrapping/jar/this-jar-contains-a-bootstrap-config-file.jar"
          config (str "jar:file:///" (.getAbsolutePath (io/file jar)) "!/bootstrap.cfg")]
      ; The bootstrap in the jar contains an empty line at the end
      (is (= ["puppetlabs.trapperkeeper.examples.bootstrapping.test-services/hello-world-service"
              ""]
             (bootstrap/read-config config)))))
  (testing "malformed uri is wrapped in our exception"
    (let [config "\n"]
      (is (thrown-with-msg?
           IllegalArgumentException
           #"Specified bootstrap config file does not exist"
           (bootstrap/read-config config)))))
  (testing "Non-absolute uri is wrapped in our exception"
    ; TODO This path is currently interpreted as a URI because TK checks
    ; if it's a file, and if not, attemps to load as a URI
    (let [config "./not-a-file"]
      (is (thrown-with-msg?
           IllegalArgumentException
           #"Specified bootstrap config file does not exist"
           (println (bootstrap/read-config config))))))
  (testing "Non-existent file in URI is wrapped in our exception"
    (let [config "file:///not-a-file"]
      (is (thrown-with-msg?
           IllegalArgumentException
           #"Specified bootstrap config file does not exist"
           (bootstrap/read-config config))))))