]> git.mxchange.org Git - simgear.git/blob - simgear/package/CatalogTest.cxx
Use SGBinaryFile in a couple more places.
[simgear.git] / simgear / package / CatalogTest.cxx
1 // Copyright (C) 2015  James Turner - zakalawe@mac.com
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #ifdef HAVE_CONFIG_H
19 #  include <simgear_config.h>
20 #endif
21
22 #include <simgear/misc/test_macros.hxx>
23
24 #include <cstdlib>
25 #include <iostream>
26 #include <fstream>
27
28 #include <simgear/package/Catalog.hxx>
29 #include <simgear/package/Root.hxx>
30 #include <simgear/package/Package.hxx>
31 #include <simgear/package/Install.hxx>
32
33 #include <simgear/misc/test_macros.hxx>
34 #include <simgear/misc/sg_dir.hxx>
35 #include <simgear/timing/timestamp.hxx>
36
37 #include <simgear/io/test_HTTP.hxx>
38 #include <simgear/io/HTTPClient.hxx>
39 #include <simgear/io/sg_file.hxx>
40 #include <simgear/structure/exception.hxx>
41
42 using namespace simgear;
43
44 std::string readFileIntoString(const SGPath& path)
45 {
46     std::string contents;
47
48     size_t readLen;
49     SGBinaryFile f(path.str());
50     if (!f.open(SG_IO_IN)) {
51         throw sg_io_exception("Couldn't open file", path);
52     }
53
54     char buf[8192];
55     while ((readLen = f.read(buf, 8192)) > 0) {
56         contents += std::string(buf, readLen);
57     }
58
59     return contents;
60 }
61
62 SGPath global_serverFilesRoot;
63 unsigned int global_catalogVersion = 0;
64
65 class TestPackageChannel : public TestServerChannel
66 {
67 public:
68
69     virtual void processRequestHeaders()
70     {
71         state = STATE_IDLE;
72         SGPath localPath(global_serverFilesRoot);
73
74
75         if (path == "/catalogTest1/catalog.xml") {
76             if (global_catalogVersion > 0) {
77                 std::stringstream ss;
78                 ss << "/catalogTest1/catalog-v" << global_catalogVersion << ".xml";
79                 path = ss.str();
80             }
81         }
82
83         localPath.append(path);
84
85       //  SG_LOG(SG_IO, SG_INFO, "local path is:" << localPath.str());
86
87         if (localPath.exists()) {
88             std::string content = readFileIntoString(localPath);
89             std::stringstream d;
90             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
91             d << "Content-Length:" << content.size() << "\r\n";
92             d << "\r\n"; // final CRLF to terminate the headers
93             d << content;
94
95             std::string ds(d.str());
96             bufferSend(ds.data(), ds.size());
97         } else {
98             sendErrorResponse(404, false, "");
99         }
100     }
101 };
102
103 TestServer<TestPackageChannel> testServer;
104
105 void waitForUpdateComplete(HTTP::Client* cl, pkg::Root* root)
106 {
107     SGTimeStamp start(SGTimeStamp::now());
108     while (start.elapsedMSec() <  10000) {
109         cl->update();
110         testServer.poll();
111
112         if (!cl->hasActiveRequests()) {
113             return;
114         }
115
116         SGTimeStamp::sleepForMSec(15);
117     }
118
119     std::cerr << "timed out" << std::endl;
120 }
121
122 int parseTest()
123 {
124     SGPath rootPath = simgear::Dir::current().path();
125     rootPath.append("testRoot");
126     pkg::Root* root = new pkg::Root(rootPath, "8.1.12");
127     pkg::CatalogRef cat = pkg::Catalog::createFromPath(root, SGPath(SRC_DIR "/catalogTest1"));
128
129     VERIFY(cat.valid());
130
131     COMPARE(cat->id(), "org.flightgear.test.catalog1");
132     COMPARE(cat->url(), "http://localhost:2000/catalogTest1/catalog.xml");
133     COMPARE(cat->description(), "First test catalog");
134
135 // check the packages too
136     COMPARE(cat->packages().size(), 3);
137
138     pkg::PackageRef p1 = cat->packages().front();
139     COMPARE(p1->catalog(), cat.ptr());
140
141     COMPARE(p1->id(), "alpha");
142     COMPARE(p1->qualifiedId(), "org.flightgear.test.catalog1.alpha");
143     COMPARE(p1->name(), "Alpha package");
144     COMPARE(p1->revision(), 8);
145     COMPARE(p1->fileSizeBytes(), 593);
146
147
148     pkg::PackageRef p2 = cat->getPackageById("c172p");
149     VERIFY(p2.valid());
150     COMPARE(p2->qualifiedId(), "org.flightgear.test.catalog1.c172p");
151     COMPARE(p2->description(), "A plane made by Cessna");
152
153
154
155 // test filtering / searching too
156     string_set tags(p2->tags());
157     COMPARE(tags.size(), 4);
158     VERIFY(tags.find("ifr") != tags.end());
159     VERIFY(tags.find("cessna") != tags.end());
160     VERIFY(tags.find("jet") == tags.end());
161
162
163     SGPropertyNode_ptr queryA(new SGPropertyNode);
164     queryA->setStringValue("tag", "ifr");
165     VERIFY(p2->matches(queryA.ptr()));
166
167     SGPropertyNode_ptr queryB(new SGPropertyNode);
168     queryB->setStringValue("name", "ces");
169     VERIFY(p2->matches(queryB.ptr()));
170
171     SGPropertyNode_ptr queryC(new SGPropertyNode);
172     queryC->setStringValue("name", "foo");
173     VERIFY(!p2->matches(queryC.ptr()));
174
175     SGPropertyNode_ptr queryD(new SGPropertyNode);
176     queryD->setIntValue("rating-FDM", 3);
177     VERIFY(p2->matches(queryD.ptr()));
178
179     SGPropertyNode_ptr queryE(new SGPropertyNode);
180     queryE->setIntValue("rating-model", 5);
181     queryE->setStringValue("description", "cessna");
182     VERIFY(p2->matches(queryE.ptr()));
183
184
185     delete root;
186     return EXIT_SUCCESS;
187 }
188
189 void testAddCatalog(HTTP::Client* cl)
190 {
191 // erase dir
192     SGPath rootPath(simgear::Dir::current().path());
193     rootPath.append("pkg_add_catalog");
194     simgear::Dir pd(rootPath);
195     pd.removeChildren();
196
197
198     pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
199     // specify a test dir
200     root->setHTTPClient(cl);
201
202     pkg::CatalogRef c = pkg::Catalog::createFromUrl(root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
203
204     waitForUpdateComplete(cl, root);
205
206 // verify on disk state
207     SGPath p(rootPath);
208     p.append("org.flightgear.test.catalog1");
209     p.append("catalog.xml");
210     VERIFY(p.exists());
211     COMPARE(root->allPackages().size(), 3);
212     COMPARE(root->catalogs().size(), 1);
213
214     pkg::PackageRef p1 = root->getPackageById("alpha");
215     COMPARE(p1->id(), "alpha");
216
217     pkg::PackageRef p2 = root->getPackageById("org.flightgear.test.catalog1.c172p");
218     COMPARE(p2->id(), "c172p");
219     COMPARE(p2->qualifiedId(), "org.flightgear.test.catalog1.c172p");
220
221 }
222
223 void testInstallPackage(HTTP::Client* cl)
224 {
225     SGPath rootPath(simgear::Dir::current().path());
226     rootPath.append("pkg_install_with_dep");
227     simgear::Dir pd(rootPath);
228     pd.removeChildren();
229
230     pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
231     // specify a test dir
232     root->setHTTPClient(cl);
233
234     pkg::CatalogRef c = pkg::Catalog::createFromUrl(root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
235     waitForUpdateComplete(cl, root);
236
237     pkg::PackageRef p1 = root->getPackageById("org.flightgear.test.catalog1.c172p");
238     pkg::InstallRef ins = p1->install();
239
240     VERIFY(ins->isQueued());
241
242     waitForUpdateComplete(cl, root);
243     VERIFY(p1->isInstalled());
244     VERIFY(p1->existingInstall() == ins);
245
246     pkg::PackageRef commonDeps = root->getPackageById("common-sounds");
247     VERIFY(commonDeps->existingInstall());
248
249     // verify on disk state
250     SGPath p(rootPath);
251     p.append("org.flightgear.test.catalog1");
252     p.append("Aircraft");
253     p.append("c172p");
254
255     COMPARE(p, ins->path());
256
257     p.append("c172p-floats-set.xml");
258     VERIFY(p.exists());
259
260     SGPath p2(rootPath);
261     p2.append("org.flightgear.test.catalog1");
262     p2.append("Aircraft");
263     p2.append("sounds");
264     p2.append("sharedfile.txt");
265     VERIFY(p2.exists());
266 }
267
268 void testUninstall(HTTP::Client* cl)
269 {
270     SGPath rootPath(simgear::Dir::current().path());
271     rootPath.append("pkg_uninstall");
272     simgear::Dir pd(rootPath);
273     pd.removeChildren();
274
275     pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
276     root->setHTTPClient(cl);
277
278     pkg::CatalogRef c = pkg::Catalog::createFromUrl(root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
279     waitForUpdateComplete(cl, root);
280
281     pkg::PackageRef p1 = root->getPackageById("org.flightgear.test.catalog1.c172p");
282     pkg::InstallRef ins = p1->install();
283
284     waitForUpdateComplete(cl, root);
285
286     VERIFY(p1->isInstalled());
287
288     ins->uninstall();
289
290     VERIFY(!ins->path().exists());
291 }
292
293 void testRemoveCatalog(HTTP::Client* cl)
294 {
295     SGPath rootPath(simgear::Dir::current().path());
296     rootPath.append("pkg_catalog_remove");
297     simgear::Dir pd(rootPath);
298     pd.removeChildren();
299
300     pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
301     root->setHTTPClient(cl);
302
303     {
304         pkg::CatalogRef c = pkg::Catalog::createFromUrl(root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
305         waitForUpdateComplete(cl, root);
306     }
307
308     {
309         pkg::PackageRef p1 = root->getPackageById("org.flightgear.test.catalog1.c172p");
310         pkg::InstallRef ins = p1->install();
311
312         waitForUpdateComplete(cl, root);
313
314         VERIFY(p1->isInstalled());
315     }
316
317     root->removeCatalogById("org.flightgear.test.catalog1");
318
319
320     SGPath p2(rootPath);
321     p2.append("org.flightgear.test.catalog1");
322     VERIFY(!p2.exists());
323
324     VERIFY(root->allPackages().empty());
325     VERIFY(root->catalogs().empty());
326
327     pkg::CatalogRef c = root->getCatalogById("org.flightgear.test.catalog1");
328     COMPARE(c, pkg::CatalogRef());
329 }
330
331 template <class T>
332 bool contains(const std::vector<T>& vec, const T& item)
333 {
334     typename std::vector<T>::const_iterator it = std::find(vec.begin(), vec.end(), item);
335     return (it != vec.end());
336 }
337
338 void testRefreshCatalog(HTTP::Client* cl)
339 {
340     SGPath rootPath(simgear::Dir::current().path());
341     rootPath.append("pkg_catalog_refresh_update");
342     simgear::Dir pd(rootPath);
343     pd.removeChildren();
344
345     pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
346     root->setHTTPClient(cl);
347
348     {
349         pkg::CatalogRef c = pkg::Catalog::createFromUrl(root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
350         waitForUpdateComplete(cl, root);
351     }
352
353     {
354         pkg::PackageRef p1 = root->getPackageById("org.flightgear.test.catalog1.c172p");
355         pkg::InstallRef ins = p1->install();
356
357         pkg::PackageRef p2 = root->getPackageById("org.flightgear.test.catalog1.alpha");
358         pkg::InstallRef ins2 = p2->install();
359
360         waitForUpdateComplete(cl, root);
361
362         VERIFY(p1->isInstalled());
363         VERIFY(p2->isInstalled());
364     }
365
366     VERIFY(root->packagesNeedingUpdate().empty());
367
368     global_catalogVersion = 2;
369
370     VERIFY(!cl->hasActiveRequests());
371     root->refresh();
372
373     // should be a no-op due to catalog age testing
374     VERIFY(!cl->hasActiveRequests());
375
376     // force it this time
377     root->refresh(true);
378     VERIFY(cl->hasActiveRequests());
379     waitForUpdateComplete(cl, root);
380
381     pkg::CatalogRef c = root->getCatalogById("org.flightgear.test.catalog1");
382     COMPARE(c->ageInSeconds(), 0);
383
384     VERIFY(root->getPackageById("dc3") != pkg::PackageRef());
385     COMPARE(root->packagesNeedingUpdate().size(), 2);
386
387     pkg::PackageList needingUpdate = root->packagesNeedingUpdate();
388     VERIFY(contains(needingUpdate, root->getPackageById("common-sounds")));
389     VERIFY(contains(needingUpdate, root->getPackageById("org.flightgear.test.catalog1.alpha")));
390
391     pkg::InstallRef ins = root->getPackageById("alpha")->existingInstall();
392     VERIFY(ins->hasUpdate());
393
394     for (pkg::PackageList::const_iterator it = needingUpdate.begin();
395          it != needingUpdate.end(); ++it)
396     {
397         root->scheduleToUpdate((*it)->existingInstall());
398     }
399
400     waitForUpdateComplete(cl, root);
401
402     VERIFY(root->packagesNeedingUpdate().empty());
403     COMPARE(root->getPackageById("common-sounds")->revision(), 11);
404 }
405
406
407 int main(int argc, char* argv[])
408 {
409     sglog().setLogLevels( SG_ALL, SG_DEBUG );
410
411     HTTP::Client cl;
412     cl.setMaxConnections(1);
413
414     global_serverFilesRoot = SGPath(SRC_DIR);
415
416     testAddCatalog(&cl);
417
418     parseTest();
419
420     testInstallPackage(&cl);
421     
422     testUninstall(&cl);
423
424     testRemoveCatalog(&cl);
425
426     testRefreshCatalog(&cl);
427
428     std::cout << "Successfully passed all tests!" << std::endl;
429     return EXIT_SUCCESS;
430 }