mirror of
https://github.com/fwbuilder/fwbuilder
synced 2026-03-23 19:57:21 +01:00
when user opens the firewall or any of its children objects in the editor. This includes any rule set, interface or any other child object. Also moved function Interface::getParentHost() from class Interface to class Host as static FWObject* Host::getParentHost(FWObject *o). Its behavior is now more logical, it returns non-NULL pointer only if an object actually has a parent that is host, firewall or cluster. Old function Interface::getParentHost() returned non-NULL pointer even when object was not in the proper position in the tree. Now this function can be used to get parent host/firewall/cluster for any child object rather than only interface. I had to fix bunch of problems in unit tests that got uncovered because new function behaves in a more strict way (returns NULL when there is no parent of correct type).
370 lines
14 KiB
C++
370 lines
14 KiB
C++
/*
|
|
|
|
Firewall Builder
|
|
|
|
Copyright (C) 2010 NetCitadel, LLC
|
|
|
|
Author: Roman Bovsunivskiy a2k0001@gmail.com
|
|
|
|
$Id: genericDialogTest.cpp 2723 2010-03-16 17:32:18Z a2k $
|
|
|
|
This program is free software which we release under the GNU General Public
|
|
License. You may redistribute and/or modify this program under the terms
|
|
of that license as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
To get a copy of the GNU General Public License, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
#include "genericDialogTest.h"
|
|
|
|
#include "../../../../config.h"
|
|
//#include "../../global.h"
|
|
|
|
#include <qapplication.h>
|
|
#include <qfile.h>
|
|
#include <qtextstream.h>
|
|
#include <QTest>
|
|
#include <iostream>
|
|
|
|
#include <QProcess>
|
|
#include <QRegExp>
|
|
#include <QDebug>
|
|
|
|
#include <QToolButton>
|
|
#include <QRadioButton>
|
|
#include <QMessageBox>
|
|
#include <QWidget>
|
|
#include <QLineEdit>
|
|
#include <QUndoStack>
|
|
#include "FWWindow.h"
|
|
#include "ProjectPanel.h"
|
|
#include "ObjectTreeView.h"
|
|
#include "ObjectTreeViewItem.h"
|
|
#include "ObjectEditor.h"
|
|
#include "FWObjectClipboard.h"
|
|
#include "TextEditWidget.h"
|
|
#include "fwbuilder/Address.h"
|
|
#include "fwbuilder/IPv4.h"
|
|
#include "fwbuilder/IPv6.h"
|
|
#include "FWBTree.h"
|
|
#include "fwbuilder/Library.h"
|
|
#include "fwbuilder/FWObjectDatabase.h"
|
|
#include "FirewallDialog.h"
|
|
#include "StartTipDialog.h"
|
|
#include "fwbuilder/FWObjectDatabase.h"
|
|
#include "fwbuilder/Interface.h"
|
|
#include "genericDialogTest.h"
|
|
#include "fwbuilder/IPService.h"
|
|
#include "DialogFactory.h"
|
|
#include "FWCmdChange.h"
|
|
#include "RuleOptionsDialog.h"
|
|
#include "fwbuilder/Rule.h"
|
|
#include "fwbuilder/Policy.h"
|
|
#include "fwbuilder/Routing.h"
|
|
#include "fwbuilder/NAT.h"
|
|
#include "RoutingRuleOptionsDialog.h"
|
|
#include "platforms.h"
|
|
#include "NATRuleOptionsDialog.h"
|
|
#include "UserWorkflow.h"
|
|
|
|
using namespace std;
|
|
using namespace libfwbuilder;
|
|
|
|
void genericDialogTest::initTestCase()
|
|
{
|
|
new FWObjectClipboard();
|
|
mw = new FWWindow();
|
|
wfl = new UserWorkflow();
|
|
mw->show();
|
|
mw->startupLoad();
|
|
mw->resize(1200, 600);
|
|
StartTipDialog *d = mw->findChild<StartTipDialog*>();
|
|
if (d!=NULL) d->close();
|
|
om = dynamic_cast<ObjectManipulator*>(mw->getCurrentObjectTree()->parent()->parent());
|
|
init_platforms();
|
|
QTest::qWait(1000);
|
|
}
|
|
|
|
QList<QWidget*> genericDialogTest::scanDialog(QWidget *dialog)
|
|
{
|
|
QList<QWidget*> result;
|
|
foreach(QLineEdit *item, dialog->findChildren<QLineEdit*>())
|
|
result.append(dynamic_cast<QWidget*>(item));
|
|
foreach(QCheckBox *item, dialog->findChildren<QCheckBox*>())
|
|
result.append(dynamic_cast<QWidget*>(item));
|
|
foreach(QComboBox *item, dialog->findChildren<QComboBox*>())
|
|
result.append(dynamic_cast<QWidget*>(item));
|
|
foreach(QRadioButton *item, dialog->findChildren<QRadioButton*>())
|
|
result.append(dynamic_cast<QWidget*>(item));
|
|
foreach(QTextEdit *item, dialog->findChildren<QTextEdit*>())
|
|
result.append(dynamic_cast<QWidget*>(item));
|
|
foreach(TextEditWidget *item, dialog->findChildren<TextEditWidget*>())
|
|
result.append(dynamic_cast<QWidget*>(item));
|
|
foreach(QSpinBox *item, dialog->findChildren<QSpinBox*>())
|
|
result.append(dynamic_cast<QWidget*>(item));
|
|
return result;
|
|
}
|
|
|
|
// Activates tab which contains widget
|
|
void genericDialogTest::activateTab(QWidget *widget)
|
|
{
|
|
QWidget *current = widget;
|
|
while (current->parent() != NULL)
|
|
{
|
|
if (dynamic_cast<QTabWidget*>(current->parent()) != NULL)
|
|
{
|
|
QTabWidget *tabs = dynamic_cast<QTabWidget*>(current->parent());
|
|
for (int i=0; i<tabs->count(); i++)
|
|
{
|
|
if (tabs->widget(i)->findChildren<QWidget*>(widget->objectName()).contains(widget))
|
|
{
|
|
tabs->setCurrentIndex(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
current = dynamic_cast<QWidget*>(current->parent());
|
|
}
|
|
|
|
}
|
|
|
|
bool genericDialogTest::testControl(QWidget *control)
|
|
{
|
|
if (dynamic_cast<QSpinBox*>(control) != NULL)
|
|
{
|
|
QSpinBox *box = dynamic_cast<QSpinBox*>(control);
|
|
QTest::keyClick(box, Qt::Key_Up);
|
|
QTest::keyClick(box, Qt::Key_Up);
|
|
QTest::keyClick(box, Qt::Key_Enter);
|
|
QTest::keyClick(box, Qt::Key_Tab);
|
|
}
|
|
else if (dynamic_cast<QLineEdit*>(control) != NULL)
|
|
{
|
|
QLineEdit *line = dynamic_cast<QLineEdit*>(control);
|
|
line->clear();
|
|
QTest::keyClicks(line, QString("Some text for %1").arg(line->objectName()));
|
|
//line->setText(QString("Some text for %1").arg(control->objectName()));
|
|
QTest::keyClick(line, Qt::Key_Enter);
|
|
}
|
|
else if (dynamic_cast<QCheckBox*>(control) != NULL)
|
|
{
|
|
QCheckBox *box = dynamic_cast<QCheckBox*>(control);
|
|
QTest::mouseClick(box, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
|
|
}
|
|
else if (dynamic_cast<QRadioButton*>(control) != NULL)
|
|
{
|
|
QRadioButton *box = dynamic_cast<QRadioButton*>(control);
|
|
// if it is not checked, jut clicking it
|
|
if (!box->isChecked())
|
|
QTest::mouseClick(box, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
|
|
else
|
|
{
|
|
QList<QAbstractButton*> buttons;
|
|
if (box->group() == NULL)
|
|
{
|
|
foreach(QRadioButton *button, box->parent()->findChildren<QRadioButton*>())
|
|
{
|
|
if (button->group() == NULL)
|
|
buttons.append(button);
|
|
}
|
|
|
|
if (buttons.isEmpty())
|
|
{
|
|
qDebug() << "Can not test QRadioButton" << box << "that is not in group and has no buttons nearby.";
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
buttons = box->group()->buttons();
|
|
}
|
|
if (buttons.count() < 2)
|
|
{
|
|
qDebug() << "Can not test QRadioButton" << box << " that is only one button in group.";
|
|
return false;
|
|
}
|
|
// looking for first radio button in same group that is not checked and clicking it
|
|
foreach(QAbstractButton *button, buttons)
|
|
{
|
|
if (button->isChecked() == false && button != box)
|
|
{
|
|
QTest::mouseClick(button, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (dynamic_cast<QComboBox*>(control) != NULL)
|
|
{
|
|
QComboBox *box = dynamic_cast<QComboBox*>(control);
|
|
if (box->count() < 2)
|
|
{
|
|
for (int i=0; i<box->count(); i++)
|
|
qDebug() << box->itemText(i);
|
|
qDebug() << "Can not change value of QComboBox" << box << "which has less than two items.";
|
|
return false;
|
|
}
|
|
box->setCurrentIndex((box->currentIndex() + 1) % box->count());
|
|
}
|
|
else if (dynamic_cast<QTextEdit*>(control) != NULL)
|
|
{
|
|
QTextEdit *edit = dynamic_cast<QTextEdit*>(control);
|
|
QTest::mouseClick(edit, Qt::LeftButton, Qt::NoModifier);
|
|
QTest::keyClicks(edit, "Some test input for " + edit->objectName());
|
|
QTest::mouseClick(edit, Qt::LeftButton, Qt::NoModifier);
|
|
QTest::keyClick(edit, Qt::Key_Tab);
|
|
}
|
|
else return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void genericDialogTest::testDialog(QWidget *dialog, FWObject *object)
|
|
{
|
|
qDebug() << "testing dialog" << dialog;
|
|
QList<QWidget*> widgets = scanDialog(dialog);
|
|
qDebug() << "it contains" << widgets.size() << "controls";
|
|
QList<QTabWidget*> tabs = dialog->findChildren<QTabWidget*>();
|
|
FWObject *old = mw->db()->create(object->getTypeName());
|
|
for (int i=0; i<widgets.size(); i++)
|
|
{
|
|
//qDebug() << "testing control" << widgets.at(i);
|
|
old->duplicate(object);
|
|
QWidget *widget = widgets.at(i);
|
|
|
|
// Skipping QSpinBox (which inherits QLineEdit) with QLineEdit type
|
|
// there should be another one with right type in list
|
|
if (widget->objectName() == "qt_spinbox_lineedit") continue;
|
|
|
|
if (dynamic_cast<QDialog*>(dialog) != NULL)
|
|
dynamic_cast<QDialog*>(dialog)->open();
|
|
|
|
activateTab(widget);
|
|
if (!widget->isVisible() || !widget->isEnabled()) continue;
|
|
|
|
if (!testControl(widget))
|
|
{
|
|
QWARN(QString("Dont know how to test widget %1. It might be unknown class, empty QComboBox or QRadioButton with not other QRadio button in group.")
|
|
.arg(widgets.at(i)->objectName()).toAscii().data());
|
|
continue;
|
|
}
|
|
if (dynamic_cast<QDialog*>(dialog) != NULL)
|
|
dynamic_cast<QDialog*>(dialog)->accept();
|
|
else
|
|
{
|
|
QMetaObject::invokeMethod(dialog, "changed");
|
|
QMetaObject::invokeMethod(dialog, "applyChanges");
|
|
}
|
|
QVERIFY2(!old->cmp(object, true),
|
|
QString("Widget %1 does not affect object").arg(widget->objectName()).toAscii().data());
|
|
}
|
|
}
|
|
|
|
void genericDialogTest::testFirewallSettingsDialog_iptables()
|
|
{
|
|
Firewall *firewall = Firewall::cast(om->createObject(FWBTree().getStandardSlotForObject(findUserLibrary(), Firewall::TYPENAME), Firewall::TYPENAME, "TestFirewall"));
|
|
firewall->setStr("platform", "iptables");
|
|
firewall->setStr("host_OS", "linux24");
|
|
|
|
QDialog *dialog = dynamic_cast<QDialog*>(DialogFactory::createFWDialog(mw, firewall));
|
|
testDialog(dialog, firewall);
|
|
}
|
|
|
|
void genericDialogTest::testHostOSSettingsDialog_linux24()
|
|
{
|
|
Firewall *firewall = Firewall::cast(om->createObject(FWBTree().getStandardSlotForObject(findUserLibrary(), Firewall::TYPENAME), Firewall::TYPENAME, "TestFirewall"));
|
|
firewall->setStr("platform", "iptables");
|
|
firewall->setStr("host_OS", "linux24");
|
|
|
|
QDialog *dialog = dynamic_cast<QDialog*>(DialogFactory::createOSDialog(mw, firewall));
|
|
testDialog(dialog, firewall);
|
|
}
|
|
|
|
#if 0
|
|
// rule options dialog uses stacked widget with only one page visible,
|
|
// depending on the firewall platform. Some widgets in invisible pages
|
|
// are not even initialized, also depending on the platform. Need to
|
|
// devise better test that would take this into account.
|
|
|
|
void genericDialogTest::testRuleOptionsDialog()
|
|
{
|
|
Firewall *firewall = Firewall::cast(om->createObject(FWBTree().getStandardSlotForObject(findUserLibrary(), Firewall::TYPENAME), Firewall::TYPENAME, "TestFirewall"));
|
|
QMap<QString, QString> platforms = getAllPlatforms();
|
|
platforms.remove("unknown"); // dialog does not set options for it
|
|
foreach(QString platform, platforms.keys())
|
|
{
|
|
qDebug() << "Testing platform:" << platform;
|
|
firewall->setStr("platform", platform.toStdString());
|
|
PolicyRule *rule = PolicyRule::cast(firewall->getPolicy()->createRule());
|
|
firewall->getPolicy()->add(rule);
|
|
QWidget *dialog = dynamic_cast<QWidget*>(DialogFactory::createDialog(mw->activeProject(), Rule::TYPENAME));
|
|
dynamic_cast<BaseObjectDialog*>(dialog)->attachToProjectWindow(mw->activeProject());
|
|
dialog->setVisible(true);
|
|
dynamic_cast<RuleOptionsDialog*>(dialog)->loadFWObject(rule);
|
|
testDialog(dynamic_cast<QWidget*>(dialog), FWObject::cast(rule));
|
|
}
|
|
}
|
|
|
|
void genericDialogTest::testRoutingRuleOptionsDialog()
|
|
{
|
|
Firewall *firewall = Firewall::cast(om->createObject(FWBTree().getStandardSlotForObject(findUserLibrary(), Firewall::TYPENAME), Firewall::TYPENAME, "TestFirewall"));
|
|
/* QMap<QString, QString> platforms = getAllPlatforms();
|
|
platforms.remove("unknown"); // dialog does not set options for it
|
|
foreach(QString platform, platforms.keys())
|
|
{
|
|
firewall->setStr("platform", platform.toStdString());
|
|
*/
|
|
// it currently works only with iptables
|
|
firewall->setStr("platform", "iptables");
|
|
RoutingRule *rule = RoutingRule::cast(firewall->getRouting()->createRule());
|
|
firewall->getRouting()->add(rule);
|
|
QWidget *dialog = dynamic_cast<QWidget*>(DialogFactory::createDialog(mw->activeProject(), RoutingRule::TYPENAME));
|
|
dynamic_cast<BaseObjectDialog*>(dialog)->attachToProjectWindow(mw->activeProject());
|
|
dialog->setVisible(true);
|
|
dynamic_cast<RoutingRuleOptionsDialog*>(dialog)->loadFWObject(rule);
|
|
testDialog(dynamic_cast<QWidget*>(dialog), FWObject::cast(rule));
|
|
}
|
|
|
|
void genericDialogTest::testNATRuleOptionsDialog()
|
|
{
|
|
Firewall *firewall = Firewall::cast(om->createObject(FWBTree().getStandardSlotForObject(findUserLibrary(), Firewall::TYPENAME), Firewall::TYPENAME, "TestFirewall"));
|
|
QMap<QString, QString> platforms = getAllPlatforms();
|
|
platforms.remove("unknown"); // dialog does not set options for it
|
|
foreach(QString platform, platforms.keys())
|
|
{
|
|
qDebug() << "Testing platform:" << platform;
|
|
firewall->setStr("platform", platform.toStdString());
|
|
NATRule *rule = NATRule::cast(firewall->getNAT()->createRule());
|
|
firewall->getNAT()->add(rule);
|
|
QWidget *dialog = dynamic_cast<QWidget*>(DialogFactory::createDialog(mw->activeProject(), NATRule::TYPENAME));
|
|
dynamic_cast<BaseObjectDialog*>(dialog)->attachToProjectWindow(mw->activeProject());
|
|
dialog->setVisible(true);
|
|
dynamic_cast<NATRuleOptionsDialog*>(dialog)->loadFWObject(rule);
|
|
testDialog(dynamic_cast<QWidget*>(dialog), FWObject::cast(rule));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
Library* genericDialogTest::findUserLibrary()
|
|
{
|
|
Library *lib = NULL;
|
|
foreach (FWObject *obj, mw->db()->getByType(Library::TYPENAME))
|
|
{
|
|
if (obj->getName() == "User")
|
|
{
|
|
lib = Library::cast(obj);
|
|
break;
|
|
}
|
|
}
|
|
return lib;
|
|
}
|