Repository: locustio/locust

Issue:
Report charts plot data points after the test has ended
![imagen](https://user-images.githubusercontent.com/939664/105061092-665f5b00-5a79-11eb-862d-7f4e8770e11e.png)
![imagen](https://user-images.githubusercontent.com/939664/105061163-7ecf7580-5a79-11eb-9c6b-01e8aa423fc9.png)

### Describe the bug
After stopping a test on the UI, when I click on "Download report" the plots show a date range between _test-start_ and _now_, instead of _test-start_ and _test-end_. 

### Expected behavior
All the plots should only contain data between _test-start_ and _test-end_ dates I guess.

### Actual behavior
All three plots in the report continue plotting either 0 (Response Times and Number of Users) or RPS (Total Requests per Second) after the test has ended up until the moment you open or refresh the Download Report page.

### Steps to reproduce

- Start the UI with any test file (the Quick Start one for example: https://docs.locust.io/en/stable/quickstart.html): `locust -f example.py`
- Parameters don't matter as far as I know, just run the test
- Let it run for a few seconds
- Stop it
- Wait for 10 or 20 seconds so it is easier to see the bug
- Click on **Download Data -> Download Report**
- Notice the flatlines on the plots and the date ranges, extending way after the test was stopped. If you refresh this page (the report) the plots just keep growing.
- Interestingly enough, the start and end dates at the top of the report are correct

### Environment

- OS: Ubuntu 20.04
- Browser: Firefox 84.0.2 and Chromium 87.0.4280.141
- Python version: 3.8.5
- Locust version: 1.4.1
- Locust command line that you ran: `locust -f example.py`
- Locust file contents (anonymized if necessary): 

```
import time
from locust import HttpUser, task

class QuickstartUser(HttpUser):
    @task
    def hello_world(self):
        self.client.get("/hello")
        self.client.get("/world")

    @task(3)
    def view_item(self):
        for item_id in range(10):
            self.client.get(f"/item?id={item_id}", name="/item")
            time.sleep(1)

    def on_start(self):
        self.client.post("/login", json={"username":"foo", "password":"bar"})
```

BTW I think this is a great tool, I have just discovered it and I am loving it! :heart: 


Discussion:
I'm agree with you. 👍 
Let me review the code, maybe I could make a PR to solve this. Also I don't like that charts data disappear after a page refresh but it properly show up when you generate the test report

Resolving patch:
diff --git a/locust/stats.py b/locust/stats.py
--- a/locust/stats.py
+++ b/locust/stats.py
@@ -784,15 +784,16 @@ def stats_history(runner):
         stats = runner.stats
         if not stats.total.use_response_times_cache:
             break
-        r = {
-            "time": datetime.datetime.now().strftime("%H:%M:%S"),
-            "current_rps": stats.total.current_rps or 0,
-            "current_fail_per_sec": stats.total.current_fail_per_sec or 0,
-            "response_time_percentile_95": stats.total.get_current_response_time_percentile(0.95) or 0,
-            "response_time_percentile_50": stats.total.get_current_response_time_percentile(0.5) or 0,
-            "user_count": runner.user_count or 0,
-        }
-        stats.history.append(r)
+        if runner.state != 'stopped':
+            r = {
+                "time": datetime.datetime.now().strftime("%H:%M:%S"),
+                "current_rps": stats.total.current_rps or 0,
+                "current_fail_per_sec": stats.total.current_fail_per_sec or 0,
+                "response_time_percentile_95": stats.total.get_current_response_time_percentile(0.95) or 0,
+                "response_time_percentile_50": stats.total.get_current_response_time_percentile(0.5) or 0,
+                "user_count": runner.user_count or 0,
+            }
+            stats.history.append(r)
         gevent.sleep(HISTORY_STATS_INTERVAL_SEC)
 
 
diff --git a/locust/web.py b/locust/web.py
--- a/locust/web.py
+++ b/locust/web.py
@@ -390,12 +390,15 @@ def update_template_args(self):
         else:
             worker_count = 0
 
+        stats = self.environment.runner.stats
+
         self.template_args = {
             "state": self.environment.runner.state,
             "is_distributed": is_distributed,
             "user_count": self.environment.runner.user_count,
             "version": version,
             "host": host,
+            "history": stats.history,
             "override_host_warning": override_host_warning,
             "num_users": options and options.num_users,
             "spawn_rate": options and options.spawn_rate,


Test patch: