   (testing "service-id should be able to be called from any lifecycle phase"
     (let [test-context (atom {})
           service1 (service Service1
-                            []
-                            (init [this context]
-                                  (swap! test-context assoc :init-service-id (svcs/service-id this))
-                                  context)
-                            (start [this context]
-                                   (swap! test-context assoc :start-service-id (svcs/service-id this))
-                                   context)
-                            (stop [this context]
-                                  (swap! test-context assoc :stop-service-id (svcs/service-id this))
-                                  context)
-                            (service1-fn [this] nil))]
+                     []
+                     (init [this context]
+                           (swap! test-context assoc :init-service-id (svcs/service-id this))
+                           context)
+                     (start [this context]
+                            (swap! test-context assoc :start-service-id (svcs/service-id this))
+                            context)
+                     (stop [this context]
+                           (swap! test-context assoc :stop-service-id (svcs/service-id this))
+                           context)
+                     (service1-fn [this] nil))]
       (with-app-with-empty-config app [service1]
         ;; no-op; we just want the app to start up and shut down
         )

  (testing "minimal services can be defined without a protocol"
    (let [call-seq (atom [])
          service0 (service []
                            (init [this context]
                                  (swap! call-seq conj :init)
                                  (assoc context :foo :bar))
                            (start [this context]
                                   (swap! call-seq conj :start)
                                   (is (= context {:foo :bar}))
                                   context))]
      (bootstrap-services-with-empty-config [service0])
      (is (= [:init :start] @call-seq))))

  (testing "minimal services can have dependencies"
    (let [service1 (service Service1
                            []
                            (service1-fn [this] "hi"))
          result   (atom nil)
          service0 (service [[:Service1 service1-fn]]
                            (init [this context]
                                  (reset! result (service1-fn))
                                  context))]
          (bootstrap-services-with-empty-config [service1 service0])
          (is (= "hi" @result)))))

(defprotocol MultiArityService
  (foo [this x] [this x y]))

(deftest context-test
  (testing "should error if lifecycle function doesn't return context"
    (is (thrown-with-msg?
         IllegalStateException
         (re-pattern (str "Lifecycle function 'init' for service "
                          "'puppetlabs.trapperkeeper.services-test/service1'"
                          " must return a context map \\(got: \"hi\"\\)"))
         (bootstrap-services-with-empty-config [service1]))
        "Unexpected shutdown reason for bootstrap")
    (is (thrown-with-msg?
         IllegalStateException
         (re-pattern (str "Lifecycle function 'start' for service "
                          "'puppetlabs.trapperkeeper.services-test/service1-alt'"
                          " must return a context map "
                          "\\(got: \"hi\"\\)"))
         (bootstrap-services-with-empty-config [service1-alt]))
        "Unexpected shutdown reason for bootstrap"))

  (testing "lifecycle error works if service has no service symbol"
    (let [service1 (service Service1
                     []
                     (init [this context] "hi")
                     (service1-fn [this] "hi"))]
      (is (thrown-with-msg?
           IllegalStateException
           (re-pattern (str "Lifecycle function 'init' for service ':Service1'"
                            " must return a context map \\(got: \"hi\"\\)"))
           (bootstrap-services-with-empty-config [service1]))
          "Unexpected shutdown reason for bootstrap"))
    (let [service1 (service Service1
                     []
                     (start [this context] "hi")
                     (service1-fn [this] "hi"))]

      (is (thrown-with-msg?
           IllegalStateException
           (re-pattern (str "Lifecycle function 'start' for service "
                            "':Service1' must return a context map "
                            "\\(got: \"hi\"\\)"))
           (bootstrap-services-with-empty-config [service1]))
          "Unexpected shutdown reason for bootstrap")))

  (testing "context should be available in subsequent lifecycle functions"
    (let [start-context (atom nil)
          service1 (service Service1
                     []
                     (init [this context] (assoc context :foo :bar))
                     (start [this context] (reset! start-context context))
                     (service1-fn [this] "hi"))]
      (bootstrap-services-with-empty-config [service1])
      (is (= {:foo :bar} @start-context))))

  (testing "context should be accessible in service functions"
    (let [sfn-context (atom nil)
          service1 (service Service1
                     []
                     (init [this context] (assoc context :foo :bar))
                     (service1-fn [this] (reset! sfn-context (svcs/service-context this))))
          app (bootstrap-services-with-empty-config [service1])
          s1  (app/get-service app :Service1)]
      (service1-fn s1)
