• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2021 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""ChangeSummary tests."""
16
17__author__ = "partheniou@google.com (Anthonios Partheniou)"
18
19import pathlib
20import shutil
21import unittest
22
23import pandas as pd
24
25from changesummary import ChangeSummary
26from changesummary import ChangeType
27from changesummary import DirectoryDoesNotExist
28
29SCRIPTS_DIR = pathlib.Path(__file__).parent.resolve()
30NEW_ARTIFACTS_DIR = SCRIPTS_DIR / "test_resources" / "new_artifacts_dir"
31CURRENT_ARTIFACTS_DIR = SCRIPTS_DIR / "test_resources" / "current_artifacts_dir"
32TEMP_DIR = SCRIPTS_DIR / "test_resources" / "temp"
33
34
35class TestChangeSummary(unittest.TestCase):
36    def setUp(self):
37        # Clear temporary directory
38        shutil.rmtree(TEMP_DIR, ignore_errors=True)
39        # Create temporary directory
40        pathlib.Path(TEMP_DIR).mkdir()
41
42        self.cs = ChangeSummary(NEW_ARTIFACTS_DIR, CURRENT_ARTIFACTS_DIR, TEMP_DIR, [])
43
44    def test_raises_on_directory_not_found_new_artifacts_dir(self):
45        with self.assertRaises(DirectoryDoesNotExist):
46            ChangeSummary(
47                "invalid_artifact_dir", CURRENT_ARTIFACTS_DIR, TEMP_DIR, []
48            ).detect_discovery_changes()
49
50    def test_raises_on_directory_not_found_current_artifacts_dir(self):
51        with self.assertRaises(DirectoryDoesNotExist):
52            ChangeSummary(
53                NEW_ARTIFACTS_DIR, "invalid_artifact_dir", TEMP_DIR, []
54            ).detect_discovery_changes()
55
56    def test_raises_on_directory_not_found_temp_dir(self):
57        # Remove temporary directory
58        shutil.rmtree(TEMP_DIR, ignore_errors=True)
59
60        with self.assertRaises(DirectoryDoesNotExist):
61            ChangeSummary(
62                NEW_ARTIFACTS_DIR, CURRENT_ARTIFACTS_DIR, "invalid_temp_dir", []
63            ).detect_discovery_changes()
64
65        # Create temporary directory
66        pathlib.Path(TEMP_DIR).mkdir()
67
68        ChangeSummary(
69            NEW_ARTIFACTS_DIR, CURRENT_ARTIFACTS_DIR, TEMP_DIR, []
70        ).detect_discovery_changes()
71
72    def test_raises_on_directory_not_found(self):
73        with self.assertRaises(DirectoryDoesNotExist):
74            self.cs._raise_if_directory_not_found(directory="invalid_dir")
75
76    def test_load_json_to_dataframe_returns_empty_df_if_file_path_invalid(self):
77        df = self.cs._load_json_to_dataframe(file_path="invalid_path")
78        self.assertTrue(df.empty)
79
80    def test_load_json_to_dataframe_returns_expected_data(self):
81        doc_path = NEW_ARTIFACTS_DIR / "drive.v3.json"
82        df = self.cs._load_json_to_dataframe(file_path=doc_path)
83        self.assertEqual(df["name"].iloc[0], "drive")
84        self.assertEqual(df["version"].iloc[0], "v3")
85
86    def test_get_discovery_differences_for_new_doc_returns_expected_dataframe(self):
87        df = self.cs._get_discovery_differences("drive.v3.json")
88        # Assume that `drive.v3.json` is a new discovery artifact that doesn't
89        # exist in `CURRENT_ARTIFACTS_DIR`.
90        self.assertEqual(df["Name"].iloc[0], "drive")
91        self.assertEqual(df["Version"].iloc[0], "v3")
92
93        # All rows in the dataframe should  have `True` in the `Added` column
94        # and `False` in the `Deleted` column.
95        # pd.Dataframe().all() will return `True` if all elements are `True`.
96        self.assertTrue(df["Added"].all())
97        self.assertTrue((~df["Deleted"]).all())
98
99        # There should be 4 unique key differences
100        self.assertEqual(len(df), 4)
101
102        # Expected Result for key 'schemas.FileList'
103        # Key            Added   Deleted  Name   Version  ChangeType  Count
104        # schemas.FileList   True    False  drive      v3           2      8
105        self.assertTrue(df[df["Key"] == "schemas.FileList"].Added.iloc[0])
106        self.assertFalse(df[df["Key"] == "schemas.FileList"].Deleted.iloc[0])
107        self.assertEqual(
108            df[df["Key"] == "schemas.FileList"].ChangeType.iloc[0], ChangeType.ADDED
109        )
110        self.assertEqual(df[df["Key"] == "schemas.FileList"].Count.iloc[0], 8)
111
112    def test_get_discovery_differences_for_deleted_doc_returns_expected_dataframe(self):
113        df = self.cs._get_discovery_differences("cloudtasks.v2.json")
114        # Assuming that `cloudtasks.v2.json` is a discovery artifact that doesn't
115        # exist in `NEW_ARTIFACTS_DIR`.
116        self.assertEqual(df["Name"].iloc[0], "cloudtasks")
117        self.assertEqual(df["Version"].iloc[0], "v2")
118
119        # All rows in the dataframe should have `False` in the `Added` column
120        # and `True` in the `Deleted` column.
121        # pd.Dataframe().all() will return `True` if all elements are `True`.
122        self.assertTrue((~df["Added"]).all())
123        self.assertTrue(df["Deleted"].all())
124
125        # There should be 6 unique key differences
126        self.assertEqual(len(df), 6)
127
128        # Expected Result for key 'schemas.Task'
129        # Key           Added   Deleted Name        Version  ChangeType  Count
130        # schemas.Task  False     True  cloudtasks      v2           1     18
131        self.assertFalse(df[df["Key"] == "schemas.Task"].Added.iloc[0])
132        self.assertTrue(df[df["Key"] == "schemas.Task"].Deleted.iloc[0])
133        self.assertEqual(
134            df[df["Key"] == "schemas.Task"].ChangeType.iloc[0], ChangeType.DELETED
135        )
136        self.assertEqual(df[df["Key"] == "schemas.Task"].Count.iloc[0], 18)
137
138    def test_get_discovery_differences_for_changed_doc_returns_expected_dataframe(self):
139        # Assuming that `bigquery.v2.json` is a discovery artifact has
140        # changed. There will be a mix of keys being added, changed or deleted.
141        df = self.cs._get_discovery_differences("bigquery.v2.json")
142
143        self.assertEqual(df["Name"].iloc[0], "bigquery")
144        self.assertEqual(df["Version"].iloc[0], "v2")
145
146        # There should be 28 unique key differences
147        # 1 unique keys changed, 1 unique keys added, 2 unique keys deleted
148        self.assertEqual(len(df), 4)
149        self.assertEqual(len(df[df["ChangeType"] == ChangeType.CHANGED]), 1)
150        self.assertEqual(len(df[df["ChangeType"] == ChangeType.ADDED]), 1)
151        self.assertEqual(len(df[df["ChangeType"] == ChangeType.DELETED]), 2)
152
153        # Expected Result for key 'schemas.PrincipalComponentInfo'
154        # Key                             Added  Deleted  Name     Version  ChangeType  Count
155        # schemas.PrincipalComponentInfo  False     True  bigquery v2            1     10
156        key = "schemas.PrincipalComponentInfo"
157        self.assertFalse(df[df["Key"] == key].Added.iloc[0])
158        self.assertTrue(df[df["Key"] == key].Deleted.iloc[0])
159        self.assertEqual(df[df["Key"] == key].ChangeType.iloc[0], ChangeType.DELETED)
160        self.assertEqual(df[df["Key"] == key].Count.iloc[0], 10)
161
162    def test_build_summary_message_returns_expected_result(self):
163        msg = self.cs._build_summary_message(api_name="bigquery", is_feature=True)
164        self.assertEqual(msg, "feat(bigquery): update the api")
165        msg = self.cs._build_summary_message(api_name="bigquery", is_feature=False)
166        self.assertEqual(msg, "fix(bigquery): update the api")
167
168    def test_get_stable_versions(self):
169        # These versions should be considered stable
170        s = pd.Series(["v1", "v1.4", "v1.4.5"])
171        self.assertTrue(self.cs._get_stable_versions(s).all().iloc[0])
172
173        # These versions should not be considered stable
174        s = pd.Series(["v1b1", "v1alpha", "v1beta1"])
175        self.assertTrue((~self.cs._get_stable_versions(s)).all().iloc[0])
176
177    def test_detect_discovery_changes(self):
178        files_changed = ["bigquery.v2.json", "cloudtasks.v2.json", "drive.v3.json"]
179        cs = ChangeSummary(
180            NEW_ARTIFACTS_DIR, CURRENT_ARTIFACTS_DIR, TEMP_DIR, files_changed
181        )
182        cs.detect_discovery_changes()
183        result = pd.read_csv(TEMP_DIR / "allapis.dataframe")
184
185        # bigquery was added
186        # 4 key changes in total.
187        # 1 unique keys changed, 1 unique keys added, 2 unique keys deleted
188        self.assertEqual(len(result[result["Name"] == "bigquery"]), 4)
189        self.assertEqual(
190            len(result[(result["Name"] == "bigquery") & result["Added"]]), 1
191        )
192
193        # Confirm that key "schemas.ProjectReference.newkey" exists for bigquery
194        self.assertEqual(
195            result[
196                (result["Name"] == "bigquery") & (result["Added"]) & (result["Count"] == 1)
197            ]["Key"].iloc[0],
198            "schemas.ProjectReference.newkey",
199        )
200
201        self.assertEqual(
202            len(result[(result["Name"] == "bigquery") & result["Deleted"]]), 2
203        )
204        self.assertTrue(result[result["Name"] == "bigquery"].IsStable.all())
205        self.assertTrue(result[result["Name"] == "bigquery"].IsFeatureAggregate.all())
206        self.assertEqual(
207            result[result["Name"] == "bigquery"].Summary.iloc[0],
208            "feat(bigquery): update the api",
209        )
210
211        # cloudtasks was deleted
212        # 6 key changes in total. All 6 key changes should be deletions.
213        self.assertEqual(len(result[result["Name"] == "cloudtasks"]), 6)
214        self.assertEqual(
215            len(result[(result["Name"] == "cloudtasks") & result["Added"]]), 0
216        )
217        self.assertEqual(
218            len(result[(result["Name"] == "cloudtasks") & result["Deleted"]]), 6
219        )
220        self.assertTrue(result[(result["Name"] == "cloudtasks")].IsStable.all())
221        self.assertTrue(
222            result[(result["Name"] == "cloudtasks")].IsFeatureAggregate.all()
223        )
224        self.assertEqual(
225            result[(result["Name"] == "cloudtasks")].Summary.iloc[0],
226            "feat(cloudtasks): update the api",
227        )
228
229        # drive was updated
230        # 4 key changes in total. All 4 key changes should be additions
231        self.assertEqual(len(result[result["Name"] == "drive"]), 4)
232        self.assertEqual(len(result[(result["Name"] == "drive") & result["Added"]]), 4)
233        self.assertEqual(
234            len(result[(result["Name"] == "drive") & result["Deleted"]]), 0
235        )
236        self.assertTrue(result[(result["Name"] == "drive")].IsStable.all())
237        self.assertTrue(result[(result["Name"] == "drive")].IsFeatureAggregate.all())
238        self.assertEqual(
239            result[(result["Name"] == "drive")].Summary.iloc[0],
240            "feat(drive): update the api",
241        )
242
243
244if __name__ == "__main__":
245    unittest.main()
246