1 /**
2  * Tests all Network implementations.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.sys.net.test;
15 
16 import std.array;
17 import std.file;
18 import std.process : environment;
19 
20 import ae.net.http.common;
21 import ae.sys.data : Data;
22 import ae.sys.dataset : DataVec, joinToGC;
23 import ae.utils.array : asBytes, as;
24 
25 static import ae.sys.net.ae;
26 static import ae.sys.net.curl;
27 version(Windows)
28 static import ae.sys.net.wininet;
29 static import ae.sys.net.cachedcurl;
30 
31 debug static import std.stdio;
32 
33 /// Test endpoint base.
34 /// Server-side test scripts are here:
35 /// https://gist.github.com/58df32ed1dbe64fffd0545f87d9321ad
36 string testBaseURL = "http://thecybershadow.net/d/nettest/"; // (must be HTTP)
37 
38 /// Test a `ae.sys.net.Network` implementation.
39 void test(string moduleName, string className)()
40 {
41 	debug std.stdio.stderr.writeln("Testing " ~ className);
42 
43 	mixin("import ae.sys.net." ~ moduleName ~ ";");
44 	mixin("alias Net = " ~ className ~ ";");
45 	auto net = new Net();
46 
47 	debug std.stdio.stderr.writeln(" - getFile");
48 	{
49 		assert(net.getFile(testBaseURL ~ "testUrl1") == "Hello world\n");
50 	}
51 
52 	debug std.stdio.stderr.writeln(" - downloadFile");
53 	{
54 		enum fn = "test.txt";
55 		if (fn.exists) fn.remove();
56 		scope(exit) if (fn.exists) fn.remove();
57 
58 		net.downloadFile(testBaseURL ~ "testUrl1", fn);
59 		assert(fn.readText() == "Hello world\n");
60 	}
61 
62 	debug std.stdio.stderr.writeln(" - urlOK");
63 	{
64 		assert( net.urlOK(testBaseURL ~ "testUrl1"));
65 		assert(!net.urlOK(testBaseURL ~ "testUrlNX"));
66 		static if (moduleName == "wininet")
67 			assert( net.urlOK(testBaseURL.replace("http://", "https://") ~  "testUrl1"));
68 	}
69 
70 	debug std.stdio.stderr.writeln(" - resolveRedirect");
71 	{
72 		auto result = net.resolveRedirect(testBaseURL ~ "testUrl3");
73 		assert(result == testBaseURL ~ "testUrl2", result);
74 	}
75 
76 	debug std.stdio.stderr.writeln(" - post");
77 	{
78 		auto result = net.post(testBaseURL ~ "testUrl4", "Hello world\n".asBytes).as!string;
79 		assert(result == "Hello world\n", result);
80 	}
81 
82 	debug std.stdio.stderr.writeln(" - httpRequest");
83 	{
84 		auto request = new HttpRequest(testBaseURL ~ "testUrl5");
85 		request.method = "PUT";
86 		request.headers.add("Test-Request-Header", "foo");
87 		request.data = DataVec(Data("bar".asBytes));
88 		auto response = net.httpRequest(request);
89 		assert(response.status == HttpStatusCode.Accepted);
90 		assert(response.statusMessage == "Custom Message");
91 		assert(response.data.joinToGC() == "PUT foo bar");
92 		assert(response.headers["Test-Response-Header"] == "baz");
93 	}
94 }
95 
96 unittest
97 {
98 	// Don't do network requests on the project tester.
99 	// See:
100 	// - https://github.com/CyberShadow/ae/issues/30
101 	// - https://github.com/dlang/dmd/pull/9618#issuecomment-483214780
102 	if (environment.get("BUILDKITE_AGENT_NAME"))
103 		return;
104 
105 	test!("ae", "AENetwork");
106 	test!("curl", "CurlNetwork");
107 	version(Windows)
108 	test!("wininet", "WinINetNetwork");
109 
110 	import ae.utils.meta : classInit;
111 	auto cacheDir = classInit!(ae.sys.net.cachedcurl.CachedCurlNetwork).cacheDir;
112 	if (cacheDir.exists) cacheDir.rmdirRecurse();
113 	scope(exit) if (cacheDir.exists) cacheDir.rmdirRecurse();
114 	test!("cachedcurl", "CachedCurlNetwork");
115 }