diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2017-11-02 16:10:38 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2017-11-10 10:01:20 +0000 |
commit | 4ede42b26d871b1571c0aba6c2b3cc54249356f5 (patch) | |
tree | c6c70038b945da681c8c533bb3c5943a0c3fd42e /tests | |
parent | 2530d46c5a8a9dfba6e02b48a376545cdaf7a361 (diff) |
Better change tracking for imported JS files
We did both too much and too little: Firstly, we invalidated all rules
that appeared in a file that imported a changed JS file, independent of
whether that import was relevant to the rule. Secondly, we did not catch
changes to recursively imported files at all.
Now we track accesses to functions in imports and invalidate a rule or
command only if a file to which such an access refers has been modified.
More fine-grained checks (e.g. per function) would be possible, but
incur more overhead, as we'd have to store the respective source code in
the build graph.
Change-Id: I95f62d233bf87d2c39abbe37056a8fe434f20b5a
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Diffstat (limited to 'tests')
14 files changed, 154 insertions, 0 deletions
diff --git a/tests/auto/blackbox/testdata/import-change-tracking/custom1command.js b/tests/auto/blackbox/testdata/import-change-tracking/custom1command.js new file mode 100644 index 000000000..1f21beb8d --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/custom1command.js @@ -0,0 +1,3 @@ +var Irrelevant = require("./irrelevant.js"); + +function sourceCode() { } diff --git a/tests/auto/blackbox/testdata/import-change-tracking/custom1prepare1.js b/tests/auto/blackbox/testdata/import-change-tracking/custom1prepare1.js new file mode 100644 index 000000000..5df9b3873 --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/custom1prepare1.js @@ -0,0 +1,4 @@ +var CustomPrepare = require("./custom1prepare2.js"); +var Irrelevant = require("./irrelevant.js"); + +function prepare() { return CustomPrepare.prepare(); } diff --git a/tests/auto/blackbox/testdata/import-change-tracking/custom1prepare2.js b/tests/auto/blackbox/testdata/import-change-tracking/custom1prepare2.js new file mode 100644 index 000000000..79be59bf9 --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/custom1prepare2.js @@ -0,0 +1,10 @@ +var Custom1Command = require("./custom1command.js"); +var Irrelevant = require("./irrelevant.js"); + +function prepare() { + console.info("running custom1 prepare script"); + var cmd = new JavaScriptCommand(); + cmd.description = "running custom1 command"; + cmd.sourceCode = function() { return Custom1Command.sourceCode(); }; + return cmd; +} diff --git a/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/custom2prepare1.js b/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/custom2prepare1.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/custom2prepare1.js diff --git a/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/custom2prepare2.js b/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/custom2prepare2.js new file mode 100644 index 000000000..5bd6852d8 --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/custom2prepare2.js @@ -0,0 +1,9 @@ +var Custom2Command = require("custom2command"); + +function prepare() { + console.info("running custom2 prepare script"); + var cmd = new JavaScriptCommand(); + cmd.description = "running custom2 command"; + cmd.sourceCode = function() { return Custom2Command.sourceCode(); }; + return cmd; +} diff --git a/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs b/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs new file mode 100644 index 000000000..f7e9bc5de --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs @@ -0,0 +1,37 @@ +import qbs +import "irrelevant.js" as Irrelevant +import "custom1prepare1.js" as Custom1Prepare +import "custom2prepare" as Custom2Prepare + +Product { + name: "customProduct" + type: ["custom1", "custom2"] + + property string irrelevant: Irrelevant.irrelevant() + + Group { + files: "input1.txt" + fileTags: "input.custom1" + } + + Group { + files: "input2.txt" + fileTags: "input.custom2" + } + + Rule { + inputs: "input.custom1" + Artifact { filePath: "dummy.custom1"; fileTags: "custom1" } + prepare: { + return Custom1Prepare.prepare(); + } + } + + Rule { + inputs: "input.custom2" + Artifact { filePath: "dummy.custom2"; fileTags: "custom2" } + prepare: { + return Custom2Prepare.prepare(); + } + } +} diff --git a/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking.qbs b/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking.qbs new file mode 100644 index 000000000..009c0897f --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking.qbs @@ -0,0 +1,6 @@ +import qbs + +Project { + qbsSearchPaths: ["."] + references: "import-change-tracking-product.qbs" +} diff --git a/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2command1.js b/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2command1.js new file mode 100644 index 000000000..c008738be --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2command1.js @@ -0,0 +1 @@ +var Irrelevant = require("../../irrelevant.js"); diff --git a/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2command2.js b/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2command2.js new file mode 100644 index 000000000..98829a922 --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2command2.js @@ -0,0 +1,3 @@ +var Irrelevant = require("../../irrelevant.js"); + +function sourceCode() { } diff --git a/tests/auto/blackbox/testdata/import-change-tracking/input1.txt b/tests/auto/blackbox/testdata/import-change-tracking/input1.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/input1.txt diff --git a/tests/auto/blackbox/testdata/import-change-tracking/input2.txt b/tests/auto/blackbox/testdata/import-change-tracking/input2.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/input2.txt diff --git a/tests/auto/blackbox/testdata/import-change-tracking/irrelevant.js b/tests/auto/blackbox/testdata/import-change-tracking/irrelevant.js new file mode 100644 index 000000000..ebd6750a8 --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/irrelevant.js @@ -0,0 +1 @@ +function irrelevant() { return "irrelevant"; } diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index d4e4c81ca..0567ed433 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -5277,6 +5277,85 @@ void TestBlackbox::groupsInModules() QCOMPARE(output.readAll().trimmed(), QByteArray("diamond")); } +void TestBlackbox::importChangeTracking() +{ + QDir::setCurrent(testDataDir + "/import-change-tracking"); + QCOMPARE(runQbs(QStringList({"-f", "import-change-tracking.qbs"})), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + + // Change in imported file that is not used in any rule or command. + WAIT_FOR_NEW_TIMESTAMP(); + touch("irrelevant.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + + // Change in directly imported file only used by one prepare script. + WAIT_FOR_NEW_TIMESTAMP(); + touch("custom1prepare1.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + + // Change in recursively imported file only used by one prepare script. + WAIT_FOR_NEW_TIMESTAMP(); + touch("custom1prepare2.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + + // Change in imported file used only by one command. + WAIT_FOR_NEW_TIMESTAMP(); + touch("custom1command.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + + // Change in file only used by one prepare script, using directory import. + WAIT_FOR_NEW_TIMESTAMP(); + touch("custom2prepare/custom2prepare2.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + + // Change in file used only by one command, imported via search path. + WAIT_FOR_NEW_TIMESTAMP(); + touch("imports/custom2command/custom2command1.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + + // Change everything at once. + WAIT_FOR_NEW_TIMESTAMP(); + touch("irrelevant.js"); + touch("custom1prepare1.js"); + touch("custom1prepare2.js"); + touch("custom1command.js"); + touch("custom2prepare/custom2prepare1.js"); + touch("imports/custom2command/custom2command2.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); +} + void TestBlackbox::probesInNestedModules() { QDir::setCurrent(testDataDir + "/probes-in-nested-modules"); diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index 05b8d4838..2fd561742 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -96,6 +96,7 @@ private slots: void fileDependencies(); void generatedArtifactAsInputToDynamicRule(); void groupsInModules(); + void importChangeTracking(); void importInPropertiesCondition(); void importingProduct(); void importsConflict(); |