popcorn: pop_test uses NIT_TESTING_ID to determine test port
[nit.git] / lib / popcorn / pop_tests.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Popcorn testing services
16 #
17 # ## Blackbox testing
18 #
19 # Popcorn allows you to test your apps using nitunit blackbox testing.
20 #
21 # With blackbox testing you compare the output of your program with a result file.
22 #
23 # To get started with blackbox testing, create a nitunit test suite and imports
24 # the `pop_tests` module.
25 #
26 # You then need to build the app that will be tested by nitunit as shown in the
27 # `test_example_hello` method.
28 # Calling `run_test` will automatically set the `host` and `port` used for testing.
29 #
30 # Redefine the `client_test` method to write your scenario.
31 # Here we use `curl` to access some URI on the app.
32 #
33 # ~~~nitish
34 # module test_example_hello is test_suite
35 #
36 # import pop_tests
37 # import example_hello
38 #
39 # class TestExampleHello
40 # super TestPopcorn
41 #
42 # fun test_example_hello do
43 # var app = new App
44 # app.use("/", new HelloHandler)
45 # run_test(app)
46 # end
47 #
48 # redef fun client_test do
49 # system "curl -s {host}:{port}"
50 # system "curl -s {host}:{port}/"
51 # system "curl -s {host}:{port}///////////"
52 # system "curl -s {host}:{port}/not_found"
53 # system "curl -s {host}:{port}/not_found/not_found"
54 # end
55 # end
56 # ~~~
57 #
58 # The blackbox testing needs a reference result file against wich the test output
59 # will be compared.
60 # Create your expected result file in `test_example_hello.sav/test_example_hello.res`.
61 #
62 # Test your app by running nitunit:
63 #
64 # ~~~bash
65 # nitunit ./example_hello.nit
66 # ~~~
67 #
68 # See `examples/hello_world` for the complete example.
69 module pop_tests
70
71 import test_suite
72 import popcorn
73 import pthreads
74
75 redef class Sys
76
77 # Use localhost for testing
78 var test_host = "localhost"
79
80 # Return a new port for each instance
81 fun test_port: Int do
82 return testing_id % 20000 + 10000
83 end
84
85 # Nitdoc testing ID
86 fun testing_id: Int do return "NIT_TESTING_ID".environ.to_i
87 end
88
89 # Thread running the App to test.
90 class AppThread
91 super Thread
92
93 # Host used by tested App.
94 var host: String
95
96 # Port used by tested App.
97 var port: Int
98
99 # App to test.
100 var app: App
101
102 redef fun main
103 do
104 # Hide testing concept to force nitcorn to actually run
105 "NIT_TESTING".setenv("false")
106 app.quiet = true
107 app.listen(host, port)
108 return null
109 end
110 end
111
112 # Thread running the test client.
113 class ClientThread
114 super Thread
115
116 # Test suite to execute.
117 var test_suite: TestPopcorn
118
119 redef fun main do
120 test_suite.client_test
121 print ""
122 return null
123 end
124 end
125
126 # TestSuite for Popcorn blackbox testing.
127 class TestPopcorn
128 super TestSuite
129
130 # Host used to run App.
131 var host: String = test_host
132
133 # Port used to run App.
134 var port: Int = test_port
135
136 # Directory of the current test suite
137 #
138 # Useful when your tested app need to load some external files.
139 var test_path: String = "NIT_TESTING_PATH".environ.dirname
140
141 # Run the test suite on the App.
142 fun run_test(app: App) do
143 var server = new AppThread(host, port, app)
144 server.start
145 0.1.sleep
146
147 var client = new ClientThread(self)
148 client.start
149 client.join
150 0.1.sleep
151
152 exit 0
153 end
154
155 # Redefine this method to implement your test scenario.
156 fun client_test do end
157
158 # Regex to catch and hide the port from the output to get consistent results
159 var host_re: Regex = "localhost:\[0-9\]+".to_re
160
161 # Execute a System function.
162 fun system(cmd: String, title: nullable String)
163 do
164 title = title or else cmd
165 title = title.replace(host_re, "localhost:*****")
166 print "\n[Client] {title}"
167 sys.system cmd
168 end
169 end