LAWS.bend
bend-kube-runtime@0.2.0.0 · 304 lines · 33 definitions
1import Base
2import bend-kube-runtime@0.2.0.0/src/json.bend as J
3import bend-kube-runtime@0.2.0.0/src/core.bend as C
4import bend-kube-runtime@0.2.0.0/src/watcher.bend as W
5import bend-kube-runtime@0.2.0.0/src/store.bend as S
6import bend-kube-runtime@0.2.0.0/src/queue.bend as Q
7import bend-kube-runtime@0.2.0.0/src/finalizer.bend as F
8import bend-kube-runtime@0.2.0.0/src/http.bend as H
9import bend-kube-runtime@0.2.0.0/src/utf8.bend as U
10import bend-kube-runtime@0.2.0.0/src/proxy.bend as P
11
12
13
14
15
16
17
18
19
20
21
22
23law watch_gone_relists:
24 for rv: String
25 for f: U32
26 for first: Bool
27 for r: String
28 for m: String
29 {W.Watcher.step(W.WState{W.WWatch{rv}, f, first}, W.IEvent{C.WError{C.Status{410, r, m}}})
30 == W.Step{W.WState{W.WList{""}, f, True{}}, Nil{}, False{}} : W.Step}
31
32
33law watch_request_gone_relists:
34 for rv: String
35 for f: U32
36 for first: Bool
37 {W.Watcher.step(W.WState{W.WWatch{rv}, f, first}, W.IWatchErr{410})
38 == W.Step{W.WState{W.WList{""}, f, True{}}, Nil{}, False{}} : W.Step}
39
40
41law list_gone_relists:
42 for c: String
43 for f: U32
44 for first: Bool
45 {W.Watcher.step(W.WState{W.WList{c}, f, first}, W.IListErr{410})
46 == W.Step{W.WState{W.WList{""}, f, True{}}, Nil{}, False{}} : W.Step}
47
48
49
50law watch_error_backs_off:
51 for rv: String
52 for f: U32
53 for first: Bool
54 {W.Watcher.step(W.WState{W.WWatch{rv}, f, first}, W.IWatchErr{500})
55 == W.Step{W.WState{W.WWatch{rv}, (f + 1 : U32), False{}}, Nil{}, True{}} : W.Step}
56
57
58
59law watch_end_resumes:
60 for rv: String
61 for f: U32
62 for first: Bool
63 {W.Watcher.step(W.WState{W.WWatch{rv}, f, first}, W.IWatchEnd{})
64 == W.Step{W.WState{W.WWatch{rv}, 0, False{}}, Nil{}, False{}} : W.Step}
65
66
67law bookmark_advances:
68 for rv: String
69 for v: String
70 for f: U32
71 for first: Bool
72 {W.Watcher.step(W.WState{W.WWatch{rv}, f, first}, W.IEvent{C.WBookmark{v}})
73 == W.Step{W.WState{W.WWatch{v}, 0, False{}}, Nil{}, False{}} : W.Step}
74
75
76
77law last_page_watches:
78 for c: String
79 for f: U32
80 for first: Bool
81 for items: List<&2, J.Json>
82 for rv: String
83 {W.Watcher.step(W.WState{W.WList{c}, f, first}, W.IPage{C.Page{items, rv, ""}})
84 == W.Step{W.WState{W.WWatch{rv}, 0, True{}},
85 W.Watcher.init_out(first, W.Watcher.page_outs(items, [W.OInitDone{}])), False{}} : W.Step}
86
87
88law first_page_inits:
89 for items: List<&2, J.Json>
90 {W.Watcher.init_out(True{}, W.Watcher.page_outs(items, Nil{}))
91 == W.OInit{} <> W.Watcher.page_outs(items, Nil{}) : List<&2, W.Out>}
92
93
94law watch_backoff_capped:
95 {W.Backoff.delay(6) == 30000 : U32}
96
97
98
99
100
101law init_clears_buffer:
102 for objs: Map<&2, J.Json>
103 for buf: Map<&2, J.Json>
104 for r: Bool
105 {S.Store.apply(S.Store{objs, buf, r}, W.OInit{})
106 == S.Store{objs, Map.new(&2, J.Json), r} : S.Store}
107
108
109
110law init_done_swaps:
111 for objs: Map<&2, J.Json>
112 for buf: Map<&2, J.Json>
113 for r: Bool
114 {S.Store.apply(S.Store{objs, buf, r}, W.OInitDone{})
115 == S.Store{buf, Map.new(&2, J.Json), True{}} : S.Store}
116
117
118
119
120
121
122law add_running_marks_dirty:
123 for f: List<&2, String>
124 for b: List<&2, String>
125 for inq: Map<&2, U32>
126 for run: Map<&2, U32>
127 for d: Map<&2, U32>
128 for g: Map<&2, U32>
129 for fl: Map<&2, U32>
130 for n: U32
131 for mx: U32
132 for key: String
133 for running: {Q.Mp.has(run, key) == True{} : Bool}
134 {Q.Queue.add(Q.Queue{f, b, inq, run, d, g, fl, n, mx}, key)
135 == Q.Queue{f, b, inq, run, Q.Mp.on(d, key), Q.Mp.bump(g, key), fl, n, mx} : Q.Queue}
136
137
138law add_waiting_dedups:
139 for f: List<&2, String>
140 for b: List<&2, String>
141 for inq: Map<&2, U32>
142 for run: Map<&2, U32>
143 for d: Map<&2, U32>
144 for g: Map<&2, U32>
145 for fl: Map<&2, U32>
146 for n: U32
147 for mx: U32
148 for key: String
149 for idle: {Q.Mp.has(run, key) == False{} : Bool}
150 for waiting: {Q.Mp.has(inq, key) == True{} : Bool}
151 {Q.Queue.add(Q.Queue{f, b, inq, run, d, g, fl, n, mx}, key)
152 == Q.Queue{f, b, inq, run, d, Q.Mp.bump(g, key), fl, n, mx} : Q.Queue}
153
154
155law pop_respects_limit:
156 for f: List<&2, String>
157 for b: List<&2, String>
158 for inq: Map<&2, U32>
159 for run: Map<&2, U32>
160 for d: Map<&2, U32>
161 for g: Map<&2, U32>
162 for fl: Map<&2, U32>
163 for n: U32
164 for mx: U32
165 for full: {U32.is_lt(n, mx) == False{} : Bool}
166 {Q.Queue.pop(Q.Queue{f, b, inq, run, d, g, fl, n, mx})
167 == (Q.Queue{f, b, inq, run, d, g, fl, n, mx}, None{}) : Q.Queue & Maybe<&2, String>}
168
169
170law retry_backoff_capped:
171 {Q.Queue.backoff(18) == 1000000 : U32}
172
173
174law done_idle_noop:
175 for q: Q.Queue
176 for key: String
177 for a: Q.Action
178 for idle: {Q.Queue.running(q, key) == False{} : Bool}
179 {Q.Queue.done(q, key, a) == (q, Nil{}) : Q.Queue & List<&2, Q.Timer>}
180
181
182law forget_running_keeps:
183 for q: Q.Queue
184 for key: String
185 for running: {Q.Queue.running(q, key) == True{} : Bool}
186 {Q.Queue.forget(q, key) == q : Q.Queue}
187
188
189
190
191
192law fin_live_applies:
193 for fs: List<&2, String>
194 for name: String
195 for i: U32
196 {F.Fin.state.go(fs, name, Some{i}, False{}) == F.FApply{} : F.FState}
197
198
199law fin_gone_done:
200 for fs: List<&2, String>
201 for name: String
202 {F.Fin.state.go(fs, name, None{}, True{}) == F.FDone{} : F.FState}
203
204
205
206law fin_cleanup_tests:
207 for fs: List<&2, String>
208 for name: String
209 for i: U32
210 {F.Fin.state.go(fs, name, Some{i}, True{}) == F.FCleanup{F.Fin.remove_patch(i, name)} : F.FState}
211
212
213
214
215
216
217law eof_before_response_is_lost:
218 for t: U32
219 for h: Maybe<&2, H.Head>
220 for o: List<&2, U32>
221 {H.Http.eof(H.Resp{H.PHead{Nil{}, t}, h, o})
222 == H.Resp{H.PLost{"connection closed before a response"}, h, o} : H.Resp}
223
224
225law eof_mid_response_is_broken:
226 for b: U32
227 for bs: List<&2, U32>
228 for t: U32
229 for h: Maybe<&2, H.Head>
230 for o: List<&2, U32>
231 {H.Http.eof(H.Resp{H.PHead{b <> bs, t}, h, o})
232 == H.Resp{H.PErr{"connection closed mid-response"}, h, o} : H.Resp}
233
234
235
236
237
238
239law proxy_skips_localhost:
240 for url: String
241 for no: String
242 for port: U32
243 {P.Proxy.route(url, no, "localhost", port) == P.Direct{} : P.Route}
244
245law proxy_skips_loopback:
246 for url: String
247 for no: String
248 for port: U32
249 {P.Proxy.route(url, no, "127.0.0.1", port) == P.Direct{} : P.Route}
250
251
252law no_proxy_star_bypasses:
253 for url: String
254 for port: U32
255 {P.Proxy.route(url, "*", "api.example.com", port) == P.Direct{} : P.Route}
256
257
258law no_proxy_url_is_direct:
259 for port: U32
260 {P.Proxy.route("", "", "api.example.com", port) == P.Direct{} : P.Route}
261
262
263
264law unsupported_proxy_fails:
265 for port: U32
266 {P.Proxy.route("socks5://proxy:1080", "", "api.example.com", port)
267 == P.NoRoute{"HTTPS_PROXY: only http:// proxies are supported"} : P.Route}
268
269
270law no_proxy_dot_is_subdomains_only:
271 {P.Proxy.route("http://proxy:3128", ".corp", "corp", 443)
272 == P.Via{P.Proxy{"proxy", 3128, ""}} : P.Route}
273
274
275
276law no_proxy_respects_labels:
277 {P.Proxy.route("http://proxy:3128", "corp", "evilcorp", 443)
278 == P.Via{P.Proxy{"proxy", 3128, ""}} : P.Route}
279
280
281law no_proxy_port_narrows:
282 {P.Proxy.route("http://proxy:3128", "api.corp:6443", "api.corp", 443)
283 == P.Via{P.Proxy{"proxy", 3128, ""}} : P.Route}
284
285
286law tunnel_needs_200:
287 {P.Tunnel.feed(P.Tunnel.init(),
288 U.Utf8.encode("HTTP/1.1 407 Proxy Authentication Required\r\n\r\n"))
289 == P.TFail{"proxy refused CONNECT: HTTP/1.1 407 Proxy Authentication Required"} : P.Tunnel}
290
291
292
293law tunnel_rejects_early_bytes:
294 for b: U32
295 for bs: List<&2, U32>
296 {P.Tunnel.feed(P.Tunnel.init(),
297 List.append(&2, U32, U.Utf8.encode("HTTP/1.1 200 OK\r\n\r\n"), b <> bs))
298 == P.TFail{"proxy sent bytes before the TLS handshake"} : P.Tunnel}
299
300
301law tunnel_end_before_answer:
302 for h: List<&2, U32>
303 {P.Tunnel.feed(P.TMore{h}, Nil{})
304 == P.TFail{"proxy closed the connection before answering CONNECT"} : P.Tunnel}