Repository: juju/python-libjuju

Issue:
[Bug]: model.deploy does not behave like juju command
### Description

## Environment
juju 2.9.42
juju==3.0.4

## Scenario

1. Channel latest/table and series focal (20.04) are available at [PostgreSQL-K8S Charmhub](https://charmhub.io/postgresql-k8s)

2. The command `juju deploy postgresql-k8s --channel=latest/stable --series=focal` deploys the charm postgresql-k8s as expected:
juju deploy output:
```
Located charm "postgresql-k8s" in charm-hub, revision 20
Deploying "postgresql-k8s" from charm-hub charm "postgresql-k8s", revision 20 in channel latest/stable on focal
```

juju status output:
```
juju status
Model      Controller   Cloud/Region        Version  SLA          Timestamp
indico-18  github-pr-2  microk8s/localhost  2.9.42   unsupported  14:37:37-03:00

App             Version  Status   Scale  Charm           Channel        Rev  Address  Exposed  Message
postgresql-k8s           waiting      1  postgresql-k8s  latest/stable   20           no       agent initializing

Unit               Workload     Agent      Address  Ports  Message
postgresql-k8s/3*  maintenance  executing                  (install) installing charm software
```
3. But deploying it while running an integration test using `ops_test.model.deploy("postgresql-k8s",series="focal", channel="latest/stable")` throws an error: 
```
juju.errors.JujuError: Series focal not supported for ch:postgresql-k8s. Only ['jammy']
```

## Expected
Deploy the charm postgresql-k8s accordingly to parameters channel latest/stable and series focal.

## Reference
https://discourse.charmhub.io/t/juju-operators-for-postgresql-and-mysql-are-now-stable/10223/4



### Urgency

Annoying bug in our test suite

### Python-libjuju version

3.0.4

### Juju version

2.9.42

### Reproduce / Test

```python
ops_test.model.deploy("postgresql-k8s",series="focal", channel="latest/stable")
```


Discussion:

Patch:
diff --git a/juju/origin.py b/juju/origin.py
index 083e162..0dca746 100644
--- a/juju/origin.py
+++ b/juju/origin.py
@@ -97,7 +97,9 @@ class Channel:
         return Channel(track, risk)
 
     def normalize(self):
-        track = self.track if self.track != "latest" else ""
+        # TODO (cderici): this is essentially a noop, needs to be revised in both
+        #  2.9 and 3.x
+        track = self.track if self.track != "" else ""
         risk = self.risk if self.risk != "" else ""
         return Channel(track, risk)
 


Test patch:
diff --git a/tests/unit/test_bundle.py b/tests/unit/test_bundle.py
index 64c569b..d2f9370 100644
--- a/tests/unit/test_bundle.py
+++ b/tests/unit/test_bundle.py
@@ -355,7 +355,7 @@ class TestAddApplicationChangeRun:
 
         context = Mock()
         context.resolve.return_value = "ch:charm1"
-        context.origins = {"ch:charm1": {"stable": Mock()}}
+        context.origins = {"ch:charm1": {"latest/stable": Mock()}}
         context.trusted = False
         context.model = model
 
diff --git a/tests/unit/test_origin.py b/tests/unit/test_origin.py
index b2b3fa5..979cdc6 100644
--- a/tests/unit/test_origin.py
+++ b/tests/unit/test_origin.py
@@ -30,7 +30,7 @@ class TestChannel(unittest.TestCase):
 
     def test_parse_then_normalize(self):
         ch = Channel.parse("latest/stable").normalize()
-        self.assertEqual(ch, Channel(None, "stable"))
+        self.assertEqual(ch, Channel("latest", "stable"))
 
     def test_str_risk_only(self):
         ch = Channel.parse("stable")
@@ -50,7 +50,7 @@ class TestChannel(unittest.TestCase):
 
     def test_str_then_normalize(self):
         ch = Channel.parse("latest/stable").normalize()
-        self.assertEqual(str(ch), "stable")
+        self.assertEqual(str(ch), "latest/stable")
 
 
 class TestPlatform(unittest.TestCase):